[chore] Update gin to v1.9.0 (#1553)

This commit is contained in:
Daenney 2023-02-25 13:12:40 +01:00 committed by GitHub
commit ecdc8379fa
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
347 changed files with 166814 additions and 3671 deletions

View file

View file

@ -0,0 +1,115 @@
/*
* Copyright 2021 ByteDance Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package caching
import (
`strings`
`unsafe`
`github.com/bytedance/sonic/internal/rt`
)
type FieldMap struct {
N uint64
b unsafe.Pointer
m map[string]int
}
type FieldEntry struct {
ID int
Name string
Hash uint64
}
const (
FieldMap_N = int64(unsafe.Offsetof(FieldMap{}.N))
FieldMap_b = int64(unsafe.Offsetof(FieldMap{}.b))
FieldEntrySize = int64(unsafe.Sizeof(FieldEntry{}))
)
func newBucket(n int) unsafe.Pointer {
v := make([]FieldEntry, n)
return (*rt.GoSlice)(unsafe.Pointer(&v)).Ptr
}
func CreateFieldMap(n int) *FieldMap {
return &FieldMap {
N: uint64(n * 2),
b: newBucket(n * 2), // LoadFactor = 0.5
m: make(map[string]int, n * 2),
}
}
func (self *FieldMap) At(p uint64) *FieldEntry {
off := uintptr(p) * uintptr(FieldEntrySize)
return (*FieldEntry)(unsafe.Pointer(uintptr(self.b) + off))
}
// Get searches FieldMap by name. JIT generated assembly does NOT call this
// function, rather it implements its own version directly in assembly. So
// we must ensure this function stays in sync with the JIT generated one.
func (self *FieldMap) Get(name string) int {
h := StrHash(name)
p := h % self.N
s := self.At(p)
/* find the element;
* the hash map is never full, so the loop will always terminate */
for s.Hash != 0 {
if s.Hash == h && s.Name == name {
return s.ID
} else {
p = (p + 1) % self.N
s = self.At(p)
}
}
/* not found */
return -1
}
func (self *FieldMap) Set(name string, i int) {
h := StrHash(name)
p := h % self.N
s := self.At(p)
/* searching for an empty slot;
* the hash map is never full, so the loop will always terminate */
for s.Hash != 0 {
p = (p + 1) % self.N
s = self.At(p)
}
/* set the value */
s.ID = i
s.Hash = h
s.Name = name
/* add the case-insensitive version, prefer the one with smaller field ID */
key := strings.ToLower(name)
if v, ok := self.m[key]; !ok || i < v {
self.m[key] = i
}
}
func (self *FieldMap) GetCaseInsensitive(name string) int {
if i, ok := self.m[strings.ToLower(name)]; ok {
return i
} else {
return -1
}
}

View file

@ -0,0 +1,40 @@
/*
* Copyright 2021 ByteDance Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package caching
import (
`unsafe`
`github.com/bytedance/sonic/internal/rt`
)
var (
V_strhash = rt.UnpackEface(strhash)
S_strhash = *(*uintptr)(V_strhash.Value)
)
//go:noescape
//go:linkname strhash runtime.strhash
func strhash(_ unsafe.Pointer, _ uintptr) uintptr
func StrHash(s string) uint64 {
if v := strhash(unsafe.Pointer(&s), 0); v == 0 {
return 1
} else {
return uint64(v)
}
}

View file

@ -0,0 +1,173 @@
/*
* Copyright 2021 ByteDance Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package caching
import (
`sync`
`sync/atomic`
`unsafe`
`github.com/bytedance/sonic/internal/rt`
)
/** Program Map **/
const (
_LoadFactor = 0.5
_InitCapacity = 4096 // must be a power of 2
)
type _ProgramMap struct {
n uint64
m uint32
b []_ProgramEntry
}
type _ProgramEntry struct {
vt *rt.GoType
fn interface{}
}
func newProgramMap() *_ProgramMap {
return &_ProgramMap {
n: 0,
m: _InitCapacity - 1,
b: make([]_ProgramEntry, _InitCapacity),
}
}
func (self *_ProgramMap) copy() *_ProgramMap {
fork := &_ProgramMap{
n: self.n,
m: self.m,
b: make([]_ProgramEntry, len(self.b)),
}
for i, f := range self.b {
fork.b[i] = f
}
return fork
}
func (self *_ProgramMap) get(vt *rt.GoType) interface{} {
i := self.m + 1
p := vt.Hash & self.m
/* linear probing */
for ; i > 0; i-- {
if b := self.b[p]; b.vt == vt {
return b.fn
} else if b.vt == nil {
break
} else {
p = (p + 1) & self.m
}
}
/* not found */
return nil
}
func (self *_ProgramMap) add(vt *rt.GoType, fn interface{}) *_ProgramMap {
p := self.copy()
f := float64(atomic.LoadUint64(&p.n) + 1) / float64(p.m + 1)
/* check for load factor */
if f > _LoadFactor {
p = p.rehash()
}
/* insert the value */
p.insert(vt, fn)
return p
}
func (self *_ProgramMap) rehash() *_ProgramMap {
c := (self.m + 1) << 1
r := &_ProgramMap{m: c - 1, b: make([]_ProgramEntry, int(c))}
/* rehash every entry */
for i := uint32(0); i <= self.m; i++ {
if b := self.b[i]; b.vt != nil {
r.insert(b.vt, b.fn)
}
}
/* rebuild successful */
return r
}
func (self *_ProgramMap) insert(vt *rt.GoType, fn interface{}) {
h := vt.Hash
p := h & self.m
/* linear probing */
for i := uint32(0); i <= self.m; i++ {
if b := &self.b[p]; b.vt != nil {
p += 1
p &= self.m
} else {
b.vt = vt
b.fn = fn
atomic.AddUint64(&self.n, 1)
return
}
}
/* should never happens */
panic("no available slots")
}
/** RCU Program Cache **/
type ProgramCache struct {
m sync.Mutex
p unsafe.Pointer
}
func CreateProgramCache() *ProgramCache {
return &ProgramCache {
m: sync.Mutex{},
p: unsafe.Pointer(newProgramMap()),
}
}
func (self *ProgramCache) Get(vt *rt.GoType) interface{} {
return (*_ProgramMap)(atomic.LoadPointer(&self.p)).get(vt)
}
func (self *ProgramCache) Compute(vt *rt.GoType, compute func(*rt.GoType, ... interface{}) (interface{}, error), ex ...interface{}) (interface{}, error) {
var err error
var val interface{}
/* use defer to prevent inlining of this function */
self.m.Lock()
defer self.m.Unlock()
/* double check with write lock held */
if val = self.Get(vt); val != nil {
return val, nil
}
/* compute the value */
if val, err = compute(vt, ex...); err != nil {
return nil, err
}
/* update the RCU cache */
atomic.StorePointer(&self.p, unsafe.Pointer((*_ProgramMap)(atomic.LoadPointer(&self.p)).add(vt, val)))
return val, nil
}

View file

@ -0,0 +1,40 @@
/*
* Copyright 2021 ByteDance Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cpu
import (
`fmt`
`os`
`github.com/klauspost/cpuid/v2`
)
var (
HasAVX = cpuid.CPU.Has(cpuid.AVX)
HasAVX2 = cpuid.CPU.Has(cpuid.AVX2)
HasSSE = cpuid.CPU.Has(cpuid.SSE)
)
func init() {
switch v := os.Getenv("SONIC_MODE"); v {
case "" : break
case "auto" : break
case "noavx" : HasAVX = false; fallthrough
case "noavx2" : HasAVX2 = false
default : panic(fmt.Sprintf("invalid mode: '%s', should be one of 'auto', 'noavx', 'noavx2'", v))
}
}

View file

@ -0,0 +1,67 @@
/*
* Copyright 2021 ByteDance Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package jit
import (
`github.com/twitchyliquid64/golang-asm/asm/arch`
`github.com/twitchyliquid64/golang-asm/obj`
)
var (
_AC = arch.Set("amd64")
)
func As(op string) obj.As {
if ret, ok := _AC.Instructions[op]; ok {
return ret
} else {
panic("invalid instruction: " + op)
}
}
func Imm(imm int64) obj.Addr {
return obj.Addr {
Type : obj.TYPE_CONST,
Offset : imm,
}
}
func Reg(reg string) obj.Addr {
if ret, ok := _AC.Register[reg]; ok {
return obj.Addr{Reg: ret, Type: obj.TYPE_REG}
} else {
panic("invalid register name: " + reg)
}
}
func Ptr(reg obj.Addr, offs int64) obj.Addr {
return obj.Addr {
Reg : reg.Reg,
Type : obj.TYPE_MEM,
Offset : offs,
}
}
func Sib(reg obj.Addr, idx obj.Addr, scale int16, offs int64) obj.Addr {
return obj.Addr {
Reg : reg.Reg,
Index : idx.Reg,
Scale : scale,
Type : obj.TYPE_MEM,
Offset : offs,
}
}

0
vendor/github.com/bytedance/sonic/internal/jit/asm.s generated vendored Normal file
View file

View file

@ -0,0 +1,269 @@
/*
* Copyright 2021 ByteDance Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package jit
import (
`encoding/binary`
`strconv`
`strings`
`sync`
`github.com/bytedance/sonic/loader`
`github.com/bytedance/sonic/internal/rt`
`github.com/twitchyliquid64/golang-asm/obj`
`github.com/twitchyliquid64/golang-asm/obj/x86`
)
const (
_LB_jump_pc = "_jump_pc_"
)
type BaseAssembler struct {
i int
f func()
c []byte
o sync.Once
pb *Backend
xrefs map[string][]*obj.Prog
labels map[string]*obj.Prog
pendings map[string][]*obj.Prog
}
/** Instruction Encoders **/
var _NOPS = [][16]byte {
{0x90}, // NOP
{0x66, 0x90}, // 66 NOP
{0x0f, 0x1f, 0x00}, // NOP DWORD ptr [EAX]
{0x0f, 0x1f, 0x40, 0x00}, // NOP DWORD ptr [EAX + 00H]
{0x0f, 0x1f, 0x44, 0x00, 0x00}, // NOP DWORD ptr [EAX + EAX*1 + 00H]
{0x66, 0x0f, 0x1f, 0x44, 0x00, 0x00}, // 66 NOP DWORD ptr [EAX + EAX*1 + 00H]
{0x0f, 0x1f, 0x80, 0x00, 0x00, 0x00, 0x00}, // NOP DWORD ptr [EAX + 00000000H]
{0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00}, // NOP DWORD ptr [EAX + EAX*1 + 00000000H]
{0x66, 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00}, // 66 NOP DWORD ptr [EAX + EAX*1 + 00000000H]
}
func (self *BaseAssembler) NOP() *obj.Prog {
p := self.pb.New()
p.As = obj.ANOP
self.pb.Append(p)
return p
}
func (self *BaseAssembler) NOPn(n int) {
for i := len(_NOPS); i > 0 && n > 0; i-- {
for ; n >= i; n -= i {
self.Byte(_NOPS[i - 1][:i]...)
}
}
}
func (self *BaseAssembler) Byte(v ...byte) {
for ; len(v) >= 8; v = v[8:] { self.From("QUAD", Imm(rt.Get64(v))) }
for ; len(v) >= 4; v = v[4:] { self.From("LONG", Imm(int64(rt.Get32(v)))) }
for ; len(v) >= 2; v = v[2:] { self.From("WORD", Imm(int64(rt.Get16(v)))) }
for ; len(v) >= 1; v = v[1:] { self.From("BYTE", Imm(int64(v[0]))) }
}
func (self *BaseAssembler) Mark(pc int) {
self.i++
self.Link(_LB_jump_pc + strconv.Itoa(pc))
}
func (self *BaseAssembler) Link(to string) {
var p *obj.Prog
var v []*obj.Prog
/* placeholder substitution */
if strings.Contains(to, "{n}") {
to = strings.ReplaceAll(to, "{n}", strconv.Itoa(self.i))
}
/* check for duplications */
if _, ok := self.labels[to]; ok {
panic("label " + to + " has already been linked")
}
/* get the pending links */
p = self.NOP()
v = self.pendings[to]
/* patch all the pending jumps */
for _, q := range v {
q.To.Val = p
}
/* mark the label as resolved */
self.labels[to] = p
delete(self.pendings, to)
}
func (self *BaseAssembler) Xref(pc int, d int64) {
self.Sref(_LB_jump_pc + strconv.Itoa(pc), d)
}
func (self *BaseAssembler) Sref(to string, d int64) {
p := self.pb.New()
p.As = x86.ALONG
p.From = Imm(-d)
/* placeholder substitution */
if strings.Contains(to, "{n}") {
to = strings.ReplaceAll(to, "{n}", strconv.Itoa(self.i))
}
/* record the patch point */
self.pb.Append(p)
self.xrefs[to] = append(self.xrefs[to], p)
}
func (self *BaseAssembler) Xjmp(op string, to int) {
self.Sjmp(op, _LB_jump_pc + strconv.Itoa(to))
}
func (self *BaseAssembler) Sjmp(op string, to string) {
p := self.pb.New()
p.As = As(op)
/* placeholder substitution */
if strings.Contains(to, "{n}") {
to = strings.ReplaceAll(to, "{n}", strconv.Itoa(self.i))
}
/* check for backward jumps */
if v, ok := self.labels[to]; ok {
p.To.Val = v
} else {
self.pendings[to] = append(self.pendings[to], p)
}
/* mark as a branch, and add to instruction buffer */
p.To.Type = obj.TYPE_BRANCH
self.pb.Append(p)
}
func (self *BaseAssembler) Rjmp(op string, to obj.Addr) {
p := self.pb.New()
p.To = to
p.As = As(op)
self.pb.Append(p)
}
func (self *BaseAssembler) From(op string, val obj.Addr) {
p := self.pb.New()
p.As = As(op)
p.From = val
self.pb.Append(p)
}
func (self *BaseAssembler) Emit(op string, args ...obj.Addr) {
p := self.pb.New()
p.As = As(op)
self.assignOperands(p, args)
self.pb.Append(p)
}
func (self *BaseAssembler) assignOperands(p *obj.Prog, args []obj.Addr) {
switch len(args) {
case 0 :
case 1 : p.To = args[0]
case 2 : p.To, p.From = args[1], args[0]
case 3 : p.To, p.From, p.RestArgs = args[2], args[0], args[1:2]
case 4 : p.To, p.From, p.RestArgs = args[2], args[3], args[:2]
default : panic("invalid operands")
}
}
/** Assembler Helpers **/
func (self *BaseAssembler) Size() int {
self.build()
return len(self.c)
}
func (self *BaseAssembler) Init(f func()) {
self.i = 0
self.f = f
self.c = nil
self.o = sync.Once{}
}
var jitLoader = loader.Loader{
Name: "sonic.jit.",
File: "github.com/bytedance/sonic/jit.go",
Options: loader.Options{
NoPreempt: true,
},
}
func (self *BaseAssembler) Load(name string, frameSize int, argSize int, argStackmap []bool, localStackmap []bool) loader.Function {
self.build()
return jitLoader.LoadOne(self.c, name, frameSize, argSize, argStackmap, localStackmap)
}
/** Assembler Stages **/
func (self *BaseAssembler) init() {
self.pb = newBackend("amd64")
self.xrefs = map[string][]*obj.Prog{}
self.labels = map[string]*obj.Prog{}
self.pendings = map[string][]*obj.Prog{}
}
func (self *BaseAssembler) build() {
self.o.Do(func() {
self.init()
self.f()
self.validate()
self.assemble()
self.resolve()
self.release()
})
}
func (self *BaseAssembler) release() {
self.pb.Release()
self.pb = nil
self.xrefs = nil
self.labels = nil
self.pendings = nil
}
func (self *BaseAssembler) resolve() {
for s, v := range self.xrefs {
for _, prog := range v {
if prog.As != x86.ALONG {
panic("invalid RIP relative reference")
} else if p, ok := self.labels[s]; !ok {
panic("links are not fully resolved: " + s)
} else {
off := prog.From.Offset + p.Pc - prog.Pc
binary.LittleEndian.PutUint32(self.c[prog.Pc:], uint32(off))
}
}
}
}
func (self *BaseAssembler) validate() {
for key := range self.pendings {
panic("links are not fully resolved: " + key)
}
}
func (self *BaseAssembler) assemble() {
self.c = self.pb.Assemble()
}

View file

@ -0,0 +1,120 @@
/*
* Copyright 2021 ByteDance Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package jit
import (
`fmt`
`sync`
_ `unsafe`
`github.com/twitchyliquid64/golang-asm/asm/arch`
`github.com/twitchyliquid64/golang-asm/obj`
`github.com/twitchyliquid64/golang-asm/objabi`
)
type Backend struct {
Ctxt *obj.Link
Arch *arch.Arch
Head *obj.Prog
Tail *obj.Prog
Prog []*obj.Prog
}
var (
_progPool sync.Pool
)
//go:nosplit
//go:linkname throw runtime.throw
func throw(_ string)
func newProg() *obj.Prog {
if val := _progPool.Get(); val == nil {
return new(obj.Prog)
} else {
return remProg(val.(*obj.Prog))
}
}
func remProg(p *obj.Prog) *obj.Prog {
*p = obj.Prog{}
return p
}
func newBackend(name string) (ret *Backend) {
ret = new(Backend)
ret.Arch = arch.Set(name)
ret.Ctxt = newLinkContext(ret.Arch.LinkArch)
ret.Arch.Init(ret.Ctxt)
return
}
func newLinkContext(arch *obj.LinkArch) (ret *obj.Link) {
ret = obj.Linknew(arch)
ret.Headtype = objabi.Hlinux
ret.DiagFunc = diagLinkContext
return
}
func diagLinkContext(str string, args ...interface{}) {
throw(fmt.Sprintf(str, args...))
}
func (self *Backend) New() (ret *obj.Prog) {
ret = newProg()
ret.Ctxt = self.Ctxt
self.Prog = append(self.Prog, ret)
return
}
func (self *Backend) Append(p *obj.Prog) {
if self.Head == nil {
self.Head = p
self.Tail = p
} else {
self.Tail.Link = p
self.Tail = p
}
}
func (self *Backend) Release() {
self.Arch = nil
self.Ctxt = nil
/* return all the progs into pool */
for _, p := range self.Prog {
_progPool.Put(p)
}
/* clear all the references */
self.Head = nil
self.Tail = nil
self.Prog = nil
}
func (self *Backend) Assemble() []byte {
var sym obj.LSym
var fnv obj.FuncInfo
/* construct the function */
sym.Func = &fnv
fnv.Text = self.Head
/* call the assembler */
self.Arch.Assemble(self.Ctxt, &sym, self.New)
return sym.P
}

View file

@ -0,0 +1,54 @@
/*
* Copyright 2021 ByteDance Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package jit
import (
`reflect`
`unsafe`
`github.com/bytedance/sonic/internal/rt`
`github.com/twitchyliquid64/golang-asm/obj`
)
//go:noescape
//go:linkname getitab runtime.getitab
//goland:noinspection ALL
func getitab(inter *rt.GoType, typ *rt.GoType, canfail bool) *rt.GoItab
func Func(f interface{}) obj.Addr {
if p := rt.UnpackEface(f); p.Type.Kind() != reflect.Func {
panic("f is not a function")
} else {
return Imm(*(*int64)(p.Value))
}
}
func Type(t reflect.Type) obj.Addr {
return Gtype(rt.UnpackType(t))
}
func Itab(i *rt.GoType, t reflect.Type) obj.Addr {
return Imm(int64(uintptr(unsafe.Pointer(getitab(i, rt.UnpackType(t), false)))))
}
func Gitab(i *rt.GoItab) obj.Addr {
return Imm(int64(uintptr(unsafe.Pointer(i))))
}
func Gtype(t *rt.GoType) obj.Addr {
return Imm(int64(uintptr(unsafe.Pointer(t))))
}

View file

View file

@ -0,0 +1,124 @@
/*
* Copyright 2021 ByteDance Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package loader
import (
`reflect`
`sync`
`unsafe`
`github.com/bytedance/sonic/internal/rt`
)
//go:linkname lastmoduledatap runtime.lastmoduledatap
//goland:noinspection GoUnusedGlobalVariable
var lastmoduledatap *_ModuleData
//go:linkname moduledataverify1 runtime.moduledataverify1
func moduledataverify1(_ *_ModuleData)
// PCDATA and FUNCDATA table indexes.
//
// See funcdata.h and $GROOT/src/cmd/internal/objabi/funcdata.go.
const (
_FUNCDATA_ArgsPointerMaps = 0
_FUNCDATA_LocalsPointerMaps = 1
)
type funcInfo struct {
*_Func
datap *_ModuleData
}
//go:linkname findfunc runtime.findfunc
func findfunc(pc uintptr) funcInfo
//go:linkname funcdata runtime.funcdata
func funcdata(f funcInfo, i uint8) unsafe.Pointer
var (
modLock sync.Mutex
modList []*_ModuleData
)
var emptyByte byte
func encodeVariant(v int) []byte {
var u int
var r []byte
/* split every 7 bits */
for v > 127 {
u = v & 0x7f
v = v >> 7
r = append(r, byte(u) | 0x80)
}
/* check for last one */
if v == 0 {
return r
}
/* add the last one */
r = append(r, byte(v))
return r
}
func registerModule(mod *_ModuleData) {
modLock.Lock()
modList = append(modList, mod)
lastmoduledatap.next = mod
lastmoduledatap = mod
modLock.Unlock()
}
func stackMap(f interface{}) (args uintptr, locals uintptr) {
fv := reflect.ValueOf(f)
if fv.Kind() != reflect.Func {
panic("f must be reflect.Func kind!")
}
fi := findfunc(fv.Pointer())
return uintptr(funcdata(fi, uint8(_FUNCDATA_ArgsPointerMaps))), uintptr(funcdata(fi, uint8(_FUNCDATA_LocalsPointerMaps)))
}
var moduleCache = struct{
m map[*_ModuleData][]byte
l sync.Mutex
}{
m : make(map[*_ModuleData][]byte),
}
func cacheStackmap(argPtrs []bool, localPtrs []bool, mod *_ModuleData) (argptrs uintptr, localptrs uintptr) {
as := rt.StackMapBuilder{}
for _, b := range argPtrs {
as.AddField(b)
}
ab, _ := as.Build().MarshalBinary()
ls := rt.StackMapBuilder{}
for _, b := range localPtrs {
ls.AddField(b)
}
lb, _ := ls.Build().MarshalBinary()
cache := make([]byte, len(ab) + len(lb))
copy(cache, ab)
copy(cache[len(ab):], lb)
moduleCache.l.Lock()
moduleCache.m[mod] = cache
moduleCache.l.Unlock()
return uintptr(rt.IndexByte(cache, 0)), uintptr(rt.IndexByte(cache, len(ab)))
}

View file

@ -0,0 +1,169 @@
// +build go1.15,!go1.16
/*
* Copyright 2021 ByteDance Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package loader
import (
`unsafe`
`github.com/bytedance/sonic/internal/rt`
)
type _Func struct {
entry uintptr // start pc
nameoff int32 // function name
args int32 // in/out args size
deferreturn uint32 // offset of start of a deferreturn call instruction from entry, if any.
pcsp int32
pcfile int32
pcln int32
npcdata int32
funcID uint8 // set for certain special runtime functions
_ [2]int8 // unused
nfuncdata uint8 // must be last
argptrs uintptr
localptrs uintptr
}
type _FuncTab struct {
entry uintptr
funcoff uintptr
}
type _BitVector struct {
n int32 // # of bits
bytedata *uint8
}
type _PtabEntry struct {
name int32
typ int32
}
type _TextSection struct {
vaddr uintptr // prelinked section vaddr
length uintptr // section length
baseaddr uintptr // relocated section address
}
type _ModuleData struct {
pclntable []byte
ftab []_FuncTab
filetab []uint32
findfunctab *_FindFuncBucket
minpc, maxpc uintptr
text, etext uintptr
noptrdata, enoptrdata uintptr
data, edata uintptr
bss, ebss uintptr
noptrbss, enoptrbss uintptr
end, gcdata, gcbss uintptr
types, etypes uintptr
textsectmap []_TextSection
typelinks []int32 // offsets from types
itablinks []*rt.GoItab
ptab []_PtabEntry
pluginpath string
pkghashes []byte
modulename string
modulehashes []byte
hasmain uint8 // 1 if module contains the main function, 0 otherwise
gcdatamask, gcbssmask _BitVector
typemap map[int32]*rt.GoType // offset to *_rtype in previous module
bad bool // module failed to load and should be ignored
next *_ModuleData
}
type _FindFuncBucket struct {
idx uint32
subbuckets [16]byte
}
var findFuncTab = &_FindFuncBucket {
idx: 1,
}
func registerFunction(name string, pc uintptr, textSize uintptr, fp int, args int, size uintptr, argPtrs []bool, localPtrs []bool) {
mod := new(_ModuleData)
minpc := pc
maxpc := pc + size
/* build the PC & line table */
pclnt := []byte {
0xfb, 0xff, 0xff, 0xff, // magic : 0xfffffffb
0, // pad1 : 0
0, // pad2 : 0
1, // minLC : 1
4 << (^uintptr(0) >> 63), // ptrSize : 4 << (^uintptr(0) >> 63)
}
// cache arg and local stackmap
argptrs, localptrs := cacheStackmap(argPtrs, localPtrs, mod)
/* add the function name */
noff := len(pclnt)
pclnt = append(append(pclnt, name...), 0)
/* add PCDATA */
pcsp := len(pclnt)
pclnt = append(pclnt, encodeVariant((fp + 1) << 1)...)
pclnt = append(pclnt, encodeVariant(int(size))...)
/* function entry */
fnv := _Func {
entry : pc,
nameoff : int32(noff),
args : int32(args),
pcsp : int32(pcsp),
nfuncdata : 2,
argptrs : uintptr(argptrs),
localptrs : uintptr(localptrs),
}
/* align the func to 8 bytes */
if p := len(pclnt) % 8; p != 0 {
pclnt = append(pclnt, make([]byte, 8 - p)...)
}
/* add the function descriptor */
foff := len(pclnt)
pclnt = append(pclnt, (*(*[unsafe.Sizeof(_Func{})]byte)(unsafe.Pointer(&fnv)))[:]...)
/* function table */
tab := []_FuncTab {
{entry: pc, funcoff: uintptr(foff)},
{entry: pc, funcoff: uintptr(foff)},
{entry: maxpc},
}
/* module data */
*mod = _ModuleData {
pclntable : pclnt,
ftab : tab,
findfunctab : findFuncTab,
minpc : minpc,
maxpc : maxpc,
modulename : name,
gcdata: uintptr(unsafe.Pointer(&emptyByte)),
gcbss: uintptr(unsafe.Pointer(&emptyByte)),
}
/* verify and register the new module */
moduledataverify1(mod)
registerModule(mod)
}

View file

@ -0,0 +1,175 @@
//go:build go1.16 && !go1.18
// +build go1.16,!go1.18
/*
* Copyright 2021 ByteDance Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package loader
import (
`unsafe`
)
type _Func struct {
entry uintptr // start pc
nameoff int32 // function name
args int32 // in/out args size
deferreturn uint32 // offset of start of a deferreturn call instruction from entry, if any.
pcsp uint32
pcfile uint32
pcln uint32
npcdata uint32
cuOffset uint32 // runtime.cutab offset of this function's CU
funcID uint8 // set for certain special runtime functions
_ [2]byte // pad
nfuncdata uint8 // must be last
argptrs uintptr
localptrs uintptr
}
type _FuncTab struct {
entry uintptr
funcoff uintptr
}
type _PCHeader struct {
magic uint32 // 0xFFFFFFFA
pad1, pad2 uint8 // 0,0
minLC uint8 // min instruction size
ptrSize uint8 // size of a ptr in bytes
nfunc int // number of functions in the module
nfiles uint // number of entries in the file tab.
funcnameOffset uintptr // offset to the funcnametab variable from _PCHeader
cuOffset uintptr // offset to the cutab variable from _PCHeader
filetabOffset uintptr // offset to the filetab variable from _PCHeader
pctabOffset uintptr // offset to the pctab varible from _PCHeader
pclnOffset uintptr // offset to the pclntab variable from _PCHeader
}
type _BitVector struct {
n int32 // # of bits
bytedata *uint8
}
type _PtabEntry struct {
name int32
typ int32
}
type _TextSection struct {
vaddr uintptr // prelinked section vaddr
length uintptr // section length
baseaddr uintptr // relocated section address
}
type _ModuleData struct {
pcHeader *_PCHeader
funcnametab []byte
cutab []uint32
filetab []byte
pctab []byte
pclntable []_Func
ftab []_FuncTab
findfunctab *_FindFuncBucket
minpc, maxpc uintptr
text, etext uintptr
noptrdata, enoptrdata uintptr
data, edata uintptr
bss, ebss uintptr
noptrbss, enoptrbss uintptr
end, gcdata, gcbss uintptr
types, etypes uintptr
textsectmap []_TextSection
typelinks []int32
itablinks []unsafe.Pointer
ptab []_PtabEntry
pluginpath string
pkghashes []struct{}
modulename string
modulehashes []struct{}
hasmain uint8
gcdatamask, gcbssmask _BitVector
typemap map[int32]unsafe.Pointer
bad bool
next *_ModuleData
}
type _FindFuncBucket struct {
idx uint32
subbuckets [16]byte
}
var modHeader = &_PCHeader {
magic : 0xfffffffa,
minLC : 1,
nfunc : 1,
ptrSize : 4 << (^uintptr(0) >> 63),
}
var findFuncTab = &_FindFuncBucket {
idx: 1,
}
func makePCtab(fp int) []byte {
return append([]byte{0}, encodeVariant((fp + 1) << 1)...)
}
func registerFunction(name string, pc uintptr, textSize uintptr, fp int, args int, size uintptr, argPtrs []bool, localPtrs []bool) {
mod := new(_ModuleData)
minpc := pc
maxpc := pc + size
// cache arg and local stackmap
argptrs, localptrs := cacheStackmap(argPtrs, localPtrs, mod)
/* function entry */
lnt := []_Func {{
entry : pc,
nameoff : 1,
args : int32(args),
pcsp : 1,
nfuncdata : 2,
argptrs : uintptr(argptrs),
localptrs : uintptr(localptrs),
}}
/* function table */
tab := []_FuncTab {
{entry: pc},
{entry: pc},
{entry: maxpc},
}
/* module data */
*mod = _ModuleData {
pcHeader : modHeader,
funcnametab : append(append([]byte{0}, name...), 0),
pctab : append(makePCtab(fp), encodeVariant(int(size))...),
pclntable : lnt,
ftab : tab,
findfunctab : findFuncTab,
minpc : minpc,
maxpc : maxpc,
modulename : name,
gcdata: uintptr(unsafe.Pointer(&emptyByte)),
gcbss: uintptr(unsafe.Pointer(&emptyByte)),
}
/* verify and register the new module */
moduledataverify1(mod)
registerModule(mod)
}

View file

@ -0,0 +1,201 @@
// +build go1.18,!go1.20
/*
* Copyright 2021 ByteDance Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package loader
import (
`unsafe`
`github.com/bytedance/sonic/internal/rt`
)
// A FuncFlag holds bits about a function.
// This list must match the list in cmd/internal/objabi/funcid.go.
type funcFlag uint8
type _Func struct {
entryOff uint32 // start pc
nameoff int32 // function name
args int32 // in/out args size
deferreturn uint32 // offset of start of a deferreturn call instruction from entry, if any.
pcsp uint32
pcfile uint32
pcln uint32
npcdata uint32
cuOffset uint32 // runtime.cutab offset of this function's CU
funcID uint8 // set for certain special runtime functions
flag funcFlag
_ [1]byte // pad
nfuncdata uint8 // must be last
argptrs uint32
localptrs uint32
}
type _FuncTab struct {
entry uint32
funcoff uint32
}
type _PCHeader struct {
magic uint32 // 0xFFFFFFF0
pad1, pad2 uint8 // 0,0
minLC uint8 // min instruction size
ptrSize uint8 // size of a ptr in bytes
nfunc int // number of functions in the module
nfiles uint // number of entries in the file tab
textStart uintptr // base for function entry PC offsets in this module, equal to moduledata.text
funcnameOffset uintptr // offset to the funcnametab variable from pcHeader
cuOffset uintptr // offset to the cutab variable from pcHeader
filetabOffset uintptr // offset to the filetab variable from pcHeader
pctabOffset uintptr // offset to the pctab variable from pcHeader
pclnOffset uintptr // offset to the pclntab variable from pcHeader
}
type _BitVector struct {
n int32 // # of bits
bytedata *uint8
}
type _PtabEntry struct {
name int32
typ int32
}
type _TextSection struct {
vaddr uintptr // prelinked section vaddr
length uintptr // section length
baseaddr uintptr // relocated section address
}
type _ModuleData struct {
pcHeader *_PCHeader
funcnametab []byte
cutab []uint32
filetab []byte
pctab []byte
pclntable []byte
ftab []_FuncTab
findfunctab *_FindFuncBucket
minpc, maxpc uintptr
text, etext uintptr
noptrdata, enoptrdata uintptr
data, edata uintptr
bss, ebss uintptr
noptrbss, enoptrbss uintptr
end, gcdata, gcbss uintptr
types, etypes uintptr
rodata uintptr
gofunc uintptr
textsectmap []_TextSection
typelinks []int32
itablinks []unsafe.Pointer
ptab []_PtabEntry
pluginpath string
pkghashes []struct{}
modulename string
modulehashes []struct{}
hasmain uint8
gcdatamask, gcbssmask _BitVector
typemap map[int32]unsafe.Pointer
bad bool
next *_ModuleData
}
type _FindFuncBucket struct {
idx uint32
subbuckets [16]byte
}
func makePCtab(fp int) []byte {
return append([]byte{0}, encodeVariant((fp + 1) << 1)...)
}
func registerFunction(name string, pc uintptr, textSize uintptr, fp int, args int, size uintptr, argPtrs []bool, localPtrs []bool) {
mod := new(_ModuleData)
minpc := pc
maxpc := pc + size
findFuncTab := make([]_FindFuncBucket, textSize/4096 + 1)
modHeader := &_PCHeader {
magic : 0xfffffff0,
minLC : 1,
nfunc : 1,
ptrSize : 4 << (^uintptr(0) >> 63),
textStart: minpc,
}
// cache arg and local stackmap
argptrs, localptrs := cacheStackmap(argPtrs, localPtrs, mod)
base := argptrs
if argptrs > localptrs {
base = localptrs
}
/* function entry */
lnt := []_Func {{
entryOff : 0,
nameoff : 1,
args : int32(args),
pcsp : 1,
nfuncdata : 2,
argptrs: uint32(argptrs - base),
localptrs: uint32(localptrs - base),
}}
nlnt := len(lnt)*int(unsafe.Sizeof(_Func{}))
plnt := unsafe.Pointer(&lnt[0])
/* function table */
ftab := []_FuncTab {
{entry : 0, funcoff : 16},
{entry : uint32(size)},
}
nftab := len(ftab)*int(unsafe.Sizeof(_FuncTab{}))
pftab := unsafe.Pointer(&ftab[0])
pclntab := make([]byte, 0, nftab + nlnt)
pclntab = append(pclntab, rt.BytesFrom(pftab, nftab, nftab)...)
pclntab = append(pclntab, rt.BytesFrom(plnt, nlnt, nlnt)...)
/* module data */
*mod = _ModuleData {
pcHeader : modHeader,
funcnametab : append(append([]byte{0}, name...), 0),
pctab : append(makePCtab(fp), encodeVariant(int(size))...),
pclntable : pclntab,
ftab : ftab,
text : minpc,
etext : pc + textSize,
findfunctab : &findFuncTab[0],
minpc : minpc,
maxpc : maxpc,
modulename : name,
gcdata: uintptr(unsafe.Pointer(&emptyByte)),
gcbss: uintptr(unsafe.Pointer(&emptyByte)),
gofunc: base,
}
/* verify and register the new module */
moduledataverify1(mod)
registerModule(mod)
}

View file

@ -0,0 +1,201 @@
// +build go1.20
/*
* Copyright 2021 ByteDance Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package loader
import (
`unsafe`
`github.com/bytedance/sonic/internal/rt`
)
// A FuncFlag holds bits about a function.
// This list must match the list in cmd/internal/objabi/funcid.go.
type funcFlag uint8
type _Func struct {
entryOff uint32 // start pc
nameoff int32 // function name
args int32 // in/out args size
deferreturn uint32 // offset of start of a deferreturn call instruction from entry, if any.
pcsp uint32
pcfile uint32
pcln uint32
npcdata uint32
cuOffset uint32 // runtime.cutab offset of this function's CU
funcID uint8 // set for certain special runtime functions
flag funcFlag
_ [1]byte // pad
nfuncdata uint8 // must be last
argptrs uint32
localptrs uint32
}
type _FuncTab struct {
entry uint32
funcoff uint32
}
type _PCHeader struct {
magic uint32 // 0xFFFFFFF0
pad1, pad2 uint8 // 0,0
minLC uint8 // min instruction size
ptrSize uint8 // size of a ptr in bytes
nfunc int // number of functions in the module
nfiles uint // number of entries in the file tab
textStart uintptr // base for function entry PC offsets in this module, equal to moduledata.text
funcnameOffset uintptr // offset to the funcnametab variable from pcHeader
cuOffset uintptr // offset to the cutab variable from pcHeader
filetabOffset uintptr // offset to the filetab variable from pcHeader
pctabOffset uintptr // offset to the pctab variable from pcHeader
pclnOffset uintptr // offset to the pclntab variable from pcHeader
}
type _BitVector struct {
n int32 // # of bits
bytedata *uint8
}
type _PtabEntry struct {
name int32
typ int32
}
type _TextSection struct {
vaddr uintptr // prelinked section vaddr
length uintptr // section length
baseaddr uintptr // relocated section address
}
type _ModuleData struct {
pcHeader *_PCHeader
funcnametab []byte
cutab []uint32
filetab []byte
pctab []byte
pclntable []byte
ftab []_FuncTab
findfunctab *_FindFuncBucket
minpc, maxpc uintptr
text, etext uintptr
noptrdata, enoptrdata uintptr
data, edata uintptr
bss, ebss uintptr
noptrbss, enoptrbss uintptr
end, gcdata, gcbss uintptr
types, etypes uintptr
rodata uintptr
gofunc uintptr
textsectmap []_TextSection
typelinks []int32
itablinks []unsafe.Pointer
ptab []_PtabEntry
pluginpath string
pkghashes []struct{}
modulename string
modulehashes []struct{}
hasmain uint8
gcdatamask, gcbssmask _BitVector
typemap map[int32]unsafe.Pointer
bad bool
next *_ModuleData
}
type _FindFuncBucket struct {
idx uint32
subbuckets [16]byte
}
func makePCtab(fp int) []byte {
return append([]byte{0}, encodeVariant((fp + 1) << 1)...)
}
func registerFunction(name string, pc uintptr, textSize uintptr, fp int, args int, size uintptr, argPtrs []bool, localPtrs []bool) {
mod := new(_ModuleData)
minpc := pc
maxpc := pc + size
findFuncTab := make([]_FindFuncBucket, textSize/4096 + 1)
modHeader := &_PCHeader {
magic : 0xfffffff0,
minLC : 1,
nfunc : 1,
ptrSize : 4 << (^uintptr(0) >> 63),
textStart: minpc,
}
// cache arg and local stackmap
argptrs, localptrs := cacheStackmap(argPtrs, localPtrs, mod)
base := argptrs
if argptrs > localptrs {
base = localptrs
}
/* function entry */
lnt := []_Func {{
entryOff : 0,
nameoff : 1,
args : int32(args),
pcsp : 1,
nfuncdata : 2,
argptrs: uint32(argptrs - base),
localptrs: uint32(localptrs - base),
}}
nlnt := len(lnt)*int(unsafe.Sizeof(_Func{}))
plnt := unsafe.Pointer(&lnt[0])
/* function table */
ftab := []_FuncTab {
{entry : 0, funcoff : 16},
{entry : uint32(size)},
}
nftab := len(ftab)*int(unsafe.Sizeof(_FuncTab{}))
pftab := unsafe.Pointer(&ftab[0])
pclntab := make([]byte, 0, nftab + nlnt)
pclntab = append(pclntab, rt.BytesFrom(pftab, nftab, nftab)...)
pclntab = append(pclntab, rt.BytesFrom(plnt, nlnt, nlnt)...)
/* module data */
*mod = _ModuleData {
pcHeader : modHeader,
funcnametab : append(append([]byte{0}, name...), 0),
pctab : append(makePCtab(fp), encodeVariant(int(size))...),
pclntable : pclntab,
ftab : ftab,
text : minpc,
etext : pc + textSize,
findfunctab : &findFuncTab[0],
minpc : minpc,
maxpc : maxpc,
modulename : name,
gcdata: uintptr(unsafe.Pointer(&emptyByte)),
gcbss: uintptr(unsafe.Pointer(&emptyByte)),
gofunc: base,
}
/* verify and register the new module */
moduledataverify1(mod)
registerModule(mod)
}

View file

@ -0,0 +1,74 @@
//go:build darwin || linux
// +build darwin linux
/*
* Copyright 2021 ByteDance Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package loader
import (
`fmt`
`os`
`reflect`
`syscall`
`unsafe`
)
const (
_AP = syscall.MAP_ANON | syscall.MAP_PRIVATE
_RX = syscall.PROT_READ | syscall.PROT_EXEC
_RW = syscall.PROT_READ | syscall.PROT_WRITE
)
type Loader []byte
type Function unsafe.Pointer
func (self Loader) Load(fn string, fp int, args int, argPtrs []bool, localPtrs []bool) (f Function) {
p := os.Getpagesize()
n := (((len(self) - 1) / p) + 1) * p
/* register the function */
m := mmap(n)
v := fmt.Sprintf("runtime.__%s_%x", fn, m)
registerFunction(v, m, uintptr(n), fp, args, uintptr(len(self)), argPtrs, localPtrs)
/* reference as a slice */
s := *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader {
Data : m,
Cap : n,
Len : len(self),
}))
/* copy the machine code, and make it executable */
copy(s, self)
mprotect(m, n)
return Function(&m)
}
func mmap(nb int) uintptr {
if m, _, e := syscall.RawSyscall6(syscall.SYS_MMAP, 0, uintptr(nb), _RW, _AP, 0, 0); e != 0 {
panic(e)
} else {
return m
}
}
func mprotect(p uintptr, nb int) {
if _, _, err := syscall.RawSyscall(syscall.SYS_MPROTECT, p, uintptr(nb), _RX); err != 0 {
panic(err)
}
}

View file

@ -0,0 +1,111 @@
//go:build windows
// +build windows
/*
* Copyright 2021 ByteDance Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package loader
import (
`fmt`
`os`
`reflect`
`syscall`
`unsafe`
)
const (
MEM_COMMIT = 0x00001000
MEM_RESERVE = 0x00002000
)
var (
libKernel32 = syscall.NewLazyDLL("KERNEL32.DLL")
libKernel32_VirtualAlloc = libKernel32.NewProc("VirtualAlloc")
libKernel32_VirtualProtect = libKernel32.NewProc("VirtualProtect")
)
type Loader []byte
type Function unsafe.Pointer
func (self Loader) Load(fn string, fp int, args int, argPtrs []bool, localPtrs []bool) (f Function) {
p := os.Getpagesize()
n := (((len(self) - 1) / p) + 1) * p
/* register the function */
m := mmap(n)
v := fmt.Sprintf("runtime.__%s_%x", fn, m)
registerFunction(v, m, uintptr(n), fp, args, uintptr(len(self)), argPtrs, localPtrs)
/* reference as a slice */
s := *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader {
Data : m,
Cap : n,
Len : len(self),
}))
/* copy the machine code, and make it executable */
copy(s, self)
mprotect(m, n)
return Function(&m)
}
func mmap(nb int) uintptr {
addr, err := winapi_VirtualAlloc(0, nb, MEM_COMMIT|MEM_RESERVE, syscall.PAGE_READWRITE)
if err != nil {
panic(err)
}
return addr
}
func mprotect(p uintptr, nb int) (oldProtect int) {
err := winapi_VirtualProtect(p, nb, syscall.PAGE_EXECUTE_READ, &oldProtect)
if err != nil {
panic(err)
}
return
}
// winapi_VirtualAlloc allocate memory
// Doc: https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualalloc
func winapi_VirtualAlloc(lpAddr uintptr, dwSize int, flAllocationType int, flProtect int) (uintptr, error) {
r1, _, err := libKernel32_VirtualAlloc.Call(
lpAddr,
uintptr(dwSize),
uintptr(flAllocationType),
uintptr(flProtect),
)
if r1 == 0 {
return 0, err
}
return r1, nil
}
// winapi_VirtualProtect change memory protection
// Doc: https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualprotect
func winapi_VirtualProtect(lpAddr uintptr, dwSize int, flNewProtect int, lpflOldProtect *int) error {
r1, _, err := libKernel32_VirtualProtect.Call(
lpAddr,
uintptr(dwSize),
uintptr(flNewProtect),
uintptr(unsafe.Pointer(lpflOldProtect)),
)
if r1 == 0 {
return err
}
return nil
}

View file

@ -0,0 +1,135 @@
// Code generated by Makefile, DO NOT EDIT.
/*
* Copyright 2021 ByteDance Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package avx
import (
`unsafe`
`github.com/bytedance/sonic/internal/native/types`
)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __i64toa(out *byte, val int64) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __u64toa(out *byte, val uint64) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __f64toa(out *byte, val float64) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __f32toa(out *byte, val float32) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __lspace(sp unsafe.Pointer, nb int, off int) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __quote(sp unsafe.Pointer, nb int, dp unsafe.Pointer, dn *int, flags uint64) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __html_escape(sp unsafe.Pointer, nb int, dp unsafe.Pointer, dn *int) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __unquote(sp unsafe.Pointer, nb int, dp unsafe.Pointer, ep *int, flags uint64) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __value(s unsafe.Pointer, n int, p int, v *types.JsonState, flags uint64) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __vstring(s *string, p *int, v *types.JsonState, flags uint64)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __vnumber(s *string, p *int, v *types.JsonState)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __vsigned(s *string, p *int, v *types.JsonState)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __vunsigned(s *string, p *int, v *types.JsonState)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __skip_one(s *string, p *int, m *types.StateMachine, flags uint64) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __skip_one_fast(s *string, p *int) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __skip_array(s *string, p *int, m *types.StateMachine, flags uint64) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __skip_object(s *string, p *int, m *types.StateMachine, flags uint64) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __skip_number(s *string, p *int) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __validate_one(s *string, p *int, m *types.StateMachine) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __get_by_path(s *string, p *int, path *[]interface{}) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __validate_utf8(s *string, p *int, m *types.StateMachine) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __validate_utf8_fast(s *string) (ret int)

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,49 @@
// Code generated by Makefile, DO NOT EDIT.
/*
* Copyright 2021 ByteDance Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package avx
var (
S_f64toa = _subr__f64toa
S_f32toa = _subr__f32toa
S_i64toa = _subr__i64toa
S_u64toa = _subr__u64toa
S_lspace = _subr__lspace
)
var (
S_quote = _subr__quote
S_unquote = _subr__unquote
)
var (
S_value = _subr__value
S_vstring = _subr__vstring
S_vnumber = _subr__vnumber
S_vsigned = _subr__vsigned
S_vunsigned = _subr__vunsigned
)
var (
S_skip_one = _subr__skip_one
S_skip_one_fast = _subr__skip_one_fast
S_skip_array = _subr__skip_array
S_skip_object = _subr__skip_object
S_skip_number = _subr__skip_number
S_get_by_path = _subr__get_by_path
)

View file

@ -0,0 +1,109 @@
// +build !noasm !appengine
// Code generated by asm2asm, DO NOT EDIT.
package avx
//go:nosplit
//go:noescape
//goland:noinspection ALL
func __native_entry__() uintptr
var (
_subr__f32toa = __native_entry__() + 29744
_subr__f64toa = __native_entry__() + 496
_subr__get_by_path = __native_entry__() + 27424
_subr__html_escape = __native_entry__() + 9968
_subr__i64toa = __native_entry__() + 4112
_subr__lspace = __native_entry__() + 80
_subr__quote = __native_entry__() + 5792
_subr__skip_array = __native_entry__() + 20576
_subr__skip_number = __native_entry__() + 23920
_subr__skip_object = __native_entry__() + 22496
_subr__skip_one = __native_entry__() + 24080
_subr__skip_one_fast = __native_entry__() + 24320
_subr__u64toa = __native_entry__() + 4384
_subr__unquote = __native_entry__() + 7488
_subr__validate_one = __native_entry__() + 24144
_subr__validate_utf8 = __native_entry__() + 28464
_subr__validate_utf8_fast = __native_entry__() + 29136
_subr__value = __native_entry__() + 14672
_subr__vnumber = __native_entry__() + 18320
_subr__vsigned = __native_entry__() + 19856
_subr__vstring = __native_entry__() + 16864
_subr__vunsigned = __native_entry__() + 20208
)
const (
_stack__f32toa = 56
_stack__f64toa = 80
_stack__get_by_path = 312
_stack__html_escape = 64
_stack__i64toa = 16
_stack__lspace = 8
_stack__quote = 80
_stack__skip_array = 128
_stack__skip_number = 72
_stack__skip_object = 128
_stack__skip_one = 128
_stack__skip_one_fast = 208
_stack__u64toa = 8
_stack__unquote = 128
_stack__validate_one = 128
_stack__validate_utf8 = 48
_stack__validate_utf8_fast = 24
_stack__value = 368
_stack__vnumber = 280
_stack__vsigned = 16
_stack__vstring = 128
_stack__vunsigned = 24
)
var (
_ = _subr__f32toa
_ = _subr__f64toa
_ = _subr__get_by_path
_ = _subr__html_escape
_ = _subr__i64toa
_ = _subr__lspace
_ = _subr__quote
_ = _subr__skip_array
_ = _subr__skip_number
_ = _subr__skip_object
_ = _subr__skip_one
_ = _subr__skip_one_fast
_ = _subr__u64toa
_ = _subr__unquote
_ = _subr__validate_one
_ = _subr__validate_utf8
_ = _subr__validate_utf8_fast
_ = _subr__value
_ = _subr__vnumber
_ = _subr__vsigned
_ = _subr__vstring
_ = _subr__vunsigned
)
const (
_ = _stack__f32toa
_ = _stack__f64toa
_ = _stack__get_by_path
_ = _stack__html_escape
_ = _stack__i64toa
_ = _stack__lspace
_ = _stack__quote
_ = _stack__skip_array
_ = _stack__skip_number
_ = _stack__skip_object
_ = _stack__skip_one
_ = _stack__skip_one_fast
_ = _stack__u64toa
_ = _stack__unquote
_ = _stack__validate_one
_ = _stack__validate_utf8
_ = _stack__validate_utf8_fast
_ = _stack__value
_ = _stack__vnumber
_ = _stack__vsigned
_ = _stack__vstring
_ = _stack__vunsigned
)

View file

@ -0,0 +1,135 @@
// Code generated by Makefile, DO NOT EDIT.
/*
* Copyright 2021 ByteDance Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package avx2
import (
`unsafe`
`github.com/bytedance/sonic/internal/native/types`
)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __i64toa(out *byte, val int64) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __u64toa(out *byte, val uint64) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __f64toa(out *byte, val float64) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __f32toa(out *byte, val float32) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __lspace(sp unsafe.Pointer, nb int, off int) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __quote(sp unsafe.Pointer, nb int, dp unsafe.Pointer, dn *int, flags uint64) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __html_escape(sp unsafe.Pointer, nb int, dp unsafe.Pointer, dn *int) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __unquote(sp unsafe.Pointer, nb int, dp unsafe.Pointer, ep *int, flags uint64) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __value(s unsafe.Pointer, n int, p int, v *types.JsonState, flags uint64) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __vstring(s *string, p *int, v *types.JsonState, flags uint64)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __vnumber(s *string, p *int, v *types.JsonState)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __vsigned(s *string, p *int, v *types.JsonState)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __vunsigned(s *string, p *int, v *types.JsonState)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __skip_one(s *string, p *int, m *types.StateMachine, flags uint64) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __skip_one_fast(s *string, p *int) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __skip_array(s *string, p *int, m *types.StateMachine, flags uint64) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __skip_object(s *string, p *int, m *types.StateMachine, flags uint64) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __skip_number(s *string, p *int) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __validate_one(s *string, p *int, m *types.StateMachine) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __get_by_path(s *string, p *int, path *[]interface{}) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __validate_utf8(s *string, p *int, m *types.StateMachine) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __validate_utf8_fast(s *string) (ret int)

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,49 @@
// Code generated by Makefile, DO NOT EDIT.
/*
* Copyright 2021 ByteDance Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package avx2
var (
S_f64toa = _subr__f64toa
S_f32toa = _subr__f32toa
S_i64toa = _subr__i64toa
S_u64toa = _subr__u64toa
S_lspace = _subr__lspace
)
var (
S_quote = _subr__quote
S_unquote = _subr__unquote
)
var (
S_value = _subr__value
S_vstring = _subr__vstring
S_vnumber = _subr__vnumber
S_vsigned = _subr__vsigned
S_vunsigned = _subr__vunsigned
)
var (
S_skip_one = _subr__skip_one
S_skip_one_fast = _subr__skip_one_fast
S_skip_array = _subr__skip_array
S_skip_object = _subr__skip_object
S_skip_number = _subr__skip_number
S_get_by_path = _subr__get_by_path
)

View file

@ -0,0 +1,109 @@
// +build !noasm !appengine
// Code generated by asm2asm, DO NOT EDIT.
package avx2
//go:nosplit
//go:noescape
//goland:noinspection ALL
func __native_entry__() uintptr
var (
_subr__f32toa = __native_entry__() + 35216
_subr__f64toa = __native_entry__() + 752
_subr__get_by_path = __native_entry__() + 30384
_subr__html_escape = __native_entry__() + 11712
_subr__i64toa = __native_entry__() + 4368
_subr__lspace = __native_entry__() + 224
_subr__quote = __native_entry__() + 6160
_subr__skip_array = __native_entry__() + 22864
_subr__skip_number = __native_entry__() + 26928
_subr__skip_object = __native_entry__() + 24864
_subr__skip_one = __native_entry__() + 27088
_subr__skip_one_fast = __native_entry__() + 27504
_subr__u64toa = __native_entry__() + 4640
_subr__unquote = __native_entry__() + 8960
_subr__validate_one = __native_entry__() + 27152
_subr__validate_utf8 = __native_entry__() + 31552
_subr__validate_utf8_fast = __native_entry__() + 32496
_subr__value = __native_entry__() + 16816
_subr__vnumber = __native_entry__() + 20608
_subr__vsigned = __native_entry__() + 22144
_subr__vstring = __native_entry__() + 19312
_subr__vunsigned = __native_entry__() + 22496
)
const (
_stack__f32toa = 56
_stack__f64toa = 80
_stack__get_by_path = 320
_stack__html_escape = 72
_stack__i64toa = 16
_stack__lspace = 8
_stack__quote = 72
_stack__skip_array = 120
_stack__skip_number = 80
_stack__skip_object = 120
_stack__skip_one = 120
_stack__skip_one_fast = 216
_stack__u64toa = 8
_stack__unquote = 128
_stack__validate_one = 120
_stack__validate_utf8 = 48
_stack__validate_utf8_fast = 200
_stack__value = 368
_stack__vnumber = 280
_stack__vsigned = 16
_stack__vstring = 104
_stack__vunsigned = 24
)
var (
_ = _subr__f32toa
_ = _subr__f64toa
_ = _subr__get_by_path
_ = _subr__html_escape
_ = _subr__i64toa
_ = _subr__lspace
_ = _subr__quote
_ = _subr__skip_array
_ = _subr__skip_number
_ = _subr__skip_object
_ = _subr__skip_one
_ = _subr__skip_one_fast
_ = _subr__u64toa
_ = _subr__unquote
_ = _subr__validate_one
_ = _subr__validate_utf8
_ = _subr__validate_utf8_fast
_ = _subr__value
_ = _subr__vnumber
_ = _subr__vsigned
_ = _subr__vstring
_ = _subr__vunsigned
)
const (
_ = _stack__f32toa
_ = _stack__f64toa
_ = _stack__get_by_path
_ = _stack__html_escape
_ = _stack__i64toa
_ = _stack__lspace
_ = _stack__quote
_ = _stack__skip_array
_ = _stack__skip_number
_ = _stack__skip_object
_ = _stack__skip_one
_ = _stack__skip_one_fast
_ = _stack__u64toa
_ = _stack__unquote
_ = _stack__validate_one
_ = _stack__validate_utf8
_ = _stack__validate_utf8_fast
_ = _stack__value
_ = _stack__vnumber
_ = _stack__vsigned
_ = _stack__vstring
_ = _stack__vunsigned
)

View file

@ -0,0 +1,202 @@
/*
* Copyright 2021 ByteDance Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package native
import (
`unsafe`
`github.com/bytedance/sonic/internal/cpu`
`github.com/bytedance/sonic/internal/native/avx`
`github.com/bytedance/sonic/internal/native/avx2`
`github.com/bytedance/sonic/internal/native/sse`
`github.com/bytedance/sonic/internal/native/types`
)
const (
MaxFrameSize uintptr = 400
BufPaddingSize int = 64
)
var (
S_f64toa uintptr
S_f32toa uintptr
S_i64toa uintptr
S_u64toa uintptr
S_lspace uintptr
)
var (
S_quote uintptr
S_unquote uintptr
)
var (
S_value uintptr
S_vstring uintptr
S_vnumber uintptr
S_vsigned uintptr
S_vunsigned uintptr
)
var (
S_skip_one uintptr
S_skip_one_fast uintptr
S_get_by_path uintptr
S_skip_array uintptr
S_skip_object uintptr
S_skip_number uintptr
)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func Quote(s unsafe.Pointer, nb int, dp unsafe.Pointer, dn *int, flags uint64) int
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func Unquote(s unsafe.Pointer, nb int, dp unsafe.Pointer, ep *int, flags uint64) int
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func HTMLEscape(s unsafe.Pointer, nb int, dp unsafe.Pointer, dn *int) int
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func Value(s unsafe.Pointer, n int, p int, v *types.JsonState, flags uint64) int
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func SkipOne(s *string, p *int, m *types.StateMachine, flags uint64) int
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func SkipOneFast(s *string, p *int) int
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func GetByPath(s *string, p *int, path *[]interface{}) int
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func ValidateOne(s *string, p *int, m *types.StateMachine) int
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func I64toa(out *byte, val int64) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func U64toa(out *byte, val uint64) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func F64toa(out *byte, val float64) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func ValidateUTF8(s *string, p *int, m *types.StateMachine) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func ValidateUTF8Fast(s *string) (ret int)
func useAVX() {
S_f64toa = avx.S_f64toa
S_f32toa = avx.S_f32toa
S_i64toa = avx.S_i64toa
S_u64toa = avx.S_u64toa
S_lspace = avx.S_lspace
S_quote = avx.S_quote
S_unquote = avx.S_unquote
S_value = avx.S_value
S_vstring = avx.S_vstring
S_vnumber = avx.S_vnumber
S_vsigned = avx.S_vsigned
S_vunsigned = avx.S_vunsigned
S_skip_one = avx.S_skip_one
S_skip_one_fast = avx.S_skip_one_fast
S_skip_array = avx.S_skip_array
S_skip_object = avx.S_skip_object
S_skip_number = avx.S_skip_number
S_get_by_path = avx.S_get_by_path
}
func useAVX2() {
S_f64toa = avx2.S_f64toa
S_f32toa = avx2.S_f32toa
S_i64toa = avx2.S_i64toa
S_u64toa = avx2.S_u64toa
S_lspace = avx2.S_lspace
S_quote = avx2.S_quote
S_unquote = avx2.S_unquote
S_value = avx2.S_value
S_vstring = avx2.S_vstring
S_vnumber = avx2.S_vnumber
S_vsigned = avx2.S_vsigned
S_vunsigned = avx2.S_vunsigned
S_skip_one = avx2.S_skip_one
S_skip_one_fast = avx2.S_skip_one_fast
S_skip_array = avx2.S_skip_array
S_skip_object = avx2.S_skip_object
S_skip_number = avx2.S_skip_number
S_get_by_path = avx2.S_get_by_path
}
func useSSE() {
S_f64toa = sse.S_f64toa
S_f32toa = sse.S_f32toa
S_i64toa = sse.S_i64toa
S_u64toa = sse.S_u64toa
S_lspace = sse.S_lspace
S_quote = sse.S_quote
S_unquote = sse.S_unquote
S_value = sse.S_value
S_vstring = sse.S_vstring
S_vnumber = sse.S_vnumber
S_vsigned = sse.S_vsigned
S_vunsigned = sse.S_vunsigned
S_skip_one = sse.S_skip_one
S_skip_one_fast = sse.S_skip_one_fast
S_skip_array = sse.S_skip_array
S_skip_object = sse.S_skip_object
S_skip_number = sse.S_skip_number
S_get_by_path = sse.S_get_by_path
}
func init() {
if cpu.HasAVX2 {
useAVX2()
} else if cpu.HasAVX {
useAVX()
} else if cpu.HasSSE {
useSSE()
} else {
panic("Unsupported CPU, maybe it's too old to run Sonic.")
}
}

View file

@ -0,0 +1,137 @@
//
// Copyright 2021 ByteDance Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#include "go_asm.h"
#include "funcdata.h"
#include "textflag.h"
TEXT ·Quote(SB), NOSPLIT, $0 - 48
CMPB github·combytedancesonicinternalcpu·HasAVX2(SB), $0
JE 2(PC)
JMP github·combytedancesonicinternalnativeavx2·__quote(SB)
CMPB github·combytedancesonicinternalcpu·HasAVX(SB), $0
JE 2(PC)
JMP github·combytedancesonicinternalnativeavx·__quote(SB)
JMP github·combytedancesonicinternalnativesse·__quote(SB)
TEXT ·Unquote(SB), NOSPLIT, $0 - 48
CMPB github·combytedancesonicinternalcpu·HasAVX2(SB), $0
JE 2(PC)
JMP github·combytedancesonicinternalnativeavx2·__unquote(SB)
CMPB github·combytedancesonicinternalcpu·HasAVX(SB), $0
JE 2(PC)
JMP github·combytedancesonicinternalnativeavx·__unquote(SB)
JMP github·combytedancesonicinternalnativesse·__unquote(SB)
TEXT ·HTMLEscape(SB), NOSPLIT, $0 - 40
CMPB github·combytedancesonicinternalcpu·HasAVX2(SB), $0
JE 2(PC)
JMP github·combytedancesonicinternalnativeavx2·__html_escape(SB)
CMPB github·combytedancesonicinternalcpu·HasAVX(SB), $0
JE 2(PC)
JMP github·combytedancesonicinternalnativeavx·__html_escape(SB)
JMP github·combytedancesonicinternalnativesse·__html_escape(SB)
TEXT ·Value(SB), NOSPLIT, $0 - 48
CMPB github·combytedancesonicinternalcpu·HasAVX2(SB), $0
JE 2(PC)
JMP github·combytedancesonicinternalnativeavx2·__value(SB)
CMPB github·combytedancesonicinternalcpu·HasAVX(SB), $0
JE 2(PC)
JMP github·combytedancesonicinternalnativeavx·__value(SB)
JMP github·combytedancesonicinternalnativesse·__value(SB)
TEXT ·SkipOne(SB), NOSPLIT, $0 - 40
CMPB github·combytedancesonicinternalcpu·HasAVX2(SB), $0
JE 2(PC)
JMP github·combytedancesonicinternalnativeavx2·__skip_one(SB)
CMPB github·combytedancesonicinternalcpu·HasAVX(SB), $0
JE 2(PC)
JMP github·combytedancesonicinternalnativeavx·__skip_one(SB)
JMP github·combytedancesonicinternalnativesse·__skip_one(SB)
TEXT ·SkipOneFast(SB), NOSPLIT, $0 - 24
CMPB github·combytedancesonicinternalcpu·HasAVX2(SB), $0
JE 2(PC)
JMP github·combytedancesonicinternalnativeavx2·__skip_one_fast(SB)
CMPB github·combytedancesonicinternalcpu·HasAVX(SB), $0
JE 2(PC)
JMP github·combytedancesonicinternalnativeavx·__skip_one_fast(SB)
JMP github·combytedancesonicinternalnativesse·__skip_one_fast(SB)
TEXT ·GetByPath(SB), NOSPLIT, $0 - 32
CMPB github·combytedancesonicinternalcpu·HasAVX2(SB), $0
JE 2(PC)
JMP github·combytedancesonicinternalnativeavx2·__get_by_path(SB)
CMPB github·combytedancesonicinternalcpu·HasAVX(SB), $0
JE 2(PC)
JMP github·combytedancesonicinternalnativeavx·__get_by_path(SB)
JMP github·combytedancesonicinternalnativesse·__get_by_path(SB)
TEXT ·ValidateOne(SB), NOSPLIT, $0 - 32
CMPB github·combytedancesonicinternalcpu·HasAVX2(SB), $0
JE 2(PC)
JMP github·combytedancesonicinternalnativeavx2·__validate_one(SB)
CMPB github·combytedancesonicinternalcpu·HasAVX(SB), $0
JE 2(PC)
JMP github·combytedancesonicinternalnativeavx·__validate_one(SB)
JMP github·combytedancesonicinternalnativesse·__validate_one(SB)
TEXT ·ValidateUTF8(SB), NOSPLIT, $0 - 40
CMPB github·combytedancesonicinternalcpu·HasAVX2(SB), $0
JE 2(PC)
JMP github·combytedancesonicinternalnativeavx2·__validate_utf8(SB)
CMPB github·combytedancesonicinternalcpu·HasAVX(SB), $0
JE 2(PC)
JMP github·combytedancesonicinternalnativeavx·__validate_utf8(SB)
JMP github·combytedancesonicinternalnativesse·__validate_utf8(SB)
TEXT ·ValidateUTF8Fast(SB), NOSPLIT, $0 - 16
CMPB github·combytedancesonicinternalcpu·HasAVX2(SB), $0
JE 2(PC)
JMP github·combytedancesonicinternalnativeavx2·__validate_utf8_fast(SB)
CMPB github·combytedancesonicinternalcpu·HasAVX(SB), $0
JE 2(PC)
JMP github·combytedancesonicinternalnativeavx·__validate_utf8_fast(SB)
JMP github·combytedancesonicinternalnativesse·__validate_utf8_fast(SB)
TEXT ·I64toa(SB), NOSPLIT, $0 - 32
CMPB github·combytedancesonicinternalcpu·HasAVX2(SB), $0
JE 2(PC)
JMP github·combytedancesonicinternalnativeavx2·__i64toa(SB)
CMPB github·combytedancesonicinternalcpu·HasAVX(SB), $0
JE 2(PC)
JMP github·combytedancesonicinternalnativeavx·__i64toa(SB)
JMP github·combytedancesonicinternalnativesse·__i64toa(SB)
TEXT ·U64toa(SB), NOSPLIT, $0 - 32
CMPB github·combytedancesonicinternalcpu·HasAVX2(SB), $0
JE 2(PC)
JMP github·combytedancesonicinternalnativeavx2·__u64toa(SB)
CMPB github·combytedancesonicinternalcpu·HasAVX(SB), $0
JE 2(PC)
JMP github·combytedancesonicinternalnativeavx·__u64toa(SB)
JMP github·combytedancesonicinternalnativesse·__u64toa(SB)
TEXT ·F64toa(SB), NOSPLIT, $0 - 32
CMPB github·combytedancesonicinternalcpu·HasAVX2(SB), $0
JE 2(PC)
JMP github·combytedancesonicinternalnativeavx2·__f64toa(SB)
CMPB github·combytedancesonicinternalcpu·HasAVX(SB), $0
JE 2(PC)
JMP github·combytedancesonicinternalnativeavx·__f64toa(SB)
JMP github·combytedancesonicinternalnativesse·__f64toa(SB)

View file

@ -0,0 +1,138 @@
/*
* Copyright 2021 ByteDance Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package {{PACKAGE}}
import (
`math`
`strconv`
`testing`
`math/rand`
`encoding/json`
`github.com/stretchr/testify/assert`
)
func TestFastFloat_Encode(t *testing.T) {
var buf [64]byte
assert.Equal(t, "0" , string(buf[:__f64toa(&buf[0], 0)]))
assert.Equal(t, "-0" , string(buf[:__f64toa(&buf[0], math.Float64frombits(0x8000000000000000))]))
assert.Equal(t, "12340000000" , string(buf[:__f64toa(&buf[0], 1234e7)]))
assert.Equal(t, "12.34" , string(buf[:__f64toa(&buf[0], 1234e-2)]))
assert.Equal(t, "0.001234" , string(buf[:__f64toa(&buf[0], 1234e-6)]))
assert.Equal(t, "1e+30" , string(buf[:__f64toa(&buf[0], 1e30)]))
assert.Equal(t, "1.234e+33" , string(buf[:__f64toa(&buf[0], 1234e30)]))
assert.Equal(t, "1.234e+308" , string(buf[:__f64toa(&buf[0], 1234e305)]))
assert.Equal(t, "1.234e-317" , string(buf[:__f64toa(&buf[0], 1234e-320)]))
assert.Equal(t, "1.7976931348623157e+308" , string(buf[:__f64toa(&buf[0], 1.7976931348623157e308)]))
assert.Equal(t, "-12340000000" , string(buf[:__f64toa(&buf[0], -1234e7)]))
assert.Equal(t, "-12.34" , string(buf[:__f64toa(&buf[0], -1234e-2)]))
assert.Equal(t, "-0.001234" , string(buf[:__f64toa(&buf[0], -1234e-6)]))
assert.Equal(t, "-1e+30" , string(buf[:__f64toa(&buf[0], -1e30)]))
assert.Equal(t, "-1.234e+33" , string(buf[:__f64toa(&buf[0], -1234e30)]))
assert.Equal(t, "-1.234e+308" , string(buf[:__f64toa(&buf[0], -1234e305)]))
assert.Equal(t, "-1.234e-317" , string(buf[:__f64toa(&buf[0], -1234e-320)]))
assert.Equal(t, "-2.2250738585072014e-308" , string(buf[:__f64toa(&buf[0], -2.2250738585072014e-308)]))
}
func TestFastFloat_Random(t *testing.T) {
var buf [64]byte
N := 10000
for i := 0; i < N; i++ {
b64 := uint64(rand.Uint32())<<32 | uint64(rand.Uint32())
f64 := math.Float64frombits(b64)
jout, jerr := json.Marshal(f64)
n := __f64toa(&buf[0], f64)
if jerr == nil {
assert.Equal(t, jout, buf[:n])
} else {
assert.True(t, n == 0)
}
f32 := math.Float32frombits(rand.Uint32())
jout, jerr = json.Marshal(f32)
n = __f32toa(&buf[0], f32)
if jerr == nil {
assert.Equal(t, jout, buf[:n])
} else {
assert.True(t, n == 0)
}
}
}
func BenchmarkParseFloat64(b *testing.B) {
var f64toaBenches = []struct {
name string
float float64
}{
{"Zero", 0},
{"Decimal", 33909},
{"Float", 339.7784},
{"Exp", -5.09e75},
{"NegExp", -5.11e-95},
{"LongExp", 1.234567890123456e-78},
{"Big", 123456789123456789123456789},
}
for _, c := range f64toaBenches {
f64bench := []struct {
name string
test func(*testing.B)
}{{
name: "StdLib",
test: func(b *testing.B) { var buf [64]byte; for i := 0; i < b.N; i++ { strconv.AppendFloat(buf[:0], c.float, 'g', -1, 64) }},
}, {
name: "FastFloat",
test: func(b *testing.B) { var buf [64]byte; for i := 0; i < b.N; i++ { __f64toa(&buf[0], c.float) }},
}}
for _, bm := range f64bench {
name := bm.name + "_" + c.name
b.Run(name, bm.test)
}
}
}
func BenchmarkParseFloat32(b *testing.B) {
var f32toaBenches = []struct {
name string
float float32
}{
{"Zero", 0},
{"Integer", 33909},
{"ExactFraction", 3.375},
{"Point", 339.7784},
{"Exp", -5.09e25},
{"NegExp", -5.11e-25},
{"Shortest", 1.234567e-8},
}
for _, c := range f32toaBenches {
bench := []struct {
name string
test func(*testing.B)
}{{
name: "StdLib32",
test: func(b *testing.B) { var buf [64]byte; for i := 0; i < b.N; i++ { strconv.AppendFloat(buf[:0], float64(c.float), 'g', -1, 32) }},
}, {
name: "FastFloat32",
test: func(b *testing.B) { var buf [64]byte; for i := 0; i < b.N; i++ { __f32toa(&buf[0], c.float) }},
}}
for _, bm := range bench {
name := bm.name + "_" + c.name
b.Run(name, bm.test)
}
}
}

View file

@ -0,0 +1,151 @@
/*
* Copyright 2021 ByteDance Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package {{PACKAGE}}
import (
`strconv`
`testing`
`fmt`
`github.com/stretchr/testify/assert`
)
func TestFastInt_IntToString(t *testing.T) {
var buf [32]byte
assert.Equal(t, "0" , string(buf[:__i64toa(&buf[0], 0)]))
assert.Equal(t, "1" , string(buf[:__i64toa(&buf[0], 1)]))
assert.Equal(t, "12" , string(buf[:__i64toa(&buf[0], 12)]))
assert.Equal(t, "123" , string(buf[:__i64toa(&buf[0], 123)]))
assert.Equal(t, "1234" , string(buf[:__i64toa(&buf[0], 1234)]))
assert.Equal(t, "12345" , string(buf[:__i64toa(&buf[0], 12345)]))
assert.Equal(t, "123456" , string(buf[:__i64toa(&buf[0], 123456)]))
assert.Equal(t, "1234567" , string(buf[:__i64toa(&buf[0], 1234567)]))
assert.Equal(t, "12345678" , string(buf[:__i64toa(&buf[0], 12345678)]))
assert.Equal(t, "123456789" , string(buf[:__i64toa(&buf[0], 123456789)]))
assert.Equal(t, "1234567890" , string(buf[:__i64toa(&buf[0], 1234567890)]))
assert.Equal(t, "12345678901" , string(buf[:__i64toa(&buf[0], 12345678901)]))
assert.Equal(t, "123456789012" , string(buf[:__i64toa(&buf[0], 123456789012)]))
assert.Equal(t, "1234567890123" , string(buf[:__i64toa(&buf[0], 1234567890123)]))
assert.Equal(t, "12345678901234" , string(buf[:__i64toa(&buf[0], 12345678901234)]))
assert.Equal(t, "123456789012345" , string(buf[:__i64toa(&buf[0], 123456789012345)]))
assert.Equal(t, "1234567890123456" , string(buf[:__i64toa(&buf[0], 1234567890123456)]))
assert.Equal(t, "12345678901234567" , string(buf[:__i64toa(&buf[0], 12345678901234567)]))
assert.Equal(t, "123456789012345678" , string(buf[:__i64toa(&buf[0], 123456789012345678)]))
assert.Equal(t, "1234567890123456789" , string(buf[:__i64toa(&buf[0], 1234567890123456789)]))
assert.Equal(t, "9223372036854775807" , string(buf[:__i64toa(&buf[0], 9223372036854775807)]))
assert.Equal(t, "-1" , string(buf[:__i64toa(&buf[0], -1)]))
assert.Equal(t, "-12" , string(buf[:__i64toa(&buf[0], -12)]))
assert.Equal(t, "-123" , string(buf[:__i64toa(&buf[0], -123)]))
assert.Equal(t, "-1234" , string(buf[:__i64toa(&buf[0], -1234)]))
assert.Equal(t, "-12345" , string(buf[:__i64toa(&buf[0], -12345)]))
assert.Equal(t, "-123456" , string(buf[:__i64toa(&buf[0], -123456)]))
assert.Equal(t, "-1234567" , string(buf[:__i64toa(&buf[0], -1234567)]))
assert.Equal(t, "-12345678" , string(buf[:__i64toa(&buf[0], -12345678)]))
assert.Equal(t, "-123456789" , string(buf[:__i64toa(&buf[0], -123456789)]))
assert.Equal(t, "-1234567890" , string(buf[:__i64toa(&buf[0], -1234567890)]))
assert.Equal(t, "-12345678901" , string(buf[:__i64toa(&buf[0], -12345678901)]))
assert.Equal(t, "-123456789012" , string(buf[:__i64toa(&buf[0], -123456789012)]))
assert.Equal(t, "-1234567890123" , string(buf[:__i64toa(&buf[0], -1234567890123)]))
assert.Equal(t, "-12345678901234" , string(buf[:__i64toa(&buf[0], -12345678901234)]))
assert.Equal(t, "-123456789012345" , string(buf[:__i64toa(&buf[0], -123456789012345)]))
assert.Equal(t, "-1234567890123456" , string(buf[:__i64toa(&buf[0], -1234567890123456)]))
assert.Equal(t, "-12345678901234567" , string(buf[:__i64toa(&buf[0], -12345678901234567)]))
assert.Equal(t, "-123456789012345678" , string(buf[:__i64toa(&buf[0], -123456789012345678)]))
assert.Equal(t, "-1234567890123456789" , string(buf[:__i64toa(&buf[0], -1234567890123456789)]))
assert.Equal(t, "-9223372036854775808" , string(buf[:__i64toa(&buf[0], -9223372036854775808)]))
}
func TestFastInt_UintToString(t *testing.T) {
var buf [32]byte
assert.Equal(t, "0" , string(buf[:__u64toa(&buf[0], 0)]))
assert.Equal(t, "1" , string(buf[:__u64toa(&buf[0], 1)]))
assert.Equal(t, "12" , string(buf[:__u64toa(&buf[0], 12)]))
assert.Equal(t, "123" , string(buf[:__u64toa(&buf[0], 123)]))
assert.Equal(t, "1234" , string(buf[:__u64toa(&buf[0], 1234)]))
assert.Equal(t, "12345" , string(buf[:__u64toa(&buf[0], 12345)]))
assert.Equal(t, "123456" , string(buf[:__u64toa(&buf[0], 123456)]))
assert.Equal(t, "1234567" , string(buf[:__u64toa(&buf[0], 1234567)]))
assert.Equal(t, "12345678" , string(buf[:__u64toa(&buf[0], 12345678)]))
assert.Equal(t, "123456789" , string(buf[:__u64toa(&buf[0], 123456789)]))
assert.Equal(t, "1234567890" , string(buf[:__u64toa(&buf[0], 1234567890)]))
assert.Equal(t, "12345678901" , string(buf[:__u64toa(&buf[0], 12345678901)]))
assert.Equal(t, "123456789012" , string(buf[:__u64toa(&buf[0], 123456789012)]))
assert.Equal(t, "1234567890123" , string(buf[:__u64toa(&buf[0], 1234567890123)]))
assert.Equal(t, "12345678901234" , string(buf[:__u64toa(&buf[0], 12345678901234)]))
assert.Equal(t, "123456789012345" , string(buf[:__u64toa(&buf[0], 123456789012345)]))
assert.Equal(t, "1234567890123456" , string(buf[:__u64toa(&buf[0], 1234567890123456)]))
assert.Equal(t, "12345678901234567" , string(buf[:__u64toa(&buf[0], 12345678901234567)]))
assert.Equal(t, "123456789012345678" , string(buf[:__u64toa(&buf[0], 123456789012345678)]))
assert.Equal(t, "1234567890123456789" , string(buf[:__u64toa(&buf[0], 1234567890123456789)]))
assert.Equal(t, "12345678901234567890" , string(buf[:__u64toa(&buf[0], 12345678901234567890)]))
assert.Equal(t, "18446744073709551615" , string(buf[:__u64toa(&buf[0], 18446744073709551615)]))
}
func BenchmarkFastInt_IntToString(b *testing.B) {
benchmarks := []struct {
name string
test func(*testing.B)
}{{
name: "StdLib-Positive",
test: func(b *testing.B) { var buf [32]byte; for i := 0; i < b.N; i++ { strconv.AppendInt(buf[:0], int64(i), 10) }},
}, {
name: "StdLib-Negative",
test: func(b *testing.B) { var buf [32]byte; for i := 0; i < b.N; i++ { strconv.AppendInt(buf[:0], -int64(i), 10) }},
}, {
name: "FastInt-Positive",
test: func(b *testing.B) { var buf [32]byte; for i := 0; i < b.N; i++ { __i64toa(&buf[0], int64(i)) }},
}, {
name: "FastInt-Negative",
test: func(b *testing.B) { var buf [32]byte; for i := 0; i < b.N; i++ { __i64toa(&buf[0], -int64(i)) }},
}}
for _, bm := range benchmarks {
b.Run(bm.name, bm.test)
}
}
type utoaBench struct {
name string
num uint64
}
func BenchmarkFastInt_UintToString(b *testing.B) {
maxUint := "18446744073709551615"
benchs := make([]utoaBench, len(maxUint) + 1)
benchs[0].name = "Zero"
benchs[0].num = 0
for i := 1; i <= len(maxUint); i++ {
benchs[i].name = strconv.FormatInt(int64(i), 10) + "-Digs"
benchs[i].num, _ = strconv.ParseUint(string(maxUint[:i]), 10, 64)
}
for _, t := range(benchs) {
benchmarks := []struct {
name string
test func(*testing.B)
}{{
name: "StdLib",
test: func(b *testing.B) { var buf [32]byte; for i := 0; i < b.N; i++ { strconv.AppendUint(buf[:0], t.num, 10) }},
}, {
name: "FastInt",
test: func(b *testing.B) { var buf [32]byte; for i := 0; i < b.N; i++ { __u64toa(&buf[0], t.num) }},
}}
for _, bm := range benchmarks {
name := fmt.Sprintf("%s_%s", bm.name, t.name)
b.Run(name, bm.test)
}
}
}

View file

@ -0,0 +1,133 @@
/*
* Copyright 2021 ByteDance Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package {{PACKAGE}}
import (
`unsafe`
`github.com/bytedance/sonic/internal/native/types`
)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __i64toa(out *byte, val int64) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __u64toa(out *byte, val uint64) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __f64toa(out *byte, val float64) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __f32toa(out *byte, val float32) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __lspace(sp unsafe.Pointer, nb int, off int) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __quote(sp unsafe.Pointer, nb int, dp unsafe.Pointer, dn *int, flags uint64) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __html_escape(sp unsafe.Pointer, nb int, dp unsafe.Pointer, dn *int) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __unquote(sp unsafe.Pointer, nb int, dp unsafe.Pointer, ep *int, flags uint64) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __value(s unsafe.Pointer, n int, p int, v *types.JsonState, flags uint64) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __vstring(s *string, p *int, v *types.JsonState, flags uint64)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __vnumber(s *string, p *int, v *types.JsonState)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __vsigned(s *string, p *int, v *types.JsonState)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __vunsigned(s *string, p *int, v *types.JsonState)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __skip_one(s *string, p *int, m *types.StateMachine, flags uint64) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __skip_one_fast(s *string, p *int) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __skip_array(s *string, p *int, m *types.StateMachine, flags uint64) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __skip_object(s *string, p *int, m *types.StateMachine, flags uint64) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __skip_number(s *string, p *int) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __validate_one(s *string, p *int, m *types.StateMachine) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __get_by_path(s *string, p *int, path *[]interface{}) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __validate_utf8(s *string, p *int, m *types.StateMachine) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __validate_utf8_fast(s *string) (ret int)

View file

@ -0,0 +1,593 @@
/*
* Copyright 2021 ByteDance Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package {{PACKAGE}}
import (
`encoding/hex`
`fmt`
`math`
`testing`
`unsafe`
`github.com/bytedance/sonic/internal/native/types`
`github.com/bytedance/sonic/internal/rt`
`github.com/davecgh/go-spew/spew`
`github.com/stretchr/testify/assert`
`github.com/stretchr/testify/require`
)
func TestNative_Value(t *testing.T) {
var v types.JsonState
s := ` -12345`
p := (*rt.GoString)(unsafe.Pointer(&s))
x := __value(p.Ptr, p.Len, 0, &v, 0)
assert.Equal(t, 9, x)
assert.Equal(t, types.V_INTEGER, v.Vt)
assert.Equal(t, int64(-12345), v.Iv)
assert.Equal(t, 3, v.Ep)
}
func TestNative_Value_OutOfBound(t *testing.T) {
var v types.JsonState
mem := []byte{'"', '"'}
s := rt.Mem2Str(mem[:1])
p := (*rt.GoString)(unsafe.Pointer(&s))
x := __value(p.Ptr, p.Len, 0, &v, 0)
assert.Equal(t, 1, x)
assert.Equal(t, -int(types.ERR_EOF), int(v.Vt))
}
func TestNative_Quote(t *testing.T) {
s := "hello\b\f\n\r\t\\\"\u666fworld"
d := make([]byte, 256)
dp := (*rt.GoSlice)(unsafe.Pointer(&d))
sp := (*rt.GoString)(unsafe.Pointer(&s))
rv := __quote(sp.Ptr, sp.Len, dp.Ptr, &dp.Len, 0)
if rv < 0 {
require.NoError(t, types.ParsingError(-rv))
}
assert.Equal(t, len(s), rv)
assert.Equal(t, 35, len(d))
assert.Equal(t, `hello\u0008\u000c\n\r\t\\\"景world`, string(d))
}
func TestNative_QuoteNoMem(t *testing.T) {
s := "hello\b\f\n\r\t\\\"\u666fworld"
d := make([]byte, 10)
dp := (*rt.GoSlice)(unsafe.Pointer(&d))
sp := (*rt.GoString)(unsafe.Pointer(&s))
rv := __quote(sp.Ptr, sp.Len, dp.Ptr, &dp.Len, 0)
assert.Equal(t, -6, rv)
assert.Equal(t, 5, len(d))
assert.Equal(t, `hello`, string(d))
}
func TestNative_DoubleQuote(t *testing.T) {
s := "hello\b\f\n\r\t\\\"\u666fworld"
d := make([]byte, 256)
dp := (*rt.GoSlice)(unsafe.Pointer(&d))
sp := (*rt.GoString)(unsafe.Pointer(&s))
rv := __quote(sp.Ptr, sp.Len, dp.Ptr, &dp.Len, types.F_DOUBLE_UNQUOTE)
if rv < 0 {
require.NoError(t, types.ParsingError(-rv))
}
assert.Equal(t, len(s), rv)
assert.Equal(t, 44, len(d))
assert.Equal(t, `hello\\u0008\\u000c\\n\\r\\t\\\\\\\"景world`, string(d))
}
func TestNative_Unquote(t *testing.T) {
s := `hello\b\f\n\r\t\\\"\u2333world`
d := make([]byte, 0, len(s))
ep := -1
dp := (*rt.GoSlice)(unsafe.Pointer(&d))
sp := (*rt.GoString)(unsafe.Pointer(&s))
rv := __unquote(sp.Ptr, sp.Len, dp.Ptr, &ep, 0)
if rv < 0 {
require.NoError(t, types.ParsingError(-rv))
}
dp.Len = rv
assert.Equal(t, -1, ep)
assert.Equal(t, "hello\b\f\n\r\t\\\"\u2333world", string(d))
}
func TestNative_UnquoteError(t *testing.T) {
s := `asdf\`
d := make([]byte, 0, len(s))
ep := -1
dp := (*rt.GoSlice)(unsafe.Pointer(&d))
sp := (*rt.GoString)(unsafe.Pointer(&s))
rv := __unquote(sp.Ptr, sp.Len, dp.Ptr, &ep, 0)
assert.Equal(t, -int(types.ERR_EOF), rv)
assert.Equal(t, 5, ep)
s = `asdf\gqwer`
d = make([]byte, 0, len(s))
ep = -1
dp = (*rt.GoSlice)(unsafe.Pointer(&d))
sp = (*rt.GoString)(unsafe.Pointer(&s))
rv = __unquote(sp.Ptr, sp.Len, dp.Ptr, &ep, 0)
assert.Equal(t, -int(types.ERR_INVALID_ESCAPE), rv)
assert.Equal(t, 5, ep)
s = `asdf\u1gggqwer`
d = make([]byte, 0, len(s))
ep = -1
dp = (*rt.GoSlice)(unsafe.Pointer(&d))
sp = (*rt.GoString)(unsafe.Pointer(&s))
rv = __unquote(sp.Ptr, sp.Len, dp.Ptr, &ep, 0)
assert.Equal(t, -int(types.ERR_INVALID_CHAR), rv)
assert.Equal(t, 7, ep)
s = `asdf\ud800qwer`
d = make([]byte, 0, len(s))
ep = -1
dp = (*rt.GoSlice)(unsafe.Pointer(&d))
sp = (*rt.GoString)(unsafe.Pointer(&s))
rv = __unquote(sp.Ptr, sp.Len, dp.Ptr, &ep, 0)
assert.Equal(t, -int(types.ERR_INVALID_UNICODE), rv)
assert.Equal(t, 6, ep)
s = `asdf\\ud800qwer`
d = make([]byte, 0, len(s))
ep = -1
dp = (*rt.GoSlice)(unsafe.Pointer(&d))
sp = (*rt.GoString)(unsafe.Pointer(&s))
rv = __unquote(sp.Ptr, sp.Len, dp.Ptr, &ep, types.F_DOUBLE_UNQUOTE)
assert.Equal(t, -int(types.ERR_INVALID_UNICODE), rv)
assert.Equal(t, 7, ep)
s = `asdf\ud800\ud800qwer`
d = make([]byte, 0, len(s))
ep = -1
dp = (*rt.GoSlice)(unsafe.Pointer(&d))
sp = (*rt.GoString)(unsafe.Pointer(&s))
rv = __unquote(sp.Ptr, sp.Len, dp.Ptr, &ep, 0)
assert.Equal(t, -int(types.ERR_INVALID_UNICODE), rv)
assert.Equal(t, 12, ep)
s = `asdf\\ud800\\ud800qwer`
d = make([]byte, 0, len(s))
ep = -1
dp = (*rt.GoSlice)(unsafe.Pointer(&d))
sp = (*rt.GoString)(unsafe.Pointer(&s))
rv = __unquote(sp.Ptr, sp.Len, dp.Ptr, &ep, types.F_DOUBLE_UNQUOTE)
assert.Equal(t, -int(types.ERR_INVALID_UNICODE), rv)
assert.Equal(t, 14, ep)
}
func TestNative_DoubleUnquote(t *testing.T) {
s := `hello\\b\\f\\n\\r\\t\\\\\\\"\\u2333world`
d := make([]byte, 0, len(s))
ep := -1
dp := (*rt.GoSlice)(unsafe.Pointer(&d))
sp := (*rt.GoString)(unsafe.Pointer(&s))
rv := __unquote(sp.Ptr, sp.Len, dp.Ptr, &ep, types.F_DOUBLE_UNQUOTE)
if rv < 0 {
require.NoError(t, types.ParsingError(-rv))
}
dp.Len = rv
assert.Equal(t, -1, ep)
assert.Equal(t, "hello\b\f\n\r\t\\\"\u2333world", string(d))
}
func TestNative_UnquoteUnicodeReplacement(t *testing.T) {
s := `hello\ud800world`
d := make([]byte, 0, len(s))
ep := -1
dp := (*rt.GoSlice)(unsafe.Pointer(&d))
sp := (*rt.GoString)(unsafe.Pointer(&s))
rv := __unquote(sp.Ptr, sp.Len, dp.Ptr, &ep, types.F_UNICODE_REPLACE)
if rv < 0 {
require.NoError(t, types.ParsingError(-rv))
}
dp.Len = rv
assert.Equal(t, -1, ep)
assert.Equal(t, "hello\ufffdworld", string(d))
s = `hello\ud800\ud800world`
d = make([]byte, 0, len(s))
ep = -1
dp = (*rt.GoSlice)(unsafe.Pointer(&d))
sp = (*rt.GoString)(unsafe.Pointer(&s))
rv = __unquote(sp.Ptr, sp.Len, dp.Ptr, &ep, types.F_UNICODE_REPLACE)
if rv < 0 {
require.NoError(t, types.ParsingError(-rv))
}
dp.Len = rv
assert.Equal(t, -1, ep)
assert.Equal(t, "hello\ufffd\ufffdworld", string(d))
}
func TestNative_HTMLEscape(t *testing.T) {
s := "hello\u2029\u2028<&>world"
d := make([]byte, 256)
dp := (*rt.GoSlice)(unsafe.Pointer(&d))
sp := (*rt.GoString)(unsafe.Pointer(&s))
rv := __html_escape(sp.Ptr, sp.Len, dp.Ptr, &dp.Len)
if rv < 0 {
require.NoError(t, types.ParsingError(-rv))
}
assert.Equal(t, len(s), rv)
assert.Equal(t, 40, len(d))
assert.Equal(t, `hello\u2029\u2028\u003c\u0026\u003eworld`, string(d))
}
func TestNative_HTMLEscapeNoMem(t *testing.T) {
s := "hello\u2029\u2028<&>world"
d := make([]byte, 10)
dp := (*rt.GoSlice)(unsafe.Pointer(&d))
sp := (*rt.GoString)(unsafe.Pointer(&s))
rv := __html_escape(sp.Ptr, sp.Len, dp.Ptr, &dp.Len)
assert.Equal(t, -6, rv)
assert.Equal(t, 5, len(d))
assert.Equal(t, `hello`, string(d))
}
func TestNative_Vstring(t *testing.T) {
var v types.JsonState
i := 0
s := `test"test\n2"`
__vstring(&s, &i, &v, 0)
assert.Equal(t, 5, i)
assert.Equal(t, -1, v.Ep)
assert.Equal(t, int64(0), v.Iv)
__vstring(&s, &i, &v, 0)
assert.Equal(t, 13, i)
assert.Equal(t, 9, v.Ep)
assert.Equal(t, int64(5), v.Iv)
}
func TestNative_Vstring_ValidUnescapedChars(t *testing.T) {
var v types.JsonState
valid := uint64(types.F_VALIDATE_STRING)
i := 0
s := "test\x1f\""
__vstring(&s, &i, &v, valid)
assert.Equal(t, -int(types.ERR_INVALID_CHAR), int(v.Vt))
}
func TestNative_VstringEscapeEOF(t *testing.T) {
var v types.JsonState
i := 0
s := `xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\"xxxxxxxxxxxxxxxxxxxxxxxxxxxxx"x`
__vstring(&s, &i, &v, 0)
assert.Equal(t, 95, i)
assert.Equal(t, 63, v.Ep)
assert.Equal(t, int64(0), v.Iv)
}
func TestNative_VstringHangUpOnRandomData(t *testing.T) {
v, e := hex.DecodeString(
"228dc61efd54ef80a908fb6026b7f2d5f92a257ba8b347c995f259eb8685376a" +
"8c4500262d9c308b3f3ec2577689cf345d9f86f9b5d18d3e463bec5c22df2d2e" +
"4506010eba1dae7278",
)
assert.Nil(t, e)
p := 1
s := rt.Mem2Str(v)
var js types.JsonState
__vstring(&s, &p, &js, 0)
fmt.Printf("js: %s\n", spew.Sdump(js))
}
func TestNative_Vnumber(t *testing.T) {
var v types.JsonState
i := 0
s := "1234"
__vnumber(&s, &i, &v)
assert.Equal(t, 4, i)
assert.Equal(t, 0, v.Ep)
assert.Equal(t, int64(1234), v.Iv)
assert.Equal(t, types.V_INTEGER, v.Vt)
i = 0
s = "1.234"
__vnumber(&s, &i, &v)
assert.Equal(t, 5, i)
assert.Equal(t, 0, v.Ep)
assert.Equal(t, 1.234, v.Dv)
assert.Equal(t, types.V_DOUBLE, v.Vt)
i = 0
s = "1.234e5"
__vnumber(&s, &i, &v)
assert.Equal(t, 7, i)
assert.Equal(t, 0, v.Ep)
assert.Equal(t, 1.234e5, v.Dv)
assert.Equal(t, types.V_DOUBLE, v.Vt)
i = 0
s = "0.0125"
__vnumber(&s, &i, &v)
assert.Equal(t, 6, i)
assert.Equal(t, 0, v.Ep)
assert.Equal(t, 0.0125, v.Dv)
assert.Equal(t, types.V_DOUBLE, v.Vt)
i = 0
s = "100000000000000000000"
__vnumber(&s, &i, &v)
assert.Equal(t, 21, i)
assert.Equal(t, 0, v.Ep)
assert.Equal(t, 100000000000000000000.0, v.Dv)
assert.Equal(t, types.V_DOUBLE, v.Vt)
i = 0
s = "999999999999999900000"
__vnumber(&s, &i, &v)
assert.Equal(t, 21, i)
assert.Equal(t, 0, v.Ep)
assert.Equal(t, 999999999999999900000.0, v.Dv)
assert.Equal(t, types.V_DOUBLE, v.Vt)
i = 0
s = "-1.234"
__vnumber(&s, &i, &v)
assert.Equal(t, 6, i)
assert.Equal(t, 0, v.Ep)
assert.Equal(t, -1.234, v.Dv)
assert.Equal(t, types.V_DOUBLE, v.Vt)
}
func TestNative_Vsigned(t *testing.T) {
var v types.JsonState
i := 0
s := "1234"
__vsigned(&s, &i, &v)
assert.Equal(t, 4, i)
assert.Equal(t, 0, v.Ep)
assert.Equal(t, int64(1234), v.Iv)
assert.Equal(t, types.V_INTEGER, v.Vt)
i = 0
s = "-1234"
__vsigned(&s, &i, &v)
assert.Equal(t, 5, i)
assert.Equal(t, 0, v.Ep)
assert.Equal(t, int64(-1234), v.Iv)
assert.Equal(t, types.V_INTEGER, v.Vt)
i = 0
s = "9223372036854775807"
__vsigned(&s, &i, &v)
assert.Equal(t, 19, i)
assert.Equal(t, 0, v.Ep)
assert.Equal(t, int64(math.MaxInt64), v.Iv)
assert.Equal(t, types.V_INTEGER, v.Vt)
i = 0
s = "-9223372036854775808"
__vsigned(&s, &i, &v)
assert.Equal(t, 20, i)
assert.Equal(t, 0, v.Ep)
assert.Equal(t, int64(math.MinInt64), v.Iv)
assert.Equal(t, types.V_INTEGER, v.Vt)
i = 0
s = "9223372036854775808"
__vsigned(&s, &i, &v)
assert.Equal(t, 18, i)
assert.Equal(t, 0, v.Ep)
assert.Equal(t, types.ValueType(-int(types.ERR_INTEGER_OVERFLOW)), v.Vt)
i = 0
s = "-9223372036854775809"
__vsigned(&s, &i, &v)
assert.Equal(t, 19, i)
assert.Equal(t, 0, v.Ep)
assert.Equal(t, types.ValueType(-int(types.ERR_INTEGER_OVERFLOW)), v.Vt)
i = 0
s = "1.234"
__vsigned(&s, &i, &v)
assert.Equal(t, 1, i)
assert.Equal(t, 0, v.Ep)
assert.Equal(t, types.ValueType(-int(types.ERR_INVALID_NUMBER_FMT)), v.Vt)
i = 0
s = "0.0125"
__vsigned(&s, &i, &v)
assert.Equal(t, 1, i)
assert.Equal(t, 0, v.Ep)
assert.Equal(t, types.ValueType(-int(types.ERR_INVALID_NUMBER_FMT)), v.Vt)
i = 0
s = "-1234e5"
__vsigned(&s, &i, &v)
assert.Equal(t, 5, i)
assert.Equal(t, 0, v.Ep)
assert.Equal(t, types.ValueType(-int(types.ERR_INVALID_NUMBER_FMT)), v.Vt)
i = 0
s = "-1234e-5"
__vsigned(&s, &i, &v)
assert.Equal(t, 5, i)
assert.Equal(t, 0, v.Ep)
assert.Equal(t, types.ValueType(-int(types.ERR_INVALID_NUMBER_FMT)), v.Vt)
}
func TestNative_Vunsigned(t *testing.T) {
var v types.JsonState
i := 0
s := "1234"
__vunsigned(&s, &i, &v)
assert.Equal(t, 4, i)
assert.Equal(t, 0, v.Ep)
assert.Equal(t, int64(1234), v.Iv)
assert.Equal(t, types.V_INTEGER, v.Vt)
i = 0
s = "18446744073709551615"
__vunsigned(&s, &i, &v)
assert.Equal(t, 20, i)
assert.Equal(t, 0, v.Ep)
assert.Equal(t, ^int64(0), v.Iv)
assert.Equal(t, types.V_INTEGER, v.Vt)
i = 0
s = "18446744073709551616"
__vunsigned(&s, &i, &v)
assert.Equal(t, 19, i)
assert.Equal(t, 0, v.Ep)
assert.Equal(t, types.ValueType(-int(types.ERR_INTEGER_OVERFLOW)), v.Vt)
i = 0
s = "-1234"
__vunsigned(&s, &i, &v)
assert.Equal(t, 0, i)
assert.Equal(t, 0, v.Ep)
assert.Equal(t, types.ValueType(-int(types.ERR_INVALID_NUMBER_FMT)), v.Vt)
i = 0
s = "1.234"
__vunsigned(&s, &i, &v)
assert.Equal(t, 1, i)
assert.Equal(t, 0, v.Ep)
assert.Equal(t, types.ValueType(-int(types.ERR_INVALID_NUMBER_FMT)), v.Vt)
i = 0
s = "0.0125"
__vunsigned(&s, &i, &v)
assert.Equal(t, 1, i)
assert.Equal(t, 0, v.Ep)
assert.Equal(t, types.ValueType(-int(types.ERR_INVALID_NUMBER_FMT)), v.Vt)
i = 0
s = "1234e5"
__vunsigned(&s, &i, &v)
assert.Equal(t, 4, i)
assert.Equal(t, 0, v.Ep)
assert.Equal(t, types.ValueType(-int(types.ERR_INVALID_NUMBER_FMT)), v.Vt)
i = 0
s = "-1234e5"
__vunsigned(&s, &i, &v)
assert.Equal(t, 0, i)
assert.Equal(t, 0, v.Ep)
assert.Equal(t, types.ValueType(-int(types.ERR_INVALID_NUMBER_FMT)), v.Vt)
i = 0
s = "-1.234e5"
__vunsigned(&s, &i, &v)
assert.Equal(t, 0, i)
assert.Equal(t, 0, v.Ep)
assert.Equal(t, types.ValueType(-int(types.ERR_INVALID_NUMBER_FMT)), v.Vt)
i = 0
s = "-1.234e-5"
__vunsigned(&s, &i, &v)
assert.Equal(t, 0, i)
assert.Equal(t, 0, v.Ep)
assert.Equal(t, types.ValueType(-int(types.ERR_INVALID_NUMBER_FMT)), v.Vt)
}
func TestNative_SkipOne(t *testing.T) {
p := 0
s := ` {"asdf": [null, true, false, 1, 2.0, -3]}, 1234.5`
q := __skip_one(&s, &p, &types.StateMachine{}, uint64(0))
assert.Equal(t, 42, p)
assert.Equal(t, 1, q)
p = 0
s = `1 2.5 -3 "asdf\nqwer" true false null {} []`
q = __skip_one(&s, &p, &types.StateMachine{}, uint64(0))
assert.Equal(t, 1, p)
assert.Equal(t, 0, q)
q = __skip_one(&s, &p, &types.StateMachine{}, uint64(0))
assert.Equal(t, 5, p)
assert.Equal(t, 2, q)
q = __skip_one(&s, &p, &types.StateMachine{}, uint64(0))
assert.Equal(t, 8, p)
assert.Equal(t, 6, q)
q = __skip_one(&s, &p, &types.StateMachine{}, uint64(0))
assert.Equal(t, 21, p)
assert.Equal(t, 9, q)
q = __skip_one(&s, &p, &types.StateMachine{}, uint64(0))
assert.Equal(t, 26, p)
assert.Equal(t, 22, q)
q = __skip_one(&s, &p, &types.StateMachine{}, uint64(0))
assert.Equal(t, 32, p)
assert.Equal(t, 27, q)
q = __skip_one(&s, &p, &types.StateMachine{}, uint64(0))
assert.Equal(t, 37, p)
assert.Equal(t, 33, q)
q = __skip_one(&s, &p, &types.StateMachine{}, uint64(0))
assert.Equal(t, 40, p)
assert.Equal(t, 38, q)
q = __skip_one(&s, &p, &types.StateMachine{}, uint64(0))
assert.Equal(t, 43, p)
assert.Equal(t, 41, q)
}
func TestNative_SkipOne_Error(t *testing.T) {
for _, s := range([]string{
"-", "+", "0.", "0. ", "+1", "0.0e ", "9e+", "0e-",
"tru", "fals", "nul", "trux", "fals ",
`"asdf`, `"\\\"`,
}) {
p := 0
q := __skip_one(&s, &p, &types.StateMachine{}, uint64(0))
assert.True(t, q < 0)
}
}
func TestNative_SkipArray(t *testing.T) {
p := 0
s := `null, true, false, 1, 2.0, -3, {"asdf": "wqer"}],`
__skip_array(&s, &p, &types.StateMachine{}, uint64(0))
assert.Equal(t, p, 48)
}
func TestNative_SkipObject(t *testing.T) {
p := 0
s := `"asdf": "wqer"},`
__skip_object(&s, &p, &types.StateMachine{}, uint64(0))
assert.Equal(t, p, 15)
}
func TestNative_SkipNumber(t *testing.T) {
p := 0
s := `-1.23e+12`
q := __skip_number(&s, &p)
assert.Equal(t, 9, p)
assert.Equal(t, 0, q)
}
func TestNative_SkipOneFast(t *testing.T) {
p := 0
s := ` {"asdf": [null, true, false, 1, 2.0, -3]}, 1234.5`
q := __skip_one_fast(&s, &p)
assert.Equal(t, 42, p)
assert.Equal(t, 1, q)
p = 0
s = `1, 2.5, -3, "asdf\nqwer", true, false, null, {}, [],`
q = __skip_one_fast(&s, &p)
assert.Equal(t, 1, p)
assert.Equal(t, 0, q)
p += 1
q = __skip_one_fast(&s, &p)
assert.Equal(t, 6, p)
assert.Equal(t, 3, q)
p += 1
q = __skip_one_fast(&s, &p)
assert.Equal(t, 10, p)
assert.Equal(t, 8, q)
p += 1
q = __skip_one_fast(&s, &p)
assert.Equal(t, 24, p)
assert.Equal(t, 12, q)
p += 1
q = __skip_one_fast(&s, &p)
assert.Equal(t, 30, p)
assert.Equal(t, 26, q)
p += 1
q = __skip_one_fast(&s, &p)
assert.Equal(t, 37, p)
assert.Equal(t, 32, q)
p += 1
q = __skip_one_fast(&s, &p)
assert.Equal(t, 43, p)
assert.Equal(t, 39, q)
p += 1
q = __skip_one_fast(&s, &p)
assert.Equal(t, 47, p)
assert.Equal(t, 45, q)
p += 1
q = __skip_one_fast(&s, &p)
assert.Equal(t, 51, p)
assert.Equal(t, 49, q)
}
func TestNative_SkipOneFast_Error(t *testing.T) {
for _, s := range([]string{
"{{", "[{", "{{}",
`"asdf`, `"\\\"`,
}) {
p := 0
q := __skip_one_fast(&s, &p)
assert.True(t, q < 0)
}
}

View file

@ -0,0 +1,47 @@
/*
* Copyright 2021 ByteDance Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package {{PACKAGE}}
var (
S_f64toa = _subr__f64toa
S_f32toa = _subr__f32toa
S_i64toa = _subr__i64toa
S_u64toa = _subr__u64toa
S_lspace = _subr__lspace
)
var (
S_quote = _subr__quote
S_unquote = _subr__unquote
)
var (
S_value = _subr__value
S_vstring = _subr__vstring
S_vnumber = _subr__vnumber
S_vsigned = _subr__vsigned
S_vunsigned = _subr__vunsigned
)
var (
S_skip_one = _subr__skip_one
S_skip_one_fast = _subr__skip_one_fast
S_skip_array = _subr__skip_array
S_skip_object = _subr__skip_object
S_skip_number = _subr__skip_number
S_get_by_path = _subr__get_by_path
)

View file

@ -0,0 +1,135 @@
// Code generated by Makefile, DO NOT EDIT.
/*
* Copyright 2021 ByteDance Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sse
import (
`unsafe`
`github.com/bytedance/sonic/internal/native/types`
)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __i64toa(out *byte, val int64) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __u64toa(out *byte, val uint64) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __f64toa(out *byte, val float64) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __f32toa(out *byte, val float32) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __lspace(sp unsafe.Pointer, nb int, off int) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __quote(sp unsafe.Pointer, nb int, dp unsafe.Pointer, dn *int, flags uint64) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __html_escape(sp unsafe.Pointer, nb int, dp unsafe.Pointer, dn *int) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __unquote(sp unsafe.Pointer, nb int, dp unsafe.Pointer, ep *int, flags uint64) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __value(s unsafe.Pointer, n int, p int, v *types.JsonState, flags uint64) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __vstring(s *string, p *int, v *types.JsonState, flags uint64)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __vnumber(s *string, p *int, v *types.JsonState)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __vsigned(s *string, p *int, v *types.JsonState)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __vunsigned(s *string, p *int, v *types.JsonState)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __skip_one(s *string, p *int, m *types.StateMachine, flags uint64) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __skip_one_fast(s *string, p *int) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __skip_array(s *string, p *int, m *types.StateMachine, flags uint64) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __skip_object(s *string, p *int, m *types.StateMachine, flags uint64) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __skip_number(s *string, p *int) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __validate_one(s *string, p *int, m *types.StateMachine) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __get_by_path(s *string, p *int, path *[]interface{}) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __validate_utf8(s *string, p *int, m *types.StateMachine) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __validate_utf8_fast(s *string) (ret int)

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,49 @@
// Code generated by Makefile, DO NOT EDIT.
/*
* Copyright 2021 ByteDance Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sse
var (
S_f64toa = _subr__f64toa
S_f32toa = _subr__f32toa
S_i64toa = _subr__i64toa
S_u64toa = _subr__u64toa
S_lspace = _subr__lspace
)
var (
S_quote = _subr__quote
S_unquote = _subr__unquote
)
var (
S_value = _subr__value
S_vstring = _subr__vstring
S_vnumber = _subr__vnumber
S_vsigned = _subr__vsigned
S_vunsigned = _subr__vunsigned
)
var (
S_skip_one = _subr__skip_one
S_skip_one_fast = _subr__skip_one_fast
S_skip_array = _subr__skip_array
S_skip_object = _subr__skip_object
S_skip_number = _subr__skip_number
S_get_by_path = _subr__get_by_path
)

View file

@ -0,0 +1,109 @@
// +build !noasm !appengine
// Code generated by asm2asm, DO NOT EDIT.
package sse
//go:nosplit
//go:noescape
//goland:noinspection ALL
func __native_entry__() uintptr
var (
_subr__f32toa = __native_entry__() + 28688
_subr__f64toa = __native_entry__() + 464
_subr__get_by_path = __native_entry__() + 26432
_subr__html_escape = __native_entry__() + 9584
_subr__i64toa = __native_entry__() + 3744
_subr__lspace = __native_entry__() + 80
_subr__quote = __native_entry__() + 5472
_subr__skip_array = __native_entry__() + 19184
_subr__skip_number = __native_entry__() + 22528
_subr__skip_object = __native_entry__() + 21088
_subr__skip_one = __native_entry__() + 22688
_subr__skip_one_fast = __native_entry__() + 22912
_subr__u64toa = __native_entry__() + 4016
_subr__unquote = __native_entry__() + 7184
_subr__validate_one = __native_entry__() + 22736
_subr__validate_utf8 = __native_entry__() + 27456
_subr__validate_utf8_fast = __native_entry__() + 28128
_subr__value = __native_entry__() + 13216
_subr__vnumber = __native_entry__() + 16928
_subr__vsigned = __native_entry__() + 18464
_subr__vstring = __native_entry__() + 15408
_subr__vunsigned = __native_entry__() + 18816
)
const (
_stack__f32toa = 56
_stack__f64toa = 80
_stack__get_by_path = 264
_stack__html_escape = 64
_stack__i64toa = 16
_stack__lspace = 8
_stack__quote = 80
_stack__skip_array = 128
_stack__skip_number = 72
_stack__skip_object = 128
_stack__skip_one = 128
_stack__skip_one_fast = 160
_stack__u64toa = 8
_stack__unquote = 128
_stack__validate_one = 128
_stack__validate_utf8 = 48
_stack__validate_utf8_fast = 24
_stack__value = 368
_stack__vnumber = 280
_stack__vsigned = 16
_stack__vstring = 128
_stack__vunsigned = 24
)
var (
_ = _subr__f32toa
_ = _subr__f64toa
_ = _subr__get_by_path
_ = _subr__html_escape
_ = _subr__i64toa
_ = _subr__lspace
_ = _subr__quote
_ = _subr__skip_array
_ = _subr__skip_number
_ = _subr__skip_object
_ = _subr__skip_one
_ = _subr__skip_one_fast
_ = _subr__u64toa
_ = _subr__unquote
_ = _subr__validate_one
_ = _subr__validate_utf8
_ = _subr__validate_utf8_fast
_ = _subr__value
_ = _subr__vnumber
_ = _subr__vsigned
_ = _subr__vstring
_ = _subr__vunsigned
)
const (
_ = _stack__f32toa
_ = _stack__f64toa
_ = _stack__get_by_path
_ = _stack__html_escape
_ = _stack__i64toa
_ = _stack__lspace
_ = _stack__quote
_ = _stack__skip_array
_ = _stack__skip_number
_ = _stack__skip_object
_ = _stack__skip_one
_ = _stack__skip_one_fast
_ = _stack__u64toa
_ = _stack__unquote
_ = _stack__validate_one
_ = _stack__validate_utf8
_ = _stack__validate_utf8_fast
_ = _stack__value
_ = _stack__vnumber
_ = _stack__vsigned
_ = _stack__vstring
_ = _stack__vunsigned
)

View file

@ -0,0 +1,134 @@
/*
* Copyright 2021 ByteDance Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package types
import (
`fmt`
`sync`
)
type ValueType int
type ParsingError uint
type SearchingError uint
// NOTE: !NOT MODIFIED ONLY.
// This definitions are followed in native/types.h.
const (
V_EOF ValueType = 1
V_NULL ValueType = 2
V_TRUE ValueType = 3
V_FALSE ValueType = 4
V_ARRAY ValueType = 5
V_OBJECT ValueType = 6
V_STRING ValueType = 7
V_DOUBLE ValueType = 8
V_INTEGER ValueType = 9
_ ValueType = 10 // V_KEY_SEP
_ ValueType = 11 // V_ELEM_SEP
_ ValueType = 12 // V_ARRAY_END
_ ValueType = 13 // V_OBJECT_END
V_MAX
)
const (
B_DOUBLE_UNQUOTE = 0
B_UNICODE_REPLACE = 1
B_VALIDATE_STRING = 5
)
const (
F_DOUBLE_UNQUOTE = 1 << B_DOUBLE_UNQUOTE
F_UNICODE_REPLACE = 1 << B_UNICODE_REPLACE
F_VALIDATE_STRING = 1 << B_VALIDATE_STRING
)
const (
MAX_RECURSE = 4096
)
const (
SPACE_MASK = (1 << ' ') | (1 << '\t') | (1 << '\r') | (1 << '\n')
)
const (
ERR_EOF ParsingError = 1
ERR_INVALID_CHAR ParsingError = 2
ERR_INVALID_ESCAPE ParsingError = 3
ERR_INVALID_UNICODE ParsingError = 4
ERR_INTEGER_OVERFLOW ParsingError = 5
ERR_INVALID_NUMBER_FMT ParsingError = 6
ERR_RECURSE_EXCEED_MAX ParsingError = 7
ERR_FLOAT_INFINITY ParsingError = 8
ERR_MISMATCH ParsingError = 9
ERR_INVALID_UTF8 ParsingError = 10
)
var _ParsingErrors = []string{
0 : "ok",
ERR_EOF : "eof",
ERR_INVALID_CHAR : "invalid char",
ERR_INVALID_ESCAPE : "invalid escape char",
ERR_INVALID_UNICODE : "invalid unicode escape",
ERR_INTEGER_OVERFLOW : "integer overflow",
ERR_INVALID_NUMBER_FMT : "invalid number format",
ERR_RECURSE_EXCEED_MAX : "recursion exceeded max depth",
ERR_FLOAT_INFINITY : "float number is infinity",
ERR_MISMATCH : "mismatched type with value",
ERR_INVALID_UTF8 : "invalid UTF8",
}
func (self ParsingError) Error() string {
return "json: error when parsing input: " + self.Message()
}
func (self ParsingError) Message() string {
if int(self) < len(_ParsingErrors) {
return _ParsingErrors[self]
} else {
return fmt.Sprintf("unknown error %d", self)
}
}
type JsonState struct {
Vt ValueType
Dv float64
Iv int64
Ep int
Dbuf *byte
Dcap int
}
type StateMachine struct {
Sp int
Vt [MAX_RECURSE]int
}
var stackPool = sync.Pool{
New: func()interface{}{
return &StateMachine{}
},
}
func NewStateMachine() *StateMachine {
return stackPool.Get().(*StateMachine)
}
func FreeStateMachine(fsm *StateMachine) {
stackPool.Put(fsm)
}

View file

View file

@ -0,0 +1,214 @@
/*
* Copyright 2021 ByteDance Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package resolver
import (
`fmt`
`reflect`
`strings`
`sync`
)
type FieldOpts int
type OffsetType int
const (
F_omitempty FieldOpts = 1 << iota
F_stringize
)
const (
F_offset OffsetType = iota
F_deref
)
type Offset struct {
Size uintptr
Kind OffsetType
Type reflect.Type
}
type FieldMeta struct {
Name string
Path []Offset
Opts FieldOpts
Type reflect.Type
}
func (self *FieldMeta) String() string {
var path []string
var opts []string
/* dump the field path */
for _, off := range self.Path {
if off.Kind == F_offset {
path = append(path, fmt.Sprintf("%d", off.Size))
} else {
path = append(path, fmt.Sprintf("%d.(*%s)", off.Size, off.Type))
}
}
/* check for "string" */
if (self.Opts & F_stringize) != 0 {
opts = append(opts, "string")
}
/* check for "omitempty" */
if (self.Opts & F_omitempty) != 0 {
opts = append(opts, "omitempty")
}
/* format the field */
return fmt.Sprintf(
"{Field \"%s\" @ %s, opts=%s, type=%s}",
self.Name,
strings.Join(path, "."),
strings.Join(opts, ","),
self.Type,
)
}
func (self *FieldMeta) optimize() {
var n int
var v uintptr
/* merge adjacent offsets */
for _, o := range self.Path {
if v += o.Size; o.Kind == F_deref {
self.Path[n].Size = v
self.Path[n].Type, v = o.Type, 0
self.Path[n].Kind, n = F_deref, n + 1
}
}
/* last offset value */
if v != 0 {
self.Path[n].Size = v
self.Path[n].Type = nil
self.Path[n].Kind = F_offset
n++
}
/* must be at least 1 offset */
if n != 0 {
self.Path = self.Path[:n]
} else {
self.Path = []Offset{{Kind: F_offset}}
}
}
func resolveFields(vt reflect.Type) []FieldMeta {
tfv := typeFields(vt)
ret := []FieldMeta(nil)
/* convert each field */
for _, fv := range tfv.list {
item := vt
path := []Offset(nil)
opts := FieldOpts(0)
/* check for "string" */
if fv.quoted {
opts |= F_stringize
}
/* check for "omitempty" */
if fv.omitEmpty {
opts |= F_omitempty
}
/* dump the field path */
for _, i := range fv.index {
kind := F_offset
fval := item.Field(i)
item = fval.Type
/* deref the pointer if needed */
if item.Kind() == reflect.Ptr {
kind = F_deref
item = item.Elem()
}
/* add to path */
path = append(path, Offset {
Kind: kind,
Type: item,
Size: fval.Offset,
})
}
/* get the index to the last offset */
fvt := fv.typ
idx := len(path) - 1
/* do not dereference into fields */
if path[idx].Kind == F_deref {
fvt = reflect.PtrTo(fvt)
path[idx].Kind = F_offset
}
/* add to result */
ret = append(ret, FieldMeta {
Type: fvt,
Opts: opts,
Path: path,
Name: fv.name,
})
}
/* optimize the offsets */
for i := range ret {
ret[i].optimize()
}
/* all done */
return ret
}
var (
fieldLock = sync.RWMutex{}
fieldCache = map[reflect.Type][]FieldMeta{}
)
func ResolveStruct(vt reflect.Type) []FieldMeta {
var ok bool
var fm []FieldMeta
/* attempt to read from cache */
fieldLock.RLock()
fm, ok = fieldCache[vt]
fieldLock.RUnlock()
/* check if it was cached */
if ok {
return fm
}
/* otherwise use write-lock */
fieldLock.Lock()
defer fieldLock.Unlock()
/* double check */
if fm, ok = fieldCache[vt]; ok {
return fm
}
/* resolve the field */
fm = resolveFields(vt)
fieldCache[vt] = fm
return fm
}

View file

@ -0,0 +1,46 @@
/*
* Copyright 2021 ByteDance Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package resolver
import (
_ `encoding/json`
`reflect`
_ `unsafe`
)
type StdField struct {
name string
nameBytes []byte
equalFold func()
nameNonEsc string
nameEscHTML string
tag bool
index []int
typ reflect.Type
omitEmpty bool
quoted bool
encoder func()
}
type StdStructFields struct {
list []StdField
nameIndex map[string]int
}
//go:noescape
//go:linkname typeFields encoding/json.typeFields
func typeFields(_ reflect.Type) StdStructFields

View file

@ -0,0 +1,60 @@
// +build !noasm !appengine
// Code generated by asm2asm, DO NOT EDIT·
#include "go_asm.h"
#include "funcdata.h"
#include "textflag.h"
TEXT ·MoreStack(SB), NOSPLIT, $0 - 8
NO_LOCAL_POINTERS
_entry:
MOVQ (TLS), R14
MOVQ size+0(FP), R12
NOTQ R12
LEAQ (SP)(R12*1), R12
CMPQ R12, 16(R14)
JBE _stack_grow
RET
_stack_grow:
CALL runtime·morestack_noctxt<>(SB)
JMP _entry
TEXT ·StopProf(SB), NOSPLIT, $0-0
NO_LOCAL_POINTERS
CMPB github·combytedancesonicinternalrt·StopProfiling(SB), $0
JEQ _ret_1
MOVL $1, AX
LEAQ github·combytedancesonicinternalrt·yieldCount(SB), CX
LOCK
XADDL AX, (CX)
MOVL runtime·prof+4(SB), AX
TESTL AX, AX
JEQ _ret_1
MOVL AX, github·combytedancesonicinternalrt·oldHz(SB)
MOVL $0, runtime·prof+4(SB)
_ret_1:
RET
TEXT ·StartProf(SB), NOSPLIT, $0-0
NO_LOCAL_POINTERS
CMPB github·combytedancesonicinternalrt·StopProfiling(SB), $0
JEQ _ret_2
MOVL $-1, AX
LEAQ github·combytedancesonicinternalrt·yieldCount(SB), CX
LOCK
XADDL AX, (CX)
CMPL github·combytedancesonicinternalrt·yieldCount(SB), $0
JNE _ret_2
CMPL runtime·prof+4(SB), $0
JNE _ret_2
CMPL github·combytedancesonicinternalrt·oldHz(SB), $0
JNE _branch_1
MOVL $100, github·combytedancesonicinternalrt·oldHz(SB)
_branch_1:
MOVL github·combytedancesonicinternalrt·oldHz(SB), AX
MOVL AX, runtime·prof+4(SB)
_ret_2:
RET

View file

@ -0,0 +1,10 @@
// +build !noasm !appengine
// Code generated by asm2asm, DO NOT EDIT.
#include "go_asm.h"
#include "funcdata.h"
#include "textflag.h"
TEXT ·MoreStack(SB), NOSPLIT, $0 - 8
NO_LOCAL_POINTERS
RET

View file

@ -0,0 +1,113 @@
/*
* Copyright 2021 ByteDance Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package rt
import (
`unsafe`
`reflect`
)
//go:nosplit
func Get16(v []byte) int16 {
return *(*int16)((*GoSlice)(unsafe.Pointer(&v)).Ptr)
}
//go:nosplit
func Get32(v []byte) int32 {
return *(*int32)((*GoSlice)(unsafe.Pointer(&v)).Ptr)
}
//go:nosplit
func Get64(v []byte) int64 {
return *(*int64)((*GoSlice)(unsafe.Pointer(&v)).Ptr)
}
//go:nosplit
func Mem2Str(v []byte) (s string) {
(*GoString)(unsafe.Pointer(&s)).Len = (*GoSlice)(unsafe.Pointer(&v)).Len
(*GoString)(unsafe.Pointer(&s)).Ptr = (*GoSlice)(unsafe.Pointer(&v)).Ptr
return
}
//go:nosplit
func Str2Mem(s string) (v []byte) {
(*GoSlice)(unsafe.Pointer(&v)).Cap = (*GoString)(unsafe.Pointer(&s)).Len
(*GoSlice)(unsafe.Pointer(&v)).Len = (*GoString)(unsafe.Pointer(&s)).Len
(*GoSlice)(unsafe.Pointer(&v)).Ptr = (*GoString)(unsafe.Pointer(&s)).Ptr
return
}
func BytesFrom(p unsafe.Pointer, n int, c int) (r []byte) {
(*GoSlice)(unsafe.Pointer(&r)).Ptr = p
(*GoSlice)(unsafe.Pointer(&r)).Len = n
(*GoSlice)(unsafe.Pointer(&r)).Cap = c
return
}
func FuncAddr(f interface{}) unsafe.Pointer {
if vv := UnpackEface(f); vv.Type.Kind() != reflect.Func {
panic("f is not a function")
} else {
return *(*unsafe.Pointer)(vv.Value)
}
}
func IndexChar(src string, index int) unsafe.Pointer {
return unsafe.Pointer(uintptr((*GoString)(unsafe.Pointer(&src)).Ptr) + uintptr(index))
}
func IndexByte(ptr []byte, index int) unsafe.Pointer {
return unsafe.Pointer(uintptr((*GoSlice)(unsafe.Pointer(&ptr)).Ptr) + uintptr(index))
}
//go:nosplit
func GuardSlice(buf *[]byte, n int) {
c := cap(*buf)
l := len(*buf)
if c-l < n {
c = c>>1 + n + l
if c < 32 {
c = 32
}
tmp := make([]byte, l, c)
copy(tmp, *buf)
*buf = tmp
}
return
}
//go:nosplit
func Ptr2SlicePtr(s unsafe.Pointer, l int, c int) unsafe.Pointer {
slice := &GoSlice{
Ptr: s,
Len: l,
Cap: c,
}
return unsafe.Pointer(slice)
}
//go:nosplit
func StrPtr(s string) unsafe.Pointer {
return (*GoString)(unsafe.Pointer(&s)).Ptr
}
//go:nosplit
func StrFrom(p unsafe.Pointer, n int64) (s string) {
(*GoString)(unsafe.Pointer(&s)).Ptr = p
(*GoString)(unsafe.Pointer(&s)).Len = int(n)
return
}

View file

@ -0,0 +1,200 @@
/*
* Copyright 2021 ByteDance Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package rt
import (
`reflect`
`unsafe`
)
var (
reflectRtypeItab = findReflectRtypeItab()
)
const (
F_direct = 1 << 5
F_kind_mask = (1 << 5) - 1
)
type GoType struct {
Size uintptr
PtrData uintptr
Hash uint32
Flags uint8
Align uint8
FieldAlign uint8
KindFlags uint8
Traits unsafe.Pointer
GCData *byte
Str int32
PtrToSelf int32
}
func (self *GoType) Kind() reflect.Kind {
return reflect.Kind(self.KindFlags & F_kind_mask)
}
func (self *GoType) Pack() (t reflect.Type) {
(*GoIface)(unsafe.Pointer(&t)).Itab = reflectRtypeItab
(*GoIface)(unsafe.Pointer(&t)).Value = unsafe.Pointer(self)
return
}
func (self *GoType) String() string {
return self.Pack().String()
}
func (self *GoType) Indirect() bool {
return self.KindFlags & F_direct == 0
}
type GoMap struct {
Count int
Flags uint8
B uint8
Overflow uint16
Hash0 uint32
Buckets unsafe.Pointer
OldBuckets unsafe.Pointer
Evacuate uintptr
Extra unsafe.Pointer
}
type GoMapIterator struct {
K unsafe.Pointer
V unsafe.Pointer
T *GoMapType
H *GoMap
Buckets unsafe.Pointer
Bptr *unsafe.Pointer
Overflow *[]unsafe.Pointer
OldOverflow *[]unsafe.Pointer
StartBucket uintptr
Offset uint8
Wrapped bool
B uint8
I uint8
Bucket uintptr
CheckBucket uintptr
}
type GoItab struct {
it unsafe.Pointer
Vt *GoType
hv uint32
_ [4]byte
fn [1]uintptr
}
type GoIface struct {
Itab *GoItab
Value unsafe.Pointer
}
type GoEface struct {
Type *GoType
Value unsafe.Pointer
}
func (self GoEface) Pack() (v interface{}) {
*(*GoEface)(unsafe.Pointer(&v)) = self
return
}
type GoPtrType struct {
GoType
Elem *GoType
}
type GoMapType struct {
GoType
Key *GoType
Elem *GoType
Bucket *GoType
Hasher func(unsafe.Pointer, uintptr) uintptr
KeySize uint8
ElemSize uint8
BucketSize uint16
Flags uint32
}
func (self *GoMapType) IndirectElem() bool {
return self.Flags & 2 != 0
}
type GoStructType struct {
GoType
Pkg *byte
Fields []GoStructField
}
type GoStructField struct {
Name *byte
Type *GoType
OffEmbed uintptr
}
type GoInterfaceType struct {
GoType
PkgPath *byte
Methods []GoInterfaceMethod
}
type GoInterfaceMethod struct {
Name int32
Type int32
}
type GoSlice struct {
Ptr unsafe.Pointer
Len int
Cap int
}
type GoString struct {
Ptr unsafe.Pointer
Len int
}
func PtrElem(t *GoType) *GoType {
return (*GoPtrType)(unsafe.Pointer(t)).Elem
}
func MapType(t *GoType) *GoMapType {
return (*GoMapType)(unsafe.Pointer(t))
}
func IfaceType(t *GoType) *GoInterfaceType {
return (*GoInterfaceType)(unsafe.Pointer(t))
}
func UnpackType(t reflect.Type) *GoType {
return (*GoType)((*GoIface)(unsafe.Pointer(&t)).Value)
}
func UnpackEface(v interface{}) GoEface {
return *(*GoEface)(unsafe.Pointer(&v))
}
func UnpackIface(v interface{}) GoIface {
return *(*GoIface)(unsafe.Pointer(&v))
}
func findReflectRtypeItab() *GoItab {
v := reflect.TypeOf(struct{}{})
return (*GoIface)(unsafe.Pointer(&v)).Itab
}

124
vendor/github.com/bytedance/sonic/internal/rt/gcwb.go generated vendored Normal file
View file

@ -0,0 +1,124 @@
/*
* Copyright 2021 ByteDance Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package rt
import (
`os`
`sync/atomic`
`unsafe`
`golang.org/x/arch/x86/x86asm`
)
const (
_MaxInstr = 15
)
func isvar(arg x86asm.Arg) bool {
v, ok := arg.(x86asm.Mem)
return ok && v.Base == x86asm.RIP
}
func iszero(arg x86asm.Arg) bool {
v, ok := arg.(x86asm.Imm)
return ok && v == 0
}
func GcwbAddr() uintptr {
var err error
var off uintptr
var ins x86asm.Inst
/* get the function address */
pc := uintptr(0)
fp := FuncAddr(atomic.StorePointer)
/* search within the first 16 instructions */
for i := 0; i < 16; i++ {
mem := unsafe.Pointer(uintptr(fp) + pc)
buf := BytesFrom(mem, _MaxInstr, _MaxInstr)
/* disassemble the instruction */
if ins, err = x86asm.Decode(buf, 64); err != nil {
panic("gcwbaddr: " + err.Error())
}
/* check for a byte comparison with zero */
if ins.Op == x86asm.CMP && ins.MemBytes == 1 && isvar(ins.Args[0]) && iszero(ins.Args[1]) {
off = pc + uintptr(ins.Len) + uintptr(ins.Args[0].(x86asm.Mem).Disp)
break
}
/* move to next instruction */
nb := ins.Len
pc += uintptr(nb)
}
/* check for address */
if off == 0 {
panic("gcwbaddr: could not locate the variable `writeBarrier`")
} else {
return uintptr(fp) + off
}
}
// StopProfiling is used to stop traceback introduced by SIGPROF while native code is running.
// WARN: this option is only a workaround for traceback issue (https://github.com/bytedance/sonic/issues/310),
// and will be dropped when the issue is fixed.
var StopProfiling = os.Getenv("SONIC_STOP_PROFILING") != ""
// WARN: must be aligned with runtime.Prof
// type Prof struct {
// signalLock uint32
// hz int32
// }
var (
// // go:linkname runtimeProf runtime.prof
// runtimeProf Prof
// count of native-C calls
yieldCount uint32
// previous value of runtimeProf.hz
oldHz int32
)
//go:nosplit
func MoreStack(size uintptr)
func StopProf()
// func StopProf() {
// atomic.AddUint32(&yieldCount, 1)
// if runtimeProf.hz != 0 {
// oldHz = runtimeProf.hz
// runtimeProf.hz = 0
// }
// }
func StartProf()
// func StartProf() {
// atomic.AddUint32(&yieldCount, ^uint32(0))
// if yieldCount == 0 && runtimeProf.hz == 0 {
// if oldHz == 0 {
// oldHz = 100
// }
// runtimeProf.hz = oldHz
// }
// }

36
vendor/github.com/bytedance/sonic/internal/rt/int48.go generated vendored Normal file
View file

@ -0,0 +1,36 @@
/*
* Copyright 2021 ByteDance Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package rt
const (
MinInt48 = -(1 << 47)
MaxInt48 = +(1 << 47) - 1
)
func PackInt(v int) uint64 {
if u := uint64(v); v < MinInt48 || v > MaxInt48 {
panic("int48 out of range")
} else {
return ((u >> 63) << 47) | (u & 0x00007fffffffffff)
}
}
func UnpackInt(v uint64) int {
v &= 0x0000ffffffffffff
v |= (v >> 47) * (0xffff << 48)
return int(v)
}

View file

@ -0,0 +1,180 @@
/**
* Copyright 2023 ByteDance Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package rt
import (
`fmt`
`strings`
`unsafe`
)
type Bitmap struct {
N int
B []byte
}
func (self *Bitmap) grow() {
if self.N >= len(self.B) * 8 {
self.B = append(self.B, 0)
}
}
func (self *Bitmap) mark(i int, bv int) {
if bv != 0 {
self.B[i / 8] |= 1 << (i % 8)
} else {
self.B[i / 8] &^= 1 << (i % 8)
}
}
func (self *Bitmap) Set(i int, bv int) {
if i >= self.N {
panic("bitmap: invalid bit position")
} else {
self.mark(i, bv)
}
}
func (self *Bitmap) Append(bv int) {
self.grow()
self.mark(self.N, bv)
self.N++
}
func (self *Bitmap) AppendMany(n int, bv int) {
for i := 0; i < n; i++ {
self.Append(bv)
}
}
// var (
// _stackMapLock = sync.Mutex{}
// _stackMapCache = make(map[*StackMap]struct{})
// )
type BitVec struct {
N uintptr
B unsafe.Pointer
}
func (self BitVec) Bit(i uintptr) byte {
return (*(*byte)(unsafe.Pointer(uintptr(self.B) + i / 8)) >> (i % 8)) & 1
}
func (self BitVec) String() string {
var i uintptr
var v []string
/* add each bit */
for i = 0; i < self.N; i++ {
v = append(v, fmt.Sprintf("%d", self.Bit(i)))
}
/* join them together */
return fmt.Sprintf(
"BitVec { %s }",
strings.Join(v, ", "),
)
}
type StackMap struct {
N int32
L int32
B [1]byte
}
// func (self *StackMap) add() {
// _stackMapLock.Lock()
// _stackMapCache[self] = struct{}{}
// _stackMapLock.Unlock()
// }
func (self *StackMap) Pin() uintptr {
// self.add()
return uintptr(unsafe.Pointer(self))
}
func (self *StackMap) Get(i int32) BitVec {
return BitVec {
N: uintptr(self.L),
B: unsafe.Pointer(uintptr(unsafe.Pointer(&self.B)) + uintptr(i * ((self.L + 7) >> 3))),
}
}
func (self *StackMap) String() string {
sb := strings.Builder{}
sb.WriteString("StackMap {")
/* dump every stack map */
for i := int32(0); i < self.N; i++ {
sb.WriteRune('\n')
sb.WriteString(" " + self.Get(i).String())
}
/* close the stackmap */
sb.WriteString("\n}")
return sb.String()
}
func (self *StackMap) MarshalBinary() ([]byte, error) {
size := int(self.N) * int(self.L) + int(unsafe.Sizeof(self.L)) + int(unsafe.Sizeof(self.N))
return BytesFrom(unsafe.Pointer(self), size, size), nil
}
var (
byteType = UnpackEface(byte(0)).Type
)
const (
_StackMapSize = unsafe.Sizeof(StackMap{})
)
//go:linkname mallocgc runtime.mallocgc
//goland:noinspection GoUnusedParameter
func mallocgc(nb uintptr, vt *GoType, zero bool) unsafe.Pointer
type StackMapBuilder struct {
b Bitmap
}
func (self *StackMapBuilder) Build() (p *StackMap) {
nb := len(self.b.B)
bm := mallocgc(_StackMapSize + uintptr(nb) - 1, byteType, false)
/* initialize as 1 bitmap of N bits */
p = (*StackMap)(bm)
p.N, p.L = 1, int32(self.b.N)
copy(BytesFrom(unsafe.Pointer(&p.B), nb, nb), self.b.B)
return
}
func (self *StackMapBuilder) AddField(ptr bool) {
if ptr {
self.b.Append(1)
} else {
self.b.Append(0)
}
}
func (self *StackMapBuilder) AddFields(n int, ptr bool) {
if ptr {
self.b.AppendMany(n, 1)
} else {
self.b.AppendMany(n, 0)
}
}