实现基础web服务器
This commit is contained in:
0
vendor/github.com/bytedance/sonic/internal/caching/asm.s
generated
vendored
Normal file
0
vendor/github.com/bytedance/sonic/internal/caching/asm.s
generated
vendored
Normal file
115
vendor/github.com/bytedance/sonic/internal/caching/fcache.go
generated
vendored
Normal file
115
vendor/github.com/bytedance/sonic/internal/caching/fcache.go
generated
vendored
Normal 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
|
||||
}
|
||||
}
|
||||
40
vendor/github.com/bytedance/sonic/internal/caching/hashing.go
generated
vendored
Normal file
40
vendor/github.com/bytedance/sonic/internal/caching/hashing.go
generated
vendored
Normal 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)
|
||||
}
|
||||
}
|
||||
173
vendor/github.com/bytedance/sonic/internal/caching/pcache.go
generated
vendored
Normal file
173
vendor/github.com/bytedance/sonic/internal/caching/pcache.go
generated
vendored
Normal 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
|
||||
}
|
||||
40
vendor/github.com/bytedance/sonic/internal/cpu/features.go
generated
vendored
Normal file
40
vendor/github.com/bytedance/sonic/internal/cpu/features.go
generated
vendored
Normal 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))
|
||||
}
|
||||
}
|
||||
0
vendor/github.com/bytedance/sonic/internal/decoder/asm.s
generated
vendored
Normal file
0
vendor/github.com/bytedance/sonic/internal/decoder/asm.s
generated
vendored
Normal file
2013
vendor/github.com/bytedance/sonic/internal/decoder/assembler_amd64_go116.go
generated
vendored
Normal file
2013
vendor/github.com/bytedance/sonic/internal/decoder/assembler_amd64_go116.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1992
vendor/github.com/bytedance/sonic/internal/decoder/assembler_amd64_go117.go
generated
vendored
Normal file
1992
vendor/github.com/bytedance/sonic/internal/decoder/assembler_amd64_go117.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1155
vendor/github.com/bytedance/sonic/internal/decoder/compiler.go
generated
vendored
Normal file
1155
vendor/github.com/bytedance/sonic/internal/decoder/compiler.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
70
vendor/github.com/bytedance/sonic/internal/decoder/debug.go
generated
vendored
Normal file
70
vendor/github.com/bytedance/sonic/internal/decoder/debug.go
generated
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* 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 decoder
|
||||
|
||||
import (
|
||||
`os`
|
||||
`runtime`
|
||||
`runtime/debug`
|
||||
`strings`
|
||||
|
||||
`github.com/bytedance/sonic/internal/jit`
|
||||
)
|
||||
|
||||
|
||||
var (
|
||||
debugSyncGC = os.Getenv("SONIC_SYNC_GC") != ""
|
||||
debugAsyncGC = os.Getenv("SONIC_NO_ASYNC_GC") == ""
|
||||
)
|
||||
|
||||
var (
|
||||
_Instr_End _Instr = newInsOp(_OP_nil_1)
|
||||
|
||||
_F_gc = jit.Func(runtime.GC)
|
||||
_F_force_gc = jit.Func(debug.FreeOSMemory)
|
||||
_F_println = jit.Func(println_wrapper)
|
||||
_F_print = jit.Func(print)
|
||||
)
|
||||
|
||||
func println_wrapper(i int, op1 int, op2 int){
|
||||
println(i, " Intrs ", op1, _OpNames[op1], "next: ", op2, _OpNames[op2])
|
||||
}
|
||||
|
||||
func print(i int){
|
||||
println(i)
|
||||
}
|
||||
|
||||
func (self *_Assembler) force_gc() {
|
||||
self.call_go(_F_gc)
|
||||
self.call_go(_F_force_gc)
|
||||
}
|
||||
|
||||
func (self *_Assembler) debug_instr(i int, v *_Instr) {
|
||||
if debugSyncGC {
|
||||
if (i+1 == len(self.p)) {
|
||||
self.print_gc(i, v, &_Instr_End)
|
||||
} else {
|
||||
next := &(self.p[i+1])
|
||||
self.print_gc(i, v, next)
|
||||
name := _OpNames[next.op()]
|
||||
if strings.Contains(name, "save") {
|
||||
return
|
||||
}
|
||||
}
|
||||
self.force_gc()
|
||||
}
|
||||
}
|
||||
255
vendor/github.com/bytedance/sonic/internal/decoder/decoder.go
generated
vendored
Normal file
255
vendor/github.com/bytedance/sonic/internal/decoder/decoder.go
generated
vendored
Normal file
@@ -0,0 +1,255 @@
|
||||
/*
|
||||
* 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 decoder
|
||||
|
||||
import (
|
||||
`unsafe`
|
||||
`encoding/json`
|
||||
`reflect`
|
||||
`runtime`
|
||||
|
||||
`github.com/bytedance/sonic/internal/native`
|
||||
`github.com/bytedance/sonic/internal/native/types`
|
||||
`github.com/bytedance/sonic/internal/rt`
|
||||
`github.com/bytedance/sonic/option`
|
||||
`github.com/bytedance/sonic/utf8`
|
||||
)
|
||||
|
||||
const (
|
||||
_F_use_int64 = iota
|
||||
_F_use_number
|
||||
_F_disable_urc
|
||||
_F_disable_unknown
|
||||
_F_copy_string
|
||||
_F_validate_string
|
||||
|
||||
_F_allow_control = 31
|
||||
)
|
||||
|
||||
type Options uint64
|
||||
|
||||
const (
|
||||
OptionUseInt64 Options = 1 << _F_use_int64
|
||||
OptionUseNumber Options = 1 << _F_use_number
|
||||
OptionUseUnicodeErrors Options = 1 << _F_disable_urc
|
||||
OptionDisableUnknown Options = 1 << _F_disable_unknown
|
||||
OptionCopyString Options = 1 << _F_copy_string
|
||||
OptionValidateString Options = 1 << _F_validate_string
|
||||
)
|
||||
|
||||
func (self *Decoder) SetOptions(opts Options) {
|
||||
if (opts & OptionUseNumber != 0) && (opts & OptionUseInt64 != 0) {
|
||||
panic("can't set OptionUseInt64 and OptionUseNumber both!")
|
||||
}
|
||||
self.f = uint64(opts)
|
||||
}
|
||||
|
||||
|
||||
// Decoder is the decoder context object
|
||||
type Decoder struct {
|
||||
i int
|
||||
f uint64
|
||||
s string
|
||||
}
|
||||
|
||||
// NewDecoder creates a new decoder instance.
|
||||
func NewDecoder(s string) *Decoder {
|
||||
return &Decoder{s: s}
|
||||
}
|
||||
|
||||
// Pos returns the current decoding position.
|
||||
func (self *Decoder) Pos() int {
|
||||
return self.i
|
||||
}
|
||||
|
||||
func (self *Decoder) Reset(s string) {
|
||||
self.s = s
|
||||
self.i = 0
|
||||
// self.f = 0
|
||||
}
|
||||
|
||||
func (self *Decoder) CheckTrailings() error {
|
||||
pos := self.i
|
||||
buf := self.s
|
||||
/* skip all the trailing spaces */
|
||||
if pos != len(buf) {
|
||||
for pos < len(buf) && (types.SPACE_MASK & (1 << buf[pos])) != 0 {
|
||||
pos++
|
||||
}
|
||||
}
|
||||
|
||||
/* then it must be at EOF */
|
||||
if pos == len(buf) {
|
||||
return nil
|
||||
}
|
||||
|
||||
/* junk after JSON value */
|
||||
return SyntaxError {
|
||||
Src : buf,
|
||||
Pos : pos,
|
||||
Code : types.ERR_INVALID_CHAR,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Decode parses the JSON-encoded data from current position and stores the result
|
||||
// in the value pointed to by val.
|
||||
func (self *Decoder) Decode(val interface{}) error {
|
||||
/* validate json if needed */
|
||||
if (self.f & (1 << _F_validate_string)) != 0 && !utf8.ValidateString(self.s){
|
||||
dbuf := utf8.CorrectWith(nil, rt.Str2Mem(self.s), "\ufffd")
|
||||
self.s = rt.Mem2Str(dbuf)
|
||||
}
|
||||
|
||||
vv := rt.UnpackEface(val)
|
||||
vp := vv.Value
|
||||
|
||||
/* check for nil type */
|
||||
if vv.Type == nil {
|
||||
return &json.InvalidUnmarshalError{}
|
||||
}
|
||||
|
||||
/* must be a non-nil pointer */
|
||||
if vp == nil || vv.Type.Kind() != reflect.Ptr {
|
||||
return &json.InvalidUnmarshalError{Type: vv.Type.Pack()}
|
||||
}
|
||||
|
||||
etp := rt.PtrElem(vv.Type)
|
||||
|
||||
/* check the defined pointer type for issue 379 */
|
||||
if vv.Type.IsNamed() {
|
||||
newp := vp
|
||||
etp = vv.Type
|
||||
vp = unsafe.Pointer(&newp)
|
||||
}
|
||||
|
||||
/* create a new stack, and call the decoder */
|
||||
sb := newStack()
|
||||
nb, err := decodeTypedPointer(self.s, self.i, etp, vp, sb, self.f)
|
||||
/* return the stack back */
|
||||
self.i = nb
|
||||
freeStack(sb)
|
||||
|
||||
/* avoid GC ahead */
|
||||
runtime.KeepAlive(vv)
|
||||
return err
|
||||
}
|
||||
|
||||
// UseInt64 indicates the Decoder to unmarshal an integer into an interface{} as an
|
||||
// int64 instead of as a float64.
|
||||
func (self *Decoder) UseInt64() {
|
||||
self.f |= 1 << _F_use_int64
|
||||
self.f &^= 1 << _F_use_number
|
||||
}
|
||||
|
||||
// UseNumber indicates the Decoder to unmarshal a number into an interface{} as a
|
||||
// json.Number instead of as a float64.
|
||||
func (self *Decoder) UseNumber() {
|
||||
self.f &^= 1 << _F_use_int64
|
||||
self.f |= 1 << _F_use_number
|
||||
}
|
||||
|
||||
// UseUnicodeErrors indicates the Decoder to return an error when encounter invalid
|
||||
// UTF-8 escape sequences.
|
||||
func (self *Decoder) UseUnicodeErrors() {
|
||||
self.f |= 1 << _F_disable_urc
|
||||
}
|
||||
|
||||
// DisallowUnknownFields indicates the Decoder to return an error when the destination
|
||||
// is a struct and the input contains object keys which do not match any
|
||||
// non-ignored, exported fields in the destination.
|
||||
func (self *Decoder) DisallowUnknownFields() {
|
||||
self.f |= 1 << _F_disable_unknown
|
||||
}
|
||||
|
||||
// CopyString indicates the Decoder to decode string values by copying instead of referring.
|
||||
func (self *Decoder) CopyString() {
|
||||
self.f |= 1 << _F_copy_string
|
||||
}
|
||||
|
||||
// ValidateString causes the Decoder to validate string values when decoding string value
|
||||
// in JSON. Validation is that, returning error when unescaped control chars(0x00-0x1f) or
|
||||
// invalid UTF-8 chars in the string value of JSON.
|
||||
func (self *Decoder) ValidateString() {
|
||||
self.f |= 1 << _F_validate_string
|
||||
}
|
||||
|
||||
// Pretouch compiles vt ahead-of-time to avoid JIT compilation on-the-fly, in
|
||||
// order to reduce the first-hit latency.
|
||||
//
|
||||
// Opts are the compile options, for example, "option.WithCompileRecursiveDepth" is
|
||||
// a compile option to set the depth of recursive compile for the nested struct type.
|
||||
func Pretouch(vt reflect.Type, opts ...option.CompileOption) error {
|
||||
cfg := option.DefaultCompileOptions()
|
||||
for _, opt := range opts {
|
||||
opt(&cfg)
|
||||
}
|
||||
return pretouchRec(map[reflect.Type]bool{vt:true}, cfg)
|
||||
}
|
||||
|
||||
func pretouchType(_vt reflect.Type, opts option.CompileOptions) (map[reflect.Type]bool, error) {
|
||||
/* compile function */
|
||||
compiler := newCompiler().apply(opts)
|
||||
decoder := func(vt *rt.GoType, _ ...interface{}) (interface{}, error) {
|
||||
if pp, err := compiler.compile(_vt); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
as := newAssembler(pp)
|
||||
as.name = _vt.String()
|
||||
return as.Load(), nil
|
||||
}
|
||||
}
|
||||
|
||||
/* find or compile */
|
||||
vt := rt.UnpackType(_vt)
|
||||
if val := programCache.Get(vt); val != nil {
|
||||
return nil, nil
|
||||
} else if _, err := programCache.Compute(vt, decoder); err == nil {
|
||||
return compiler.rec, nil
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
func pretouchRec(vtm map[reflect.Type]bool, opts option.CompileOptions) error {
|
||||
if opts.RecursiveDepth < 0 || len(vtm) == 0 {
|
||||
return nil
|
||||
}
|
||||
next := make(map[reflect.Type]bool)
|
||||
for vt := range(vtm) {
|
||||
sub, err := pretouchType(vt, opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for svt := range(sub) {
|
||||
next[svt] = true
|
||||
}
|
||||
}
|
||||
opts.RecursiveDepth -= 1
|
||||
return pretouchRec(next, opts)
|
||||
}
|
||||
|
||||
// Skip skips only one json value, and returns first non-blank character position and its ending position if it is valid.
|
||||
// Otherwise, returns negative error code using start and invalid character position using end
|
||||
func Skip(data []byte) (start int, end int) {
|
||||
s := rt.Mem2Str(data)
|
||||
p := 0
|
||||
m := types.NewStateMachine()
|
||||
ret := native.SkipOne(&s, &p, m, uint64(0))
|
||||
types.FreeStateMachine(m)
|
||||
return ret, p
|
||||
}
|
||||
181
vendor/github.com/bytedance/sonic/internal/decoder/errors.go
generated
vendored
Normal file
181
vendor/github.com/bytedance/sonic/internal/decoder/errors.go
generated
vendored
Normal file
@@ -0,0 +1,181 @@
|
||||
/*
|
||||
* 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 decoder
|
||||
|
||||
import (
|
||||
`encoding/json`
|
||||
`errors`
|
||||
`fmt`
|
||||
`reflect`
|
||||
`strconv`
|
||||
`strings`
|
||||
|
||||
`github.com/bytedance/sonic/internal/native/types`
|
||||
`github.com/bytedance/sonic/internal/rt`
|
||||
)
|
||||
|
||||
type SyntaxError struct {
|
||||
Pos int
|
||||
Src string
|
||||
Code types.ParsingError
|
||||
Msg string
|
||||
}
|
||||
|
||||
func (self SyntaxError) Error() string {
|
||||
return fmt.Sprintf("%q", self.Description())
|
||||
}
|
||||
|
||||
func (self SyntaxError) Description() string {
|
||||
return "Syntax error " + self.description()
|
||||
}
|
||||
|
||||
func (self SyntaxError) description() string {
|
||||
i := 16
|
||||
p := self.Pos - i
|
||||
q := self.Pos + i
|
||||
|
||||
/* check for empty source */
|
||||
if self.Src == "" {
|
||||
return fmt.Sprintf("no sources available: %#v", self)
|
||||
}
|
||||
|
||||
/* prevent slicing before the beginning */
|
||||
if p < 0 {
|
||||
p, q, i = 0, q - p, i + p
|
||||
}
|
||||
|
||||
/* prevent slicing beyond the end */
|
||||
if n := len(self.Src); q > n {
|
||||
n = q - n
|
||||
q = len(self.Src)
|
||||
|
||||
/* move the left bound if possible */
|
||||
if p > n {
|
||||
i += n
|
||||
p -= n
|
||||
}
|
||||
}
|
||||
|
||||
/* left and right length */
|
||||
x := clamp_zero(i)
|
||||
y := clamp_zero(q - p - i - 1)
|
||||
|
||||
/* compose the error description */
|
||||
return fmt.Sprintf(
|
||||
"at index %d: %s\n\n\t%s\n\t%s^%s\n",
|
||||
self.Pos,
|
||||
self.Message(),
|
||||
self.Src[p:q],
|
||||
strings.Repeat(".", x),
|
||||
strings.Repeat(".", y),
|
||||
)
|
||||
}
|
||||
|
||||
func (self SyntaxError) Message() string {
|
||||
if self.Msg == "" {
|
||||
return self.Code.Message()
|
||||
}
|
||||
return self.Msg
|
||||
}
|
||||
|
||||
func clamp_zero(v int) int {
|
||||
if v < 0 {
|
||||
return 0
|
||||
} else {
|
||||
return v
|
||||
}
|
||||
}
|
||||
|
||||
/** JIT Error Helpers **/
|
||||
|
||||
var stackOverflow = &json.UnsupportedValueError {
|
||||
Str : "Value nesting too deep",
|
||||
Value : reflect.ValueOf("..."),
|
||||
}
|
||||
|
||||
//go:nosplit
|
||||
func error_wrap(src string, pos int, code types.ParsingError) error {
|
||||
return SyntaxError {
|
||||
Pos : pos,
|
||||
Src : src,
|
||||
Code : code,
|
||||
}
|
||||
}
|
||||
|
||||
//go:nosplit
|
||||
func error_type(vt *rt.GoType) error {
|
||||
return &json.UnmarshalTypeError{Type: vt.Pack()}
|
||||
}
|
||||
|
||||
type MismatchTypeError struct {
|
||||
Pos int
|
||||
Src string
|
||||
Type reflect.Type
|
||||
}
|
||||
|
||||
func swithchJSONType (src string, pos int) string {
|
||||
var val string
|
||||
switch src[pos] {
|
||||
case 'f': fallthrough
|
||||
case 't': val = "bool"
|
||||
case '"': val = "string"
|
||||
case '{': val = "object"
|
||||
case '[': val = "array"
|
||||
case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': val = "number"
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
func (self MismatchTypeError) Error() string {
|
||||
se := SyntaxError {
|
||||
Pos : self.Pos,
|
||||
Src : self.Src,
|
||||
Code : types.ERR_MISMATCH,
|
||||
}
|
||||
return fmt.Sprintf("Mismatch type %s with value %s %q", self.Type.String(), swithchJSONType(self.Src, self.Pos), se.description())
|
||||
}
|
||||
|
||||
func (self MismatchTypeError) Description() string {
|
||||
se := SyntaxError {
|
||||
Pos : self.Pos,
|
||||
Src : self.Src,
|
||||
Code : types.ERR_MISMATCH,
|
||||
}
|
||||
return fmt.Sprintf("Mismatch type %s with value %s %s", self.Type.String(), swithchJSONType(self.Src, self.Pos), se.description())
|
||||
}
|
||||
|
||||
//go:nosplit
|
||||
func error_mismatch(src string, pos int, vt *rt.GoType) error {
|
||||
return &MismatchTypeError {
|
||||
Pos : pos,
|
||||
Src : src,
|
||||
Type : vt.Pack(),
|
||||
}
|
||||
}
|
||||
|
||||
//go:nosplit
|
||||
func error_field(name string) error {
|
||||
return errors.New("json: unknown field " + strconv.Quote(name))
|
||||
}
|
||||
|
||||
//go:nosplit
|
||||
func error_value(value string, vtype reflect.Type) error {
|
||||
return &json.UnmarshalTypeError {
|
||||
Type : vtype,
|
||||
Value : value,
|
||||
}
|
||||
}
|
||||
776
vendor/github.com/bytedance/sonic/internal/decoder/generic_amd64_go116.go
generated
vendored
Normal file
776
vendor/github.com/bytedance/sonic/internal/decoder/generic_amd64_go116.go
generated
vendored
Normal file
@@ -0,0 +1,776 @@
|
||||
// +build go1.15,!go1.17
|
||||
|
||||
/*
|
||||
* 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 decoder
|
||||
|
||||
import (
|
||||
`encoding/json`
|
||||
`fmt`
|
||||
`reflect`
|
||||
`strconv`
|
||||
|
||||
`github.com/bytedance/sonic/internal/jit`
|
||||
`github.com/bytedance/sonic/internal/native`
|
||||
`github.com/bytedance/sonic/internal/native/types`
|
||||
`github.com/twitchyliquid64/golang-asm/obj`
|
||||
`github.com/twitchyliquid64/golang-asm/obj/x86`
|
||||
)
|
||||
|
||||
/** Crucial Registers:
|
||||
*
|
||||
* ST(BX) : ro, decoder stack
|
||||
* DF(R10) : ro, decoder flags
|
||||
* EP(R11) : wo, error pointer
|
||||
* IP(R12) : ro, input pointer
|
||||
* IL(R13) : ro, input length
|
||||
* IC(R14) : rw, input cursor
|
||||
* VP(R15) : ro, value pointer (to an interface{})
|
||||
*/
|
||||
|
||||
const (
|
||||
_VD_args = 8 // 8 bytes for passing arguments to this functions
|
||||
_VD_fargs = 64 // 64 bytes for passing arguments to other Go functions
|
||||
_VD_saves = 40 // 40 bytes for saving the registers before CALL instructions
|
||||
_VD_locals = 88 // 88 bytes for local variables
|
||||
)
|
||||
|
||||
const (
|
||||
_VD_offs = _VD_fargs + _VD_saves + _VD_locals
|
||||
_VD_size = _VD_offs + 8 // 8 bytes for the parent frame pointer
|
||||
)
|
||||
|
||||
var (
|
||||
_VAR_ss = _VAR_ss_Vt
|
||||
_VAR_df = jit.Ptr(_SP, _VD_fargs + _VD_saves)
|
||||
)
|
||||
|
||||
var (
|
||||
_VAR_ss_Vt = jit.Ptr(_SP, _VD_fargs + _VD_saves + 8)
|
||||
_VAR_ss_Dv = jit.Ptr(_SP, _VD_fargs + _VD_saves + 16)
|
||||
_VAR_ss_Iv = jit.Ptr(_SP, _VD_fargs + _VD_saves + 24)
|
||||
_VAR_ss_Ep = jit.Ptr(_SP, _VD_fargs + _VD_saves + 32)
|
||||
_VAR_ss_Db = jit.Ptr(_SP, _VD_fargs + _VD_saves + 40)
|
||||
_VAR_ss_Dc = jit.Ptr(_SP, _VD_fargs + _VD_saves + 48)
|
||||
)
|
||||
|
||||
var (
|
||||
_VAR_cs_LR = jit.Ptr(_SP, _VD_fargs + _VD_saves + 56)
|
||||
_VAR_cs_p = jit.Ptr(_SP, _VD_fargs + _VD_saves + 64)
|
||||
_VAR_cs_n = jit.Ptr(_SP, _VD_fargs + _VD_saves + 72)
|
||||
_VAR_cs_d = jit.Ptr(_SP, _VD_fargs + _VD_saves + 80)
|
||||
)
|
||||
|
||||
type _ValueDecoder struct {
|
||||
jit.BaseAssembler
|
||||
}
|
||||
|
||||
func (self *_ValueDecoder) build() uintptr {
|
||||
self.Init(self.compile)
|
||||
return *(*uintptr)(self.Load("decode_value", _VD_size, _VD_args, argPtrs_generic, localPtrs_generic))
|
||||
}
|
||||
|
||||
/** Function Calling Helpers **/
|
||||
|
||||
func (self *_ValueDecoder) save(r ...obj.Addr) {
|
||||
for i, v := range r {
|
||||
if i > _VD_saves / 8 - 1 {
|
||||
panic("too many registers to save")
|
||||
} else {
|
||||
self.Emit("MOVQ", v, jit.Ptr(_SP, _VD_fargs + int64(i) * 8))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (self *_ValueDecoder) load(r ...obj.Addr) {
|
||||
for i, v := range r {
|
||||
if i > _VD_saves / 8 - 1 {
|
||||
panic("too many registers to load")
|
||||
} else {
|
||||
self.Emit("MOVQ", jit.Ptr(_SP, _VD_fargs + int64(i) * 8), v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (self *_ValueDecoder) call(fn obj.Addr) {
|
||||
self.Emit("MOVQ", fn, _AX) // MOVQ ${fn}, AX
|
||||
self.Rjmp("CALL", _AX) // CALL AX
|
||||
}
|
||||
|
||||
func (self *_ValueDecoder) call_go(fn obj.Addr) {
|
||||
self.save(_REG_go...) // SAVE $REG_go
|
||||
self.call(fn) // CALL ${fn}
|
||||
self.load(_REG_go...) // LOAD $REG_go
|
||||
}
|
||||
|
||||
/** Decoder Assembler **/
|
||||
|
||||
const (
|
||||
_S_val = iota + 1
|
||||
_S_arr
|
||||
_S_arr_0
|
||||
_S_obj
|
||||
_S_obj_0
|
||||
_S_obj_delim
|
||||
_S_obj_sep
|
||||
)
|
||||
|
||||
const (
|
||||
_S_omask_key = (1 << _S_obj_0) | (1 << _S_obj_sep)
|
||||
_S_omask_end = (1 << _S_obj_0) | (1 << _S_obj)
|
||||
_S_vmask = (1 << _S_val) | (1 << _S_arr_0)
|
||||
)
|
||||
|
||||
const (
|
||||
_A_init_len = 1
|
||||
_A_init_cap = 16
|
||||
)
|
||||
|
||||
const (
|
||||
_ST_Sp = 0
|
||||
_ST_Vt = _PtrBytes
|
||||
_ST_Vp = _PtrBytes * (types.MAX_RECURSE + 1)
|
||||
)
|
||||
|
||||
var (
|
||||
_V_true = jit.Imm(int64(pbool(true)))
|
||||
_V_false = jit.Imm(int64(pbool(false)))
|
||||
_F_value = jit.Imm(int64(native.S_value))
|
||||
)
|
||||
|
||||
var (
|
||||
_V_max = jit.Imm(int64(types.V_MAX))
|
||||
_E_eof = jit.Imm(int64(types.ERR_EOF))
|
||||
_E_invalid = jit.Imm(int64(types.ERR_INVALID_CHAR))
|
||||
_E_recurse = jit.Imm(int64(types.ERR_RECURSE_EXCEED_MAX))
|
||||
)
|
||||
|
||||
var (
|
||||
_F_convTslice = jit.Func(convTslice)
|
||||
_F_convTstring = jit.Func(convTstring)
|
||||
_F_invalid_vtype = jit.Func(invalid_vtype)
|
||||
)
|
||||
|
||||
var (
|
||||
_T_map = jit.Type(reflect.TypeOf((map[string]interface{})(nil)))
|
||||
_T_bool = jit.Type(reflect.TypeOf(false))
|
||||
_T_int64 = jit.Type(reflect.TypeOf(int64(0)))
|
||||
_T_eface = jit.Type(reflect.TypeOf((*interface{})(nil)).Elem())
|
||||
_T_slice = jit.Type(reflect.TypeOf(([]interface{})(nil)))
|
||||
_T_string = jit.Type(reflect.TypeOf(""))
|
||||
_T_number = jit.Type(reflect.TypeOf(json.Number("")))
|
||||
_T_float64 = jit.Type(reflect.TypeOf(float64(0)))
|
||||
)
|
||||
|
||||
var _R_tab = map[int]string {
|
||||
'[': "_decode_V_ARRAY",
|
||||
'{': "_decode_V_OBJECT",
|
||||
':': "_decode_V_KEY_SEP",
|
||||
',': "_decode_V_ELEM_SEP",
|
||||
']': "_decode_V_ARRAY_END",
|
||||
'}': "_decode_V_OBJECT_END",
|
||||
}
|
||||
|
||||
func (self *_ValueDecoder) compile() {
|
||||
self.Emit("SUBQ", jit.Imm(_VD_size), _SP) // SUBQ $_VD_size, SP
|
||||
self.Emit("MOVQ", _BP, jit.Ptr(_SP, _VD_offs)) // MOVQ BP, _VD_offs(SP)
|
||||
self.Emit("LEAQ", jit.Ptr(_SP, _VD_offs), _BP) // LEAQ _VD_offs(SP), BP
|
||||
|
||||
/* initialize the state machine */
|
||||
self.Emit("XORL", _CX, _CX) // XORL CX, CX
|
||||
self.Emit("MOVQ", _DF, _VAR_df) // MOVQ DF, df
|
||||
/* initialize digital buffer first */
|
||||
self.Emit("MOVQ", jit.Imm(_MaxDigitNums), _VAR_ss_Dc) // MOVQ $_MaxDigitNums, ss.Dcap
|
||||
self.Emit("LEAQ", jit.Ptr(_ST, _DbufOffset), _AX) // LEAQ _DbufOffset(ST), AX
|
||||
self.Emit("MOVQ", _AX, _VAR_ss_Db) // MOVQ AX, ss.Dbuf
|
||||
/* add ST offset */
|
||||
self.Emit("ADDQ", jit.Imm(_FsmOffset), _ST) // ADDQ _FsmOffset, _ST
|
||||
self.Emit("MOVQ", _CX, jit.Ptr(_ST, _ST_Sp)) // MOVQ CX, ST.Sp
|
||||
self.WriteRecNotAX(0, _VP, jit.Ptr(_ST, _ST_Vp), false) // MOVQ VP, ST.Vp[0]
|
||||
self.Emit("MOVQ", jit.Imm(_S_val), jit.Ptr(_ST, _ST_Vt)) // MOVQ _S_val, ST.Vt[0]
|
||||
self.Sjmp("JMP" , "_next") // JMP _next
|
||||
|
||||
/* set the value from previous round */
|
||||
self.Link("_set_value") // _set_value:
|
||||
self.Emit("MOVL" , jit.Imm(_S_vmask), _DX) // MOVL _S_vmask, DX
|
||||
self.Emit("MOVQ" , jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX
|
||||
self.Emit("MOVQ" , jit.Sib(_ST, _CX, 8, _ST_Vt), _AX) // MOVQ ST.Vt[CX], AX
|
||||
self.Emit("BTQ" , _AX, _DX) // BTQ AX, DX
|
||||
self.Sjmp("JNC" , "_vtype_error") // JNC _vtype_error
|
||||
self.Emit("XORL" , _SI, _SI) // XORL SI, SI
|
||||
self.Emit("SUBQ" , jit.Imm(1), jit.Ptr(_ST, _ST_Sp)) // SUBQ $1, ST.Sp
|
||||
self.Emit("XCHGQ", jit.Sib(_ST, _CX, 8, _ST_Vp), _SI) // XCHGQ ST.Vp[CX], SI
|
||||
self.Emit("MOVQ" , _R8, jit.Ptr(_SI, 0)) // MOVQ R8, (SI)
|
||||
self.WriteRecNotAX(1, _R9, jit.Ptr(_SI, 8), false) // MOVQ R9, 8(SI)
|
||||
|
||||
/* check for value stack */
|
||||
self.Link("_next") // _next:
|
||||
self.Emit("MOVQ" , jit.Ptr(_ST, _ST_Sp), _AX) // MOVQ ST.Sp, AX
|
||||
self.Emit("TESTQ", _AX, _AX) // TESTQ AX, AX
|
||||
self.Sjmp("JS" , "_return") // JS _return
|
||||
|
||||
/* fast path: test up to 4 characters manually */
|
||||
self.Emit("CMPQ" , _IC, _IL) // CMPQ IC, IL
|
||||
self.Sjmp("JAE" , "_decode_V_EOF") // JAE _decode_V_EOF
|
||||
self.Emit("MOVBQZX", jit.Sib(_IP, _IC, 1, 0), _AX) // MOVBQZX (IP)(IC), AX
|
||||
self.Emit("MOVQ" , jit.Imm(_BM_space), _DX) // MOVQ _BM_space, DX
|
||||
self.Emit("CMPQ" , _AX, jit.Imm(' ')) // CMPQ AX, $' '
|
||||
self.Sjmp("JA" , "_decode_fast") // JA _decode_fast
|
||||
self.Emit("BTQ" , _AX, _DX) // BTQ _AX, _DX
|
||||
self.Sjmp("JNC" , "_decode_fast") // JNC _decode_fast
|
||||
self.Emit("ADDQ" , jit.Imm(1), _IC) // ADDQ $1, IC
|
||||
|
||||
/* at least 1 to 3 spaces */
|
||||
for i := 0; i < 3; i++ {
|
||||
self.Emit("CMPQ" , _IC, _IL) // CMPQ IC, IL
|
||||
self.Sjmp("JAE" , "_decode_V_EOF") // JAE _decode_V_EOF
|
||||
self.Emit("MOVBQZX", jit.Sib(_IP, _IC, 1, 0), _AX) // MOVBQZX (IP)(IC), AX
|
||||
self.Emit("CMPQ" , _AX, jit.Imm(' ')) // CMPQ AX, $' '
|
||||
self.Sjmp("JA" , "_decode_fast") // JA _decode_fast
|
||||
self.Emit("BTQ" , _AX, _DX) // BTQ _AX, _DX
|
||||
self.Sjmp("JNC" , "_decode_fast") // JNC _decode_fast
|
||||
self.Emit("ADDQ" , jit.Imm(1), _IC) // ADDQ $1, IC
|
||||
}
|
||||
|
||||
/* at least 4 spaces */
|
||||
self.Emit("CMPQ" , _IC, _IL) // CMPQ IC, IL
|
||||
self.Sjmp("JAE" , "_decode_V_EOF") // JAE _decode_V_EOF
|
||||
self.Emit("MOVBQZX", jit.Sib(_IP, _IC, 1, 0), _AX) // MOVBQZX (IP)(IC), AX
|
||||
|
||||
/* fast path: use lookup table to select decoder */
|
||||
self.Link("_decode_fast") // _decode_fast:
|
||||
self.Byte(0x48, 0x8d, 0x3d) // LEAQ ?(PC), DI
|
||||
self.Sref("_decode_tab", 4) // .... &_decode_tab
|
||||
self.Emit("MOVLQSX", jit.Sib(_DI, _AX, 4, 0), _AX) // MOVLQSX (DI)(AX*4), AX
|
||||
self.Emit("TESTQ" , _AX, _AX) // TESTQ AX, AX
|
||||
self.Sjmp("JZ" , "_decode_native") // JZ _decode_native
|
||||
self.Emit("ADDQ" , jit.Imm(1), _IC) // ADDQ $1, IC
|
||||
self.Emit("ADDQ" , _DI, _AX) // ADDQ DI, AX
|
||||
self.Rjmp("JMP" , _AX) // JMP AX
|
||||
|
||||
/* decode with native decoder */
|
||||
self.Link("_decode_native") // _decode_native:
|
||||
self.Emit("MOVQ", _IP, _DI) // MOVQ IP, DI
|
||||
self.Emit("MOVQ", _IL, _SI) // MOVQ IL, SI
|
||||
self.Emit("MOVQ", _IC, _DX) // MOVQ IC, DX
|
||||
self.Emit("LEAQ", _VAR_ss, _CX) // LEAQ ss, CX
|
||||
self.Emit("MOVQ", _VAR_df, _R8) // MOVQ $df, R8
|
||||
self.Emit("BTSQ", jit.Imm(_F_allow_control), _R8) // ANDQ $1<<_F_allow_control, R8
|
||||
self.call(_F_value) // CALL value
|
||||
self.Emit("MOVQ", _AX, _IC) // MOVQ AX, IC
|
||||
|
||||
/* check for errors */
|
||||
self.Emit("MOVQ" , _VAR_ss_Vt, _AX) // MOVQ ss.Vt, AX
|
||||
self.Emit("TESTQ", _AX, _AX) // TESTQ AX, AX
|
||||
self.Sjmp("JS" , "_parsing_error")
|
||||
self.Sjmp("JZ" , "_invalid_vtype") // JZ _invalid_vtype
|
||||
self.Emit("CMPQ" , _AX, _V_max) // CMPQ AX, _V_max
|
||||
self.Sjmp("JA" , "_invalid_vtype") // JA _invalid_vtype
|
||||
|
||||
/* jump table selector */
|
||||
self.Byte(0x48, 0x8d, 0x3d) // LEAQ ?(PC), DI
|
||||
self.Sref("_switch_table", 4) // .... &_switch_table
|
||||
self.Emit("MOVLQSX", jit.Sib(_DI, _AX, 4, -4), _AX) // MOVLQSX -4(DI)(AX*4), AX
|
||||
self.Emit("ADDQ" , _DI, _AX) // ADDQ DI, AX
|
||||
self.Rjmp("JMP" , _AX) // JMP AX
|
||||
|
||||
/** V_EOF **/
|
||||
self.Link("_decode_V_EOF") // _decode_V_EOF:
|
||||
self.Emit("MOVL", _E_eof, _EP) // MOVL _E_eof, EP
|
||||
self.Sjmp("JMP" , "_error") // JMP _error
|
||||
|
||||
/** V_NULL **/
|
||||
self.Link("_decode_V_NULL") // _decode_V_NULL:
|
||||
self.Emit("XORL", _R8, _R8) // XORL R8, R8
|
||||
self.Emit("XORL", _R9, _R9) // XORL R9, R9
|
||||
self.Emit("LEAQ", jit.Ptr(_IC, -4), _DI) // LEAQ -4(IC), DI
|
||||
self.Sjmp("JMP" , "_set_value") // JMP _set_value
|
||||
|
||||
/** V_TRUE **/
|
||||
self.Link("_decode_V_TRUE") // _decode_V_TRUE:
|
||||
self.Emit("MOVQ", _T_bool, _R8) // MOVQ _T_bool, R8
|
||||
// TODO: maybe modified by users?
|
||||
self.Emit("MOVQ", _V_true, _R9) // MOVQ _V_true, R9
|
||||
self.Emit("LEAQ", jit.Ptr(_IC, -4), _DI) // LEAQ -4(IC), DI
|
||||
self.Sjmp("JMP" , "_set_value") // JMP _set_value
|
||||
|
||||
/** V_FALSE **/
|
||||
self.Link("_decode_V_FALSE") // _decode_V_FALSE:
|
||||
self.Emit("MOVQ", _T_bool, _R8) // MOVQ _T_bool, R8
|
||||
self.Emit("MOVQ", _V_false, _R9) // MOVQ _V_false, R9
|
||||
self.Emit("LEAQ", jit.Ptr(_IC, -5), _DI) // LEAQ -5(IC), DI
|
||||
self.Sjmp("JMP" , "_set_value") // JMP _set_value
|
||||
|
||||
/** V_ARRAY **/
|
||||
self.Link("_decode_V_ARRAY") // _decode_V_ARRAY
|
||||
self.Emit("MOVL", jit.Imm(_S_vmask), _DX) // MOVL _S_vmask, DX
|
||||
self.Emit("MOVQ", jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX
|
||||
self.Emit("MOVQ", jit.Sib(_ST, _CX, 8, _ST_Vt), _AX) // MOVQ ST.Vt[CX], AX
|
||||
self.Emit("BTQ" , _AX, _DX) // BTQ AX, DX
|
||||
self.Sjmp("JNC" , "_invalid_char") // JNC _invalid_char
|
||||
|
||||
/* create a new array */
|
||||
self.Emit("MOVQ", _T_eface, _AX) // MOVQ _T_eface, AX
|
||||
self.Emit("MOVQ", _AX, jit.Ptr(_SP, 0)) // MOVQ AX, (SP)
|
||||
self.Emit("MOVQ", jit.Imm(_A_init_len), jit.Ptr(_SP, 8)) // MOVQ _A_init_len, 8(SP)
|
||||
self.Emit("MOVQ", jit.Imm(_A_init_cap), jit.Ptr(_SP, 16)) // MOVQ _A_init_cap, 16(SP)
|
||||
self.call_go(_F_makeslice) // CALL_GO runtime.makeslice
|
||||
self.Emit("MOVQ", jit.Ptr(_SP, 24), _DX) // MOVQ 24(SP), DX
|
||||
|
||||
/* pack into an interface */
|
||||
self.Emit("MOVQ", _DX, jit.Ptr(_SP, 0)) // MOVQ DX, (SP)
|
||||
self.Emit("MOVQ", jit.Imm(_A_init_len), jit.Ptr(_SP, 8)) // MOVQ _A_init_len, 8(SP)
|
||||
self.Emit("MOVQ", jit.Imm(_A_init_cap), jit.Ptr(_SP, 16)) // MOVQ _A_init_cap, 16(SP)
|
||||
self.call_go(_F_convTslice) // CALL_GO runtime.convTslice
|
||||
self.Emit("MOVQ", jit.Ptr(_SP, 24), _R8) // MOVQ 24(SP), R8
|
||||
|
||||
/* replace current state with an array */
|
||||
self.Emit("MOVQ", jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX
|
||||
self.Emit("MOVQ", jit.Sib(_ST, _CX, 8, _ST_Vp), _SI) // MOVQ ST.Vp[CX], SI
|
||||
self.Emit("MOVQ", jit.Imm(_S_arr), jit.Sib(_ST, _CX, 8, _ST_Vt)) // MOVQ _S_arr, ST.Vt[CX]
|
||||
self.Emit("MOVQ", _T_slice, _AX) // MOVQ _T_slice, AX
|
||||
self.Emit("MOVQ", _AX, jit.Ptr(_SI, 0)) // MOVQ AX, (SI)
|
||||
self.WriteRecNotAX(2, _R8, jit.Ptr(_SI, 8), false) // MOVQ R8, 8(SI)
|
||||
|
||||
/* add a new slot for the first element */
|
||||
self.Emit("ADDQ", jit.Imm(1), _CX) // ADDQ $1, CX
|
||||
self.Emit("CMPQ", _CX, jit.Imm(types.MAX_RECURSE)) // CMPQ CX, ${types.MAX_RECURSE}
|
||||
self.Sjmp("JAE" , "_stack_overflow") // JA _stack_overflow
|
||||
self.Emit("MOVQ", jit.Ptr(_R8, 0), _AX) // MOVQ (R8), AX
|
||||
self.Emit("MOVQ", _CX, jit.Ptr(_ST, _ST_Sp)) // MOVQ CX, ST.Sp
|
||||
self.WritePtrAX(3, jit.Sib(_ST, _CX, 8, _ST_Vp), false) // MOVQ AX, ST.Vp[CX]
|
||||
self.Emit("MOVQ", jit.Imm(_S_arr_0), jit.Sib(_ST, _CX, 8, _ST_Vt)) // MOVQ _S_arr_0, ST.Vt[CX]
|
||||
self.Sjmp("JMP" , "_next") // JMP _next
|
||||
|
||||
/** V_OBJECT **/
|
||||
self.Link("_decode_V_OBJECT") // _decode_V_OBJECT:
|
||||
self.Emit("MOVL", jit.Imm(_S_vmask), _DX) // MOVL _S_vmask, DX
|
||||
self.Emit("MOVQ", jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX
|
||||
self.Emit("MOVQ", jit.Sib(_ST, _CX, 8, _ST_Vt), _AX) // MOVQ ST.Vt[CX], AX
|
||||
self.Emit("BTQ" , _AX, _DX) // BTQ AX, DX
|
||||
self.Sjmp("JNC" , "_invalid_char") // JNC _invalid_char
|
||||
self.call_go(_F_makemap_small) // CALL_GO runtime.makemap_small
|
||||
self.Emit("MOVQ", jit.Ptr(_SP, 0), _AX) // MOVQ (SP), AX
|
||||
self.Emit("MOVQ", jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX
|
||||
self.Emit("MOVQ", jit.Imm(_S_obj_0), jit.Sib(_ST, _CX, 8, _ST_Vt)) // MOVQ _S_obj, ST.Vt[CX]
|
||||
self.Emit("MOVQ", jit.Sib(_ST, _CX, 8, _ST_Vp), _SI) // MOVQ ST.Vp[CX], SI
|
||||
self.Emit("MOVQ", _T_map, _DX) // MOVQ _T_map, DX
|
||||
self.Emit("MOVQ", _DX, jit.Ptr(_SI, 0)) // MOVQ DX, (SI)
|
||||
self.WritePtrAX(4, jit.Ptr(_SI, 8), false) // MOVQ AX, 8(SI)
|
||||
self.Sjmp("JMP" , "_next") // JMP _next
|
||||
|
||||
/** V_STRING **/
|
||||
self.Link("_decode_V_STRING") // _decode_V_STRING:
|
||||
self.Emit("MOVQ", _VAR_ss_Iv, _CX) // MOVQ ss.Iv, CX
|
||||
self.Emit("MOVQ", _IC, _AX) // MOVQ IC, AX
|
||||
self.Emit("SUBQ", _CX, _AX) // SUBQ CX, AX
|
||||
|
||||
/* check for escapes */
|
||||
self.Emit("CMPQ", _VAR_ss_Ep, jit.Imm(-1)) // CMPQ ss.Ep, $-1
|
||||
self.Sjmp("JNE" , "_unquote") // JNE _unquote
|
||||
self.Emit("SUBQ", jit.Imm(1), _AX) // SUBQ $1, AX
|
||||
self.Emit("LEAQ", jit.Sib(_IP, _CX, 1, 0), _R8) // LEAQ (IP)(CX), R8
|
||||
self.Byte(0x48, 0x8d, 0x3d) // LEAQ (PC), DI
|
||||
self.Sref("_copy_string_end", 4)
|
||||
self.Emit("BTQ", jit.Imm(_F_copy_string), _VAR_df)
|
||||
self.Sjmp("JC", "copy_string")
|
||||
self.Link("_copy_string_end")
|
||||
self.Emit("XORL", _DX, _DX) // XORL DX, DX
|
||||
/* strings with no escape sequences */
|
||||
self.Link("_noescape") // _noescape:
|
||||
self.Emit("MOVL", jit.Imm(_S_omask_key), _DI) // MOVL _S_omask, DI
|
||||
self.Emit("MOVQ", jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX
|
||||
self.Emit("MOVQ", jit.Sib(_ST, _CX, 8, _ST_Vt), _SI) // MOVQ ST.Vt[CX], SI
|
||||
self.Emit("BTQ" , _SI, _DI) // BTQ SI, DI
|
||||
self.Sjmp("JC" , "_object_key") // JC _object_key
|
||||
|
||||
/* check for pre-packed strings, avoid 1 allocation */
|
||||
self.Emit("TESTQ", _DX, _DX) // TESTQ DX, DX
|
||||
self.Sjmp("JNZ" , "_packed_str") // JNZ _packed_str
|
||||
self.Emit("MOVQ" , _R8, jit.Ptr(_SP, 0)) // MOVQ R8, (SP)
|
||||
self.Emit("MOVQ" , _AX, jit.Ptr(_SP, 8)) // MOVQ AX, 8(SP)
|
||||
self.call_go(_F_convTstring) // CALL_GO runtime.convTstring
|
||||
self.Emit("MOVQ" , jit.Ptr(_SP, 16), _R9) // MOVQ 16(SP), R9
|
||||
|
||||
/* packed string already in R9 */
|
||||
self.Link("_packed_str") // _packed_str:
|
||||
self.Emit("MOVQ", _T_string, _R8) // MOVQ _T_string, R8
|
||||
self.Emit("MOVQ", _VAR_ss_Iv, _DI) // MOVQ ss.Iv, DI
|
||||
self.Emit("SUBQ", jit.Imm(1), _DI) // SUBQ $1, DI
|
||||
self.Sjmp("JMP" , "_set_value") // JMP _set_value
|
||||
|
||||
/* the string is an object key, get the map */
|
||||
self.Link("_object_key")
|
||||
self.Emit("MOVQ", jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX
|
||||
self.Emit("MOVQ", jit.Sib(_ST, _CX, 8, _ST_Vp), _SI) // MOVQ ST.Vp[CX], SI
|
||||
self.Emit("MOVQ", jit.Ptr(_SI, 8), _SI) // MOVQ 8(SI), SI
|
||||
|
||||
/* add a new delimiter */
|
||||
self.Emit("ADDQ", jit.Imm(1), _CX) // ADDQ $1, CX
|
||||
self.Emit("CMPQ", _CX, jit.Imm(types.MAX_RECURSE)) // CMPQ CX, ${types.MAX_RECURSE}
|
||||
self.Sjmp("JAE" , "_stack_overflow") // JA _stack_overflow
|
||||
self.Emit("MOVQ", _CX, jit.Ptr(_ST, _ST_Sp)) // MOVQ CX, ST.Sp
|
||||
self.Emit("MOVQ", jit.Imm(_S_obj_delim), jit.Sib(_ST, _CX, 8, _ST_Vt)) // MOVQ _S_obj_delim, ST.Vt[CX]
|
||||
|
||||
/* add a new slot int the map */
|
||||
self.Emit("MOVQ", _T_map, _DX) // MOVQ _T_map, DX
|
||||
self.Emit("MOVQ", _DX, jit.Ptr(_SP, 0)) // MOVQ DX, (SP)
|
||||
self.Emit("MOVQ", _SI, jit.Ptr(_SP, 8)) // MOVQ SI, 8(SP)
|
||||
self.Emit("MOVQ", _R8, jit.Ptr(_SP, 16)) // MOVQ R9, 16(SP)
|
||||
self.Emit("MOVQ", _AX, jit.Ptr(_SP, 24)) // MOVQ AX, 24(SP)
|
||||
self.call_go(_F_mapassign_faststr) // CALL_GO runtime.mapassign_faststr
|
||||
self.Emit("MOVQ", jit.Ptr(_SP, 32), _AX) // MOVQ 32(SP), AX
|
||||
|
||||
/* add to the pointer stack */
|
||||
self.Emit("MOVQ", jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX
|
||||
self.WritePtrAX(6, jit.Sib(_ST, _CX, 8, _ST_Vp), false) // MOVQ AX, ST.Vp[CX]
|
||||
self.Sjmp("JMP" , "_next") // JMP _next
|
||||
|
||||
/* allocate memory to store the string header and unquoted result */
|
||||
self.Link("_unquote") // _unquote:
|
||||
self.Emit("ADDQ", jit.Imm(15), _AX) // ADDQ $15, AX
|
||||
self.Emit("MOVQ", _T_byte, _CX) // MOVQ _T_byte, CX
|
||||
self.Emit("MOVQ", _AX, jit.Ptr(_SP, 0)) // MOVQ AX, (SP)
|
||||
self.Emit("MOVQ", _CX, jit.Ptr(_SP, 8)) // MOVQ CX, 8(SP)
|
||||
self.Emit("MOVB", jit.Imm(0), jit.Ptr(_SP, 16)) // MOVB $0, 16(SP)
|
||||
self.call_go(_F_mallocgc) // CALL_GO runtime.mallocgc
|
||||
self.Emit("MOVQ", jit.Ptr(_SP, 24), _R9) // MOVQ 24(SP), R9
|
||||
|
||||
/* prepare the unquoting parameters */
|
||||
self.Emit("MOVQ" , _VAR_ss_Iv, _CX) // MOVQ ss.Iv, CX
|
||||
self.Emit("LEAQ" , jit.Sib(_IP, _CX, 1, 0), _DI) // LEAQ (IP)(CX), DI
|
||||
self.Emit("NEGQ" , _CX) // NEGQ CX
|
||||
self.Emit("LEAQ" , jit.Sib(_IC, _CX, 1, -1), _SI) // LEAQ -1(IC)(CX), SI
|
||||
self.Emit("LEAQ" , jit.Ptr(_R9, 16), _DX) // LEAQ 16(R8), DX
|
||||
self.Emit("LEAQ" , _VAR_ss_Ep, _CX) // LEAQ ss.Ep, CX
|
||||
self.Emit("XORL" , _R8, _R8) // XORL R8, R8
|
||||
self.Emit("BTQ" , jit.Imm(_F_disable_urc), _VAR_df) // BTQ ${_F_disable_urc}, fv
|
||||
self.Emit("SETCC", _R8) // SETCC R8
|
||||
self.Emit("SHLQ" , jit.Imm(types.B_UNICODE_REPLACE), _R8) // SHLQ ${types.B_UNICODE_REPLACE}, R8
|
||||
|
||||
/* unquote the string, with R9 been preserved */
|
||||
self.save(_R9) // SAVE R9
|
||||
self.call(_F_unquote) // CALL unquote
|
||||
self.load(_R9) // LOAD R9
|
||||
|
||||
/* check for errors */
|
||||
self.Emit("TESTQ", _AX, _AX) // TESTQ AX, AX
|
||||
self.Sjmp("JS" , "_unquote_error") // JS _unquote_error
|
||||
self.Emit("MOVL" , jit.Imm(1), _DX) // MOVL $1, DX
|
||||
self.Emit("LEAQ" , jit.Ptr(_R9, 16), _R8) // ADDQ $16, R8
|
||||
self.Emit("MOVQ" , _R8, jit.Ptr(_R9, 0)) // MOVQ R8, (R9)
|
||||
self.Emit("MOVQ" , _AX, jit.Ptr(_R9, 8)) // MOVQ AX, 8(R9)
|
||||
self.Sjmp("JMP" , "_noescape") // JMP _noescape
|
||||
|
||||
/** V_DOUBLE **/
|
||||
self.Link("_decode_V_DOUBLE") // _decode_V_DOUBLE:
|
||||
self.Emit("BTQ" , jit.Imm(_F_use_number), _VAR_df) // BTQ _F_use_number, df
|
||||
self.Sjmp("JC" , "_use_number") // JC _use_number
|
||||
self.Emit("MOVSD", _VAR_ss_Dv, _X0) // MOVSD ss.Dv, X0
|
||||
self.Sjmp("JMP" , "_use_float64") // JMP _use_float64
|
||||
|
||||
/** V_INTEGER **/
|
||||
self.Link("_decode_V_INTEGER") // _decode_V_INTEGER:
|
||||
self.Emit("BTQ" , jit.Imm(_F_use_number), _VAR_df) // BTQ _F_use_number, df
|
||||
self.Sjmp("JC" , "_use_number") // JC _use_number
|
||||
self.Emit("BTQ" , jit.Imm(_F_use_int64), _VAR_df) // BTQ _F_use_int64, df
|
||||
self.Sjmp("JC" , "_use_int64") // JC _use_int64
|
||||
self.Emit("MOVQ" , _VAR_ss_Iv, _AX) // MOVQ ss.Iv, AX
|
||||
self.Emit("CVTSQ2SD", _AX, _X0) // CVTSQ2SD AX, X0
|
||||
|
||||
/* represent numbers as `float64` */
|
||||
self.Link("_use_float64") // _use_float64:
|
||||
self.Emit("MOVSD", _X0, jit.Ptr(_SP, 0)) // MOVSD X0, (SP)
|
||||
self.call_go(_F_convT64) // CALL_GO runtime.convT64
|
||||
self.Emit("MOVQ" , _T_float64, _R8) // MOVQ _T_float64, R8
|
||||
self.Emit("MOVQ" , jit.Ptr(_SP, 8), _R9) // MOVQ 8(SP), R9
|
||||
self.Emit("MOVQ" , _VAR_ss_Ep, _DI) // MOVQ ss.Ep, DI
|
||||
self.Sjmp("JMP" , "_set_value") // JMP _set_value
|
||||
|
||||
/* represent numbers as `json.Number` */
|
||||
self.Link("_use_number") // _use_number
|
||||
self.Emit("MOVQ", _VAR_ss_Ep, _AX) // MOVQ ss.Ep, AX
|
||||
self.Emit("LEAQ", jit.Sib(_IP, _AX, 1, 0), _SI) // LEAQ (IP)(AX), SI
|
||||
self.Emit("MOVQ", _IC, _CX) // MOVQ IC, CX
|
||||
self.Emit("SUBQ", _AX, _CX) // SUBQ AX, CX
|
||||
self.Emit("MOVQ", _SI, jit.Ptr(_SP, 0)) // MOVQ SI, (SP)
|
||||
self.Emit("MOVQ", _CX, jit.Ptr(_SP, 8)) // MOVQ CX, 8(SP)
|
||||
self.call_go(_F_convTstring) // CALL_GO runtime.convTstring
|
||||
self.Emit("MOVQ", _T_number, _R8) // MOVQ _T_number, R8
|
||||
self.Emit("MOVQ", jit.Ptr(_SP, 16), _R9) // MOVQ 16(SP), R9
|
||||
self.Emit("MOVQ", _VAR_ss_Ep, _DI) // MOVQ ss.Ep, DI
|
||||
self.Sjmp("JMP" , "_set_value") // JMP _set_value
|
||||
|
||||
/* represent numbers as `int64` */
|
||||
self.Link("_use_int64") // _use_int64:
|
||||
self.Emit("MOVQ", _VAR_ss_Iv, _AX) // MOVQ ss.Iv, AX
|
||||
self.Emit("MOVQ", _AX, jit.Ptr(_SP, 0)) // MOVQ AX, (SP)
|
||||
self.call_go(_F_convT64) // CALL_GO runtime.convT64
|
||||
self.Emit("MOVQ", _T_int64, _R8) // MOVQ _T_int64, R8
|
||||
self.Emit("MOVQ", jit.Ptr(_SP, 8), _R9) // MOVQ 8(SP), R9
|
||||
self.Emit("MOVQ", _VAR_ss_Ep, _DI) // MOVQ ss.Ep, DI
|
||||
self.Sjmp("JMP" , "_set_value") // JMP _set_value
|
||||
|
||||
/** V_KEY_SEP **/
|
||||
self.Link("_decode_V_KEY_SEP") // _decode_V_KEY_SEP:
|
||||
// self.Byte(0xcc)
|
||||
self.Emit("MOVQ", jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX
|
||||
self.Emit("MOVQ", jit.Sib(_ST, _CX, 8, _ST_Vt), _AX) // MOVQ ST.Vt[CX], AX
|
||||
self.Emit("CMPQ", _AX, jit.Imm(_S_obj_delim)) // CMPQ AX, _S_obj_delim
|
||||
self.Sjmp("JNE" , "_invalid_char") // JNE _invalid_char
|
||||
self.Emit("MOVQ", jit.Imm(_S_val), jit.Sib(_ST, _CX, 8, _ST_Vt)) // MOVQ _S_val, ST.Vt[CX]
|
||||
self.Emit("MOVQ", jit.Imm(_S_obj), jit.Sib(_ST, _CX, 8, _ST_Vt - 8)) // MOVQ _S_obj, ST.Vt[CX - 1]
|
||||
self.Sjmp("JMP" , "_next") // JMP _next
|
||||
|
||||
/** V_ELEM_SEP **/
|
||||
self.Link("_decode_V_ELEM_SEP") // _decode_V_ELEM_SEP:
|
||||
self.Emit("MOVQ" , jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX
|
||||
self.Emit("MOVQ" , jit.Sib(_ST, _CX, 8, _ST_Vt), _AX) // MOVQ ST.Vt[CX], AX
|
||||
self.Emit("CMPQ" , _AX, jit.Imm(_S_arr)) // CMPQ _AX, _S_arr
|
||||
self.Sjmp("JE" , "_array_sep") // JZ _next
|
||||
self.Emit("CMPQ" , _AX, jit.Imm(_S_obj)) // CMPQ _AX, _S_arr
|
||||
self.Sjmp("JNE" , "_invalid_char") // JNE _invalid_char
|
||||
self.Emit("MOVQ" , jit.Imm(_S_obj_sep), jit.Sib(_ST, _CX, 8, _ST_Vt))
|
||||
self.Sjmp("JMP" , "_next") // JMP _next
|
||||
|
||||
/* arrays */
|
||||
self.Link("_array_sep")
|
||||
self.Emit("MOVQ", jit.Sib(_ST, _CX, 8, _ST_Vp), _SI) // MOVQ ST.Vp[CX], SI
|
||||
self.Emit("MOVQ", jit.Ptr(_SI, 8), _SI) // MOVQ 8(SI), SI
|
||||
self.Emit("MOVQ", jit.Ptr(_SI, 8), _DX) // MOVQ 8(SI), DX
|
||||
self.Emit("CMPQ", _DX, jit.Ptr(_SI, 16)) // CMPQ DX, 16(SI)
|
||||
self.Sjmp("JAE" , "_array_more") // JAE _array_more
|
||||
|
||||
/* add a slot for the new element */
|
||||
self.Link("_array_append") // _array_append:
|
||||
self.Emit("ADDQ", jit.Imm(1), jit.Ptr(_SI, 8)) // ADDQ $1, 8(SI)
|
||||
self.Emit("MOVQ", jit.Ptr(_SI, 0), _SI) // MOVQ (SI), SI
|
||||
self.Emit("ADDQ", jit.Imm(1), _CX) // ADDQ $1, CX
|
||||
self.Emit("CMPQ", _CX, jit.Imm(types.MAX_RECURSE)) // CMPQ CX, ${types.MAX_RECURSE}
|
||||
self.Sjmp("JAE" , "_stack_overflow")
|
||||
self.Emit("SHLQ", jit.Imm(1), _DX) // SHLQ $1, DX
|
||||
self.Emit("LEAQ", jit.Sib(_SI, _DX, 8, 0), _SI) // LEAQ (SI)(DX*8), SI
|
||||
self.Emit("MOVQ", _CX, jit.Ptr(_ST, _ST_Sp)) // MOVQ CX, ST.Sp
|
||||
self.WriteRecNotAX(7 , _SI, jit.Sib(_ST, _CX, 8, _ST_Vp), false) // MOVQ SI, ST.Vp[CX]
|
||||
self.Emit("MOVQ", jit.Imm(_S_val), jit.Sib(_ST, _CX, 8, _ST_Vt)) // MOVQ _S_val, ST.Vt[CX}
|
||||
self.Sjmp("JMP" , "_next") // JMP _next
|
||||
|
||||
/** V_ARRAY_END **/
|
||||
self.Link("_decode_V_ARRAY_END") // _decode_V_ARRAY_END:
|
||||
self.Emit("XORL", _DX, _DX) // XORL DX, DX
|
||||
self.Emit("MOVQ", jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX
|
||||
self.Emit("MOVQ", jit.Sib(_ST, _CX, 8, _ST_Vt), _AX) // MOVQ ST.Vt[CX], AX
|
||||
self.Emit("CMPQ", _AX, jit.Imm(_S_arr_0)) // CMPQ AX, _S_arr_0
|
||||
self.Sjmp("JE" , "_first_item") // JE _first_item
|
||||
self.Emit("CMPQ", _AX, jit.Imm(_S_arr)) // CMPQ AX, _S_arr
|
||||
self.Sjmp("JNE" , "_invalid_char") // JNE _invalid_char
|
||||
self.Emit("SUBQ", jit.Imm(1), jit.Ptr(_ST, _ST_Sp)) // SUBQ $1, ST.Sp
|
||||
self.Emit("MOVQ", _DX, jit.Sib(_ST, _CX, 8, _ST_Vp)) // MOVQ DX, ST.Vp[CX]
|
||||
self.Sjmp("JMP" , "_next") // JMP _next
|
||||
|
||||
/* first element of an array */
|
||||
self.Link("_first_item") // _first_item:
|
||||
self.Emit("MOVQ", jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX
|
||||
self.Emit("SUBQ", jit.Imm(2), jit.Ptr(_ST, _ST_Sp)) // SUBQ $2, ST.Sp
|
||||
self.Emit("MOVQ", jit.Sib(_ST, _CX, 8, _ST_Vp - 8), _SI) // MOVQ ST.Vp[CX - 1], SI
|
||||
self.Emit("MOVQ", jit.Ptr(_SI, 8), _SI) // MOVQ 8(SI), SI
|
||||
self.Emit("MOVQ", _DX, jit.Sib(_ST, _CX, 8, _ST_Vp - 8)) // MOVQ DX, ST.Vp[CX - 1]
|
||||
self.Emit("MOVQ", _DX, jit.Sib(_ST, _CX, 8, _ST_Vp)) // MOVQ DX, ST.Vp[CX]
|
||||
self.Emit("MOVQ", _DX, jit.Ptr(_SI, 8)) // MOVQ DX, 8(SI)
|
||||
self.Sjmp("JMP" , "_next") // JMP _next
|
||||
|
||||
/** V_OBJECT_END **/
|
||||
self.Link("_decode_V_OBJECT_END") // _decode_V_OBJECT_END:
|
||||
self.Emit("MOVL", jit.Imm(_S_omask_end), _DX) // MOVL _S_omask, DI
|
||||
self.Emit("MOVQ", jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX
|
||||
self.Emit("MOVQ", jit.Sib(_ST, _CX, 8, _ST_Vt), _AX) // MOVQ ST.Vt[CX], AX
|
||||
self.Emit("BTQ" , _AX, _DX)
|
||||
self.Sjmp("JNC" , "_invalid_char") // JNE _invalid_char
|
||||
self.Emit("XORL", _AX, _AX) // XORL AX, AX
|
||||
self.Emit("SUBQ", jit.Imm(1), jit.Ptr(_ST, _ST_Sp)) // SUBQ $1, ST.Sp
|
||||
self.Emit("MOVQ", _AX, jit.Sib(_ST, _CX, 8, _ST_Vp)) // MOVQ AX, ST.Vp[CX]
|
||||
self.Sjmp("JMP" , "_next") // JMP _next
|
||||
|
||||
/* return from decoder */
|
||||
self.Link("_return") // _return:
|
||||
self.Emit("XORL", _EP, _EP) // XORL EP, EP
|
||||
self.Emit("MOVQ", _EP, jit.Ptr(_ST, _ST_Vp)) // MOVQ EP, ST.Vp[0]
|
||||
self.Link("_epilogue") // _epilogue:
|
||||
self.Emit("SUBQ", jit.Imm(_FsmOffset), _ST) // SUBQ _FsmOffset, _ST
|
||||
self.Emit("MOVQ", jit.Ptr(_SP, _VD_offs), _BP) // MOVQ _VD_offs(SP), BP
|
||||
self.Emit("ADDQ", jit.Imm(_VD_size), _SP) // ADDQ $_VD_size, SP
|
||||
self.Emit("RET") // RET
|
||||
|
||||
/* array expand */
|
||||
self.Link("_array_more") // _array_more:
|
||||
self.Emit("MOVQ" , _T_eface, _AX) // MOVQ _T_eface, AX
|
||||
self.Emit("MOVOU", jit.Ptr(_SI, 0), _X0) // MOVOU (SI), X0
|
||||
self.Emit("MOVQ" , jit.Ptr(_SI, 16), _DX) // MOVQ 16(SI), DX
|
||||
self.Emit("MOVQ" , _AX, jit.Ptr(_SP, 0)) // MOVQ AX, (SP)
|
||||
self.Emit("MOVOU", _X0, jit.Ptr(_SP, 8)) // MOVOU X0, 8(SP)
|
||||
self.Emit("MOVQ" , _DX, jit.Ptr(_SP, 24)) // MOVQ DX, 24(SP)
|
||||
self.Emit("SHLQ" , jit.Imm(1), _DX) // SHLQ $1, DX
|
||||
self.Emit("MOVQ" , _DX, jit.Ptr(_SP, 32)) // MOVQ DX, 32(SP)
|
||||
self.call_go(_F_growslice) // CALL_GO runtime.growslice
|
||||
self.Emit("MOVQ" , jit.Ptr(_SP, 40), _DI) // MOVOU 40(SP), DI
|
||||
self.Emit("MOVQ" , jit.Ptr(_SP, 48), _DX) // MOVOU 48(SP), DX
|
||||
self.Emit("MOVQ" , jit.Ptr(_SP, 56), _AX) // MOVQ 56(SP), AX
|
||||
|
||||
/* update the slice */
|
||||
self.Emit("MOVQ", jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX
|
||||
self.Emit("MOVQ", jit.Sib(_ST, _CX, 8, _ST_Vp), _SI) // MOVQ ST.Vp[CX], SI
|
||||
self.Emit("MOVQ", jit.Ptr(_SI, 8), _SI) // MOVQ 8(SI), SI
|
||||
self.Emit("MOVQ", _DX, jit.Ptr(_SI, 8)) // MOVQ DX, 8(SI)
|
||||
self.Emit("MOVQ", _AX, jit.Ptr(_SI, 16)) // MOVQ AX, 16(AX)
|
||||
self.WriteRecNotAX(8 , _DI, jit.Ptr(_SI, 0), false) // MOVQ R10, (SI)
|
||||
self.Sjmp("JMP" , "_array_append") // JMP _array_append
|
||||
|
||||
/* copy string */
|
||||
self.Link("copy_string") // pointer: R8, length: AX, return addr: DI
|
||||
// self.Byte(0xcc)
|
||||
self.Emit("MOVQ", _R8, _VAR_cs_p)
|
||||
self.Emit("MOVQ", _AX, _VAR_cs_n)
|
||||
self.Emit("MOVQ", _DI, _VAR_cs_LR)
|
||||
self.Emit("MOVQ", _T_byte, jit.Ptr(_SP, 0))
|
||||
self.Emit("MOVQ", _AX, jit.Ptr(_SP, 8))
|
||||
self.Emit("MOVQ", _AX, jit.Ptr(_SP, 16))
|
||||
self.call_go(_F_makeslice)
|
||||
self.Emit("MOVQ", jit.Ptr(_SP, 24), _R8)
|
||||
self.Emit("MOVQ", _R8, _VAR_cs_d)
|
||||
self.Emit("MOVQ", _R8, jit.Ptr(_SP, 0))
|
||||
self.Emit("MOVQ", _VAR_cs_p, _R8)
|
||||
self.Emit("MOVQ", _R8, jit.Ptr(_SP, 8))
|
||||
self.Emit("MOVQ", _VAR_cs_n, _AX)
|
||||
self.Emit("MOVQ", _AX, jit.Ptr(_SP, 16))
|
||||
self.call_go(_F_memmove)
|
||||
self.Emit("MOVQ", _VAR_cs_d, _R8)
|
||||
self.Emit("MOVQ", _VAR_cs_n, _AX)
|
||||
self.Emit("MOVQ", _VAR_cs_LR, _DI)
|
||||
// self.Byte(0xcc)
|
||||
self.Rjmp("JMP", _DI)
|
||||
|
||||
/* error handlers */
|
||||
self.Link("_stack_overflow")
|
||||
self.Emit("MOVL" , _E_recurse, _EP) // MOVQ _E_recurse, EP
|
||||
self.Sjmp("JMP" , "_error") // JMP _error
|
||||
self.Link("_vtype_error") // _vtype_error:
|
||||
self.Emit("MOVQ" , _DI, _IC) // MOVQ DI, IC
|
||||
self.Emit("MOVL" , _E_invalid, _EP) // MOVL _E_invalid, EP
|
||||
self.Sjmp("JMP" , "_error") // JMP _error
|
||||
self.Link("_invalid_char") // _invalid_char:
|
||||
self.Emit("SUBQ" , jit.Imm(1), _IC) // SUBQ $1, IC
|
||||
self.Emit("MOVL" , _E_invalid, _EP) // MOVL _E_invalid, EP
|
||||
self.Sjmp("JMP" , "_error") // JMP _error
|
||||
self.Link("_unquote_error") // _unquote_error:
|
||||
self.Emit("MOVQ" , _VAR_ss_Iv, _IC) // MOVQ ss.Iv, IC
|
||||
self.Emit("SUBQ" , jit.Imm(1), _IC) // SUBQ $1, IC
|
||||
self.Link("_parsing_error") // _parsing_error:
|
||||
self.Emit("NEGQ" , _AX) // NEGQ AX
|
||||
self.Emit("MOVQ" , _AX, _EP) // MOVQ AX, EP
|
||||
self.Link("_error") // _error:
|
||||
self.Emit("PXOR" , _X0, _X0) // PXOR X0, X0
|
||||
self.Emit("MOVOU", _X0, jit.Ptr(_VP, 0)) // MOVOU X0, (VP)
|
||||
self.Sjmp("JMP" , "_epilogue") // JMP _epilogue
|
||||
|
||||
/* invalid value type, never returns */
|
||||
self.Link("_invalid_vtype")
|
||||
self.Emit("MOVQ", _AX, jit.Ptr(_SP, 0)) // MOVQ AX, (SP)
|
||||
self.call(_F_invalid_vtype) // CALL invalid_type
|
||||
self.Emit("UD2") // UD2
|
||||
|
||||
/* switch jump table */
|
||||
self.Link("_switch_table") // _switch_table:
|
||||
self.Sref("_decode_V_EOF", 0) // SREF &_decode_V_EOF, $0
|
||||
self.Sref("_decode_V_NULL", -4) // SREF &_decode_V_NULL, $-4
|
||||
self.Sref("_decode_V_TRUE", -8) // SREF &_decode_V_TRUE, $-8
|
||||
self.Sref("_decode_V_FALSE", -12) // SREF &_decode_V_FALSE, $-12
|
||||
self.Sref("_decode_V_ARRAY", -16) // SREF &_decode_V_ARRAY, $-16
|
||||
self.Sref("_decode_V_OBJECT", -20) // SREF &_decode_V_OBJECT, $-20
|
||||
self.Sref("_decode_V_STRING", -24) // SREF &_decode_V_STRING, $-24
|
||||
self.Sref("_decode_V_DOUBLE", -28) // SREF &_decode_V_DOUBLE, $-28
|
||||
self.Sref("_decode_V_INTEGER", -32) // SREF &_decode_V_INTEGER, $-32
|
||||
self.Sref("_decode_V_KEY_SEP", -36) // SREF &_decode_V_KEY_SEP, $-36
|
||||
self.Sref("_decode_V_ELEM_SEP", -40) // SREF &_decode_V_ELEM_SEP, $-40
|
||||
self.Sref("_decode_V_ARRAY_END", -44) // SREF &_decode_V_ARRAY_END, $-44
|
||||
self.Sref("_decode_V_OBJECT_END", -48) // SREF &_decode_V_OBJECT_END, $-48
|
||||
|
||||
/* fast character lookup table */
|
||||
self.Link("_decode_tab") // _decode_tab:
|
||||
self.Sref("_decode_V_EOF", 0) // SREF &_decode_V_EOF, $0
|
||||
|
||||
/* generate rest of the tabs */
|
||||
for i := 1; i < 256; i++ {
|
||||
if to, ok := _R_tab[i]; ok {
|
||||
self.Sref(to, -int64(i) * 4)
|
||||
} else {
|
||||
self.Byte(0x00, 0x00, 0x00, 0x00)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (self *_ValueDecoder) WritePtrAX(i int, rec obj.Addr, saveDI bool) {
|
||||
self.Emit("MOVQ", _V_writeBarrier, _R10)
|
||||
self.Emit("CMPL", jit.Ptr(_R10, 0), jit.Imm(0))
|
||||
self.Sjmp("JE", "_no_writeBarrier" + strconv.Itoa(i) + "_{n}")
|
||||
if saveDI {
|
||||
self.save(_DI)
|
||||
}
|
||||
self.Emit("LEAQ", rec, _DI)
|
||||
self.Emit("MOVQ", _F_gcWriteBarrierAX, _R10) // MOVQ ${fn}, AX
|
||||
self.Rjmp("CALL", _R10)
|
||||
if saveDI {
|
||||
self.load(_DI)
|
||||
}
|
||||
self.Sjmp("JMP", "_end_writeBarrier" + strconv.Itoa(i) + "_{n}")
|
||||
self.Link("_no_writeBarrier" + strconv.Itoa(i) + "_{n}")
|
||||
self.Emit("MOVQ", _AX, rec)
|
||||
self.Link("_end_writeBarrier" + strconv.Itoa(i) + "_{n}")
|
||||
}
|
||||
|
||||
func (self *_ValueDecoder) WriteRecNotAX(i int, ptr obj.Addr, rec obj.Addr, saveDI bool) {
|
||||
if rec.Reg == x86.REG_AX || rec.Index == x86.REG_AX {
|
||||
panic("rec contains AX!")
|
||||
}
|
||||
self.Emit("MOVQ", _V_writeBarrier, _R10)
|
||||
self.Emit("CMPL", jit.Ptr(_R10, 0), jit.Imm(0))
|
||||
self.Sjmp("JE", "_no_writeBarrier" + strconv.Itoa(i) + "_{n}")
|
||||
self.Emit("MOVQ", ptr, _AX)
|
||||
if saveDI {
|
||||
self.save(_DI)
|
||||
}
|
||||
self.Emit("LEAQ", rec, _DI)
|
||||
self.Emit("MOVQ", _F_gcWriteBarrierAX, _R10) // MOVQ ${fn}, AX
|
||||
self.Rjmp("CALL", _R10)
|
||||
if saveDI {
|
||||
self.load(_DI)
|
||||
}
|
||||
self.Sjmp("JMP", "_end_writeBarrier" + strconv.Itoa(i) + "_{n}")
|
||||
self.Link("_no_writeBarrier" + strconv.Itoa(i) + "_{n}")
|
||||
self.Emit("MOVQ", ptr, rec)
|
||||
self.Link("_end_writeBarrier" + strconv.Itoa(i) + "_{n}")
|
||||
}
|
||||
|
||||
/** Generic Decoder **/
|
||||
|
||||
var (
|
||||
_subr_decode_value = new(_ValueDecoder).build()
|
||||
)
|
||||
|
||||
//go:nosplit
|
||||
func invalid_vtype(vt types.ValueType) {
|
||||
throw(fmt.Sprintf("invalid value type: %d", vt))
|
||||
}
|
||||
772
vendor/github.com/bytedance/sonic/internal/decoder/generic_amd64_go117.go
generated
vendored
Normal file
772
vendor/github.com/bytedance/sonic/internal/decoder/generic_amd64_go117.go
generated
vendored
Normal file
@@ -0,0 +1,772 @@
|
||||
//go:build go1.17 && !go1.21
|
||||
// +build go1.17,!go1.21
|
||||
|
||||
/*
|
||||
* 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 decoder
|
||||
|
||||
import (
|
||||
`encoding/json`
|
||||
`fmt`
|
||||
`reflect`
|
||||
`strconv`
|
||||
|
||||
`github.com/bytedance/sonic/internal/jit`
|
||||
`github.com/bytedance/sonic/internal/native`
|
||||
`github.com/bytedance/sonic/internal/native/types`
|
||||
`github.com/twitchyliquid64/golang-asm/obj`
|
||||
`github.com/twitchyliquid64/golang-asm/obj/x86`
|
||||
)
|
||||
|
||||
/** Crucial Registers:
|
||||
*
|
||||
* ST(R13) && 0(SP) : ro, decoder stack
|
||||
* DF(AX) : ro, decoder flags
|
||||
* EP(BX) : wo, error pointer
|
||||
* IP(R10) : ro, input pointer
|
||||
* IL(R12) : ro, input length
|
||||
* IC(R11) : rw, input cursor
|
||||
* VP(R15) : ro, value pointer (to an interface{})
|
||||
*/
|
||||
|
||||
const (
|
||||
_VD_args = 8 // 8 bytes for passing arguments to this functions
|
||||
_VD_fargs = 64 // 64 bytes for passing arguments to other Go functions
|
||||
_VD_saves = 48 // 48 bytes for saving the registers before CALL instructions
|
||||
_VD_locals = 96 // 96 bytes for local variables
|
||||
)
|
||||
|
||||
const (
|
||||
_VD_offs = _VD_fargs + _VD_saves + _VD_locals
|
||||
_VD_size = _VD_offs + 8 // 8 bytes for the parent frame pointer
|
||||
)
|
||||
|
||||
var (
|
||||
_VAR_ss = _VAR_ss_Vt
|
||||
_VAR_df = jit.Ptr(_SP, _VD_fargs + _VD_saves)
|
||||
)
|
||||
|
||||
var (
|
||||
_VAR_ss_Vt = jit.Ptr(_SP, _VD_fargs + _VD_saves + 8)
|
||||
_VAR_ss_Dv = jit.Ptr(_SP, _VD_fargs + _VD_saves + 16)
|
||||
_VAR_ss_Iv = jit.Ptr(_SP, _VD_fargs + _VD_saves + 24)
|
||||
_VAR_ss_Ep = jit.Ptr(_SP, _VD_fargs + _VD_saves + 32)
|
||||
_VAR_ss_Db = jit.Ptr(_SP, _VD_fargs + _VD_saves + 40)
|
||||
_VAR_ss_Dc = jit.Ptr(_SP, _VD_fargs + _VD_saves + 48)
|
||||
)
|
||||
|
||||
var (
|
||||
_VAR_R9 = jit.Ptr(_SP, _VD_fargs + _VD_saves + 56)
|
||||
)
|
||||
type _ValueDecoder struct {
|
||||
jit.BaseAssembler
|
||||
}
|
||||
|
||||
var (
|
||||
_VAR_cs_LR = jit.Ptr(_SP, _VD_fargs + _VD_saves + 64)
|
||||
_VAR_cs_p = jit.Ptr(_SP, _VD_fargs + _VD_saves + 72)
|
||||
_VAR_cs_n = jit.Ptr(_SP, _VD_fargs + _VD_saves + 80)
|
||||
_VAR_cs_d = jit.Ptr(_SP, _VD_fargs + _VD_saves + 88)
|
||||
)
|
||||
|
||||
func (self *_ValueDecoder) build() uintptr {
|
||||
self.Init(self.compile)
|
||||
return *(*uintptr)(self.Load("decode_value", _VD_size, _VD_args, argPtrs_generic, localPtrs_generic))
|
||||
}
|
||||
|
||||
/** Function Calling Helpers **/
|
||||
|
||||
func (self *_ValueDecoder) save(r ...obj.Addr) {
|
||||
for i, v := range r {
|
||||
if i > _VD_saves / 8 - 1 {
|
||||
panic("too many registers to save")
|
||||
} else {
|
||||
self.Emit("MOVQ", v, jit.Ptr(_SP, _VD_fargs + int64(i) * 8))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (self *_ValueDecoder) load(r ...obj.Addr) {
|
||||
for i, v := range r {
|
||||
if i > _VD_saves / 8 - 1 {
|
||||
panic("too many registers to load")
|
||||
} else {
|
||||
self.Emit("MOVQ", jit.Ptr(_SP, _VD_fargs + int64(i) * 8), v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (self *_ValueDecoder) call(fn obj.Addr) {
|
||||
self.Emit("MOVQ", fn, _R9) // MOVQ ${fn}, AX
|
||||
self.Rjmp("CALL", _R9) // CALL AX
|
||||
}
|
||||
|
||||
func (self *_ValueDecoder) call_go(fn obj.Addr) {
|
||||
self.save(_REG_go...) // SAVE $REG_go
|
||||
self.call(fn) // CALL ${fn}
|
||||
self.load(_REG_go...) // LOAD $REG_go
|
||||
}
|
||||
|
||||
func (self *_ValueDecoder) callc(fn obj.Addr) {
|
||||
self.Emit("XCHGQ", _IP, _BP)
|
||||
self.call(fn)
|
||||
self.Emit("XCHGQ", _IP, _BP)
|
||||
}
|
||||
|
||||
func (self *_ValueDecoder) call_c(fn obj.Addr) {
|
||||
self.Emit("XCHGQ", _IC, _BX)
|
||||
self.callc(fn)
|
||||
self.Emit("XCHGQ", _IC, _BX)
|
||||
}
|
||||
|
||||
/** Decoder Assembler **/
|
||||
|
||||
const (
|
||||
_S_val = iota + 1
|
||||
_S_arr
|
||||
_S_arr_0
|
||||
_S_obj
|
||||
_S_obj_0
|
||||
_S_obj_delim
|
||||
_S_obj_sep
|
||||
)
|
||||
|
||||
const (
|
||||
_S_omask_key = (1 << _S_obj_0) | (1 << _S_obj_sep)
|
||||
_S_omask_end = (1 << _S_obj_0) | (1 << _S_obj)
|
||||
_S_vmask = (1 << _S_val) | (1 << _S_arr_0)
|
||||
)
|
||||
|
||||
const (
|
||||
_A_init_len = 1
|
||||
_A_init_cap = 16
|
||||
)
|
||||
|
||||
const (
|
||||
_ST_Sp = 0
|
||||
_ST_Vt = _PtrBytes
|
||||
_ST_Vp = _PtrBytes * (types.MAX_RECURSE + 1)
|
||||
)
|
||||
|
||||
var (
|
||||
_V_true = jit.Imm(int64(pbool(true)))
|
||||
_V_false = jit.Imm(int64(pbool(false)))
|
||||
_F_value = jit.Imm(int64(native.S_value))
|
||||
)
|
||||
|
||||
var (
|
||||
_V_max = jit.Imm(int64(types.V_MAX))
|
||||
_E_eof = jit.Imm(int64(types.ERR_EOF))
|
||||
_E_invalid = jit.Imm(int64(types.ERR_INVALID_CHAR))
|
||||
_E_recurse = jit.Imm(int64(types.ERR_RECURSE_EXCEED_MAX))
|
||||
)
|
||||
|
||||
var (
|
||||
_F_convTslice = jit.Func(convTslice)
|
||||
_F_convTstring = jit.Func(convTstring)
|
||||
_F_invalid_vtype = jit.Func(invalid_vtype)
|
||||
)
|
||||
|
||||
var (
|
||||
_T_map = jit.Type(reflect.TypeOf((map[string]interface{})(nil)))
|
||||
_T_bool = jit.Type(reflect.TypeOf(false))
|
||||
_T_int64 = jit.Type(reflect.TypeOf(int64(0)))
|
||||
_T_eface = jit.Type(reflect.TypeOf((*interface{})(nil)).Elem())
|
||||
_T_slice = jit.Type(reflect.TypeOf(([]interface{})(nil)))
|
||||
_T_string = jit.Type(reflect.TypeOf(""))
|
||||
_T_number = jit.Type(reflect.TypeOf(json.Number("")))
|
||||
_T_float64 = jit.Type(reflect.TypeOf(float64(0)))
|
||||
)
|
||||
|
||||
var _R_tab = map[int]string {
|
||||
'[': "_decode_V_ARRAY",
|
||||
'{': "_decode_V_OBJECT",
|
||||
':': "_decode_V_KEY_SEP",
|
||||
',': "_decode_V_ELEM_SEP",
|
||||
']': "_decode_V_ARRAY_END",
|
||||
'}': "_decode_V_OBJECT_END",
|
||||
}
|
||||
|
||||
func (self *_ValueDecoder) compile() {
|
||||
self.Emit("SUBQ", jit.Imm(_VD_size), _SP) // SUBQ $_VD_size, SP
|
||||
self.Emit("MOVQ", _BP, jit.Ptr(_SP, _VD_offs)) // MOVQ BP, _VD_offs(SP)
|
||||
self.Emit("LEAQ", jit.Ptr(_SP, _VD_offs), _BP) // LEAQ _VD_offs(SP), BP
|
||||
|
||||
/* initialize the state machine */
|
||||
self.Emit("XORL", _CX, _CX) // XORL CX, CX
|
||||
self.Emit("MOVQ", _DF, _VAR_df) // MOVQ DF, df
|
||||
/* initialize digital buffer first */
|
||||
self.Emit("MOVQ", jit.Imm(_MaxDigitNums), _VAR_ss_Dc) // MOVQ $_MaxDigitNums, ss.Dcap
|
||||
self.Emit("LEAQ", jit.Ptr(_ST, _DbufOffset), _AX) // LEAQ _DbufOffset(ST), AX
|
||||
self.Emit("MOVQ", _AX, _VAR_ss_Db) // MOVQ AX, ss.Dbuf
|
||||
/* add ST offset */
|
||||
self.Emit("ADDQ", jit.Imm(_FsmOffset), _ST) // ADDQ _FsmOffset, _ST
|
||||
self.Emit("MOVQ", _CX, jit.Ptr(_ST, _ST_Sp)) // MOVQ CX, ST.Sp
|
||||
self.WriteRecNotAX(0, _VP, jit.Ptr(_ST, _ST_Vp), false) // MOVQ VP, ST.Vp[0]
|
||||
self.Emit("MOVQ", jit.Imm(_S_val), jit.Ptr(_ST, _ST_Vt)) // MOVQ _S_val, ST.Vt[0]
|
||||
self.Sjmp("JMP" , "_next") // JMP _next
|
||||
|
||||
/* set the value from previous round */
|
||||
self.Link("_set_value") // _set_value:
|
||||
self.Emit("MOVL" , jit.Imm(_S_vmask), _DX) // MOVL _S_vmask, DX
|
||||
self.Emit("MOVQ" , jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX
|
||||
self.Emit("MOVQ" , jit.Sib(_ST, _CX, 8, _ST_Vt), _AX) // MOVQ ST.Vt[CX], AX
|
||||
self.Emit("BTQ" , _AX, _DX) // BTQ AX, DX
|
||||
self.Sjmp("JNC" , "_vtype_error") // JNC _vtype_error
|
||||
self.Emit("XORL" , _SI, _SI) // XORL SI, SI
|
||||
self.Emit("SUBQ" , jit.Imm(1), jit.Ptr(_ST, _ST_Sp)) // SUBQ $1, ST.Sp
|
||||
self.Emit("XCHGQ", jit.Sib(_ST, _CX, 8, _ST_Vp), _SI) // XCHGQ ST.Vp[CX], SI
|
||||
self.Emit("MOVQ" , _R8, jit.Ptr(_SI, 0)) // MOVQ R8, (SI)
|
||||
self.WriteRecNotAX(1, _R9, jit.Ptr(_SI, 8), false) // MOVQ R9, 8(SI)
|
||||
|
||||
/* check for value stack */
|
||||
self.Link("_next") // _next:
|
||||
self.Emit("MOVQ" , jit.Ptr(_ST, _ST_Sp), _AX) // MOVQ ST.Sp, AX
|
||||
self.Emit("TESTQ", _AX, _AX) // TESTQ AX, AX
|
||||
self.Sjmp("JS" , "_return") // JS _return
|
||||
|
||||
/* fast path: test up to 4 characters manually */
|
||||
self.Emit("CMPQ" , _IC, _IL) // CMPQ IC, IL
|
||||
self.Sjmp("JAE" , "_decode_V_EOF") // JAE _decode_V_EOF
|
||||
self.Emit("MOVBQZX", jit.Sib(_IP, _IC, 1, 0), _AX) // MOVBQZX (IP)(IC), AX
|
||||
self.Emit("MOVQ" , jit.Imm(_BM_space), _DX) // MOVQ _BM_space, DX
|
||||
self.Emit("CMPQ" , _AX, jit.Imm(' ')) // CMPQ AX, $' '
|
||||
self.Sjmp("JA" , "_decode_fast") // JA _decode_fast
|
||||
self.Emit("BTQ" , _AX, _DX) // BTQ _AX, _DX
|
||||
self.Sjmp("JNC" , "_decode_fast") // JNC _decode_fast
|
||||
self.Emit("ADDQ" , jit.Imm(1), _IC) // ADDQ $1, IC
|
||||
|
||||
/* at least 1 to 3 spaces */
|
||||
for i := 0; i < 3; i++ {
|
||||
self.Emit("CMPQ" , _IC, _IL) // CMPQ IC, IL
|
||||
self.Sjmp("JAE" , "_decode_V_EOF") // JAE _decode_V_EOF
|
||||
self.Emit("MOVBQZX", jit.Sib(_IP, _IC, 1, 0), _AX) // MOVBQZX (IP)(IC), AX
|
||||
self.Emit("CMPQ" , _AX, jit.Imm(' ')) // CMPQ AX, $' '
|
||||
self.Sjmp("JA" , "_decode_fast") // JA _decode_fast
|
||||
self.Emit("BTQ" , _AX, _DX) // BTQ _AX, _DX
|
||||
self.Sjmp("JNC" , "_decode_fast") // JNC _decode_fast
|
||||
self.Emit("ADDQ" , jit.Imm(1), _IC) // ADDQ $1, IC
|
||||
}
|
||||
|
||||
/* at least 4 spaces */
|
||||
self.Emit("CMPQ" , _IC, _IL) // CMPQ IC, IL
|
||||
self.Sjmp("JAE" , "_decode_V_EOF") // JAE _decode_V_EOF
|
||||
self.Emit("MOVBQZX", jit.Sib(_IP, _IC, 1, 0), _AX) // MOVBQZX (IP)(IC), AX
|
||||
|
||||
/* fast path: use lookup table to select decoder */
|
||||
self.Link("_decode_fast") // _decode_fast:
|
||||
self.Byte(0x48, 0x8d, 0x3d) // LEAQ ?(PC), DI
|
||||
self.Sref("_decode_tab", 4) // .... &_decode_tab
|
||||
self.Emit("MOVLQSX", jit.Sib(_DI, _AX, 4, 0), _AX) // MOVLQSX (DI)(AX*4), AX
|
||||
self.Emit("TESTQ" , _AX, _AX) // TESTQ AX, AX
|
||||
self.Sjmp("JZ" , "_decode_native") // JZ _decode_native
|
||||
self.Emit("ADDQ" , jit.Imm(1), _IC) // ADDQ $1, IC
|
||||
self.Emit("ADDQ" , _DI, _AX) // ADDQ DI, AX
|
||||
self.Rjmp("JMP" , _AX) // JMP AX
|
||||
|
||||
/* decode with native decoder */
|
||||
self.Link("_decode_native") // _decode_native:
|
||||
self.Emit("MOVQ", _IP, _DI) // MOVQ IP, DI
|
||||
self.Emit("MOVQ", _IL, _SI) // MOVQ IL, SI
|
||||
self.Emit("MOVQ", _IC, _DX) // MOVQ IC, DX
|
||||
self.Emit("LEAQ", _VAR_ss, _CX) // LEAQ ss, CX
|
||||
self.Emit("MOVQ", _VAR_df, _R8) // MOVQ $df, R8
|
||||
self.Emit("BTSQ", jit.Imm(_F_allow_control), _R8) // ANDQ $1<<_F_allow_control, R8
|
||||
self.callc(_F_value) // CALL value
|
||||
self.Emit("MOVQ", _AX, _IC) // MOVQ AX, IC
|
||||
|
||||
/* check for errors */
|
||||
self.Emit("MOVQ" , _VAR_ss_Vt, _AX) // MOVQ ss.Vt, AX
|
||||
self.Emit("TESTQ", _AX, _AX) // TESTQ AX, AX
|
||||
self.Sjmp("JS" , "_parsing_error")
|
||||
self.Sjmp("JZ" , "_invalid_vtype") // JZ _invalid_vtype
|
||||
self.Emit("CMPQ" , _AX, _V_max) // CMPQ AX, _V_max
|
||||
self.Sjmp("JA" , "_invalid_vtype") // JA _invalid_vtype
|
||||
|
||||
/* jump table selector */
|
||||
self.Byte(0x48, 0x8d, 0x3d) // LEAQ ?(PC), DI
|
||||
self.Sref("_switch_table", 4) // .... &_switch_table
|
||||
self.Emit("MOVLQSX", jit.Sib(_DI, _AX, 4, -4), _AX) // MOVLQSX -4(DI)(AX*4), AX
|
||||
self.Emit("ADDQ" , _DI, _AX) // ADDQ DI, AX
|
||||
self.Rjmp("JMP" , _AX) // JMP AX
|
||||
|
||||
/** V_EOF **/
|
||||
self.Link("_decode_V_EOF") // _decode_V_EOF:
|
||||
self.Emit("MOVL", _E_eof, _EP) // MOVL _E_eof, EP
|
||||
self.Sjmp("JMP" , "_error") // JMP _error
|
||||
|
||||
/** V_NULL **/
|
||||
self.Link("_decode_V_NULL") // _decode_V_NULL:
|
||||
self.Emit("XORL", _R8, _R8) // XORL R8, R8
|
||||
self.Emit("XORL", _R9, _R9) // XORL R9, R9
|
||||
self.Emit("LEAQ", jit.Ptr(_IC, -4), _DI) // LEAQ -4(IC), DI
|
||||
self.Sjmp("JMP" , "_set_value") // JMP _set_value
|
||||
|
||||
/** V_TRUE **/
|
||||
self.Link("_decode_V_TRUE") // _decode_V_TRUE:
|
||||
self.Emit("MOVQ", _T_bool, _R8) // MOVQ _T_bool, R8
|
||||
// TODO: maybe modified by users?
|
||||
self.Emit("MOVQ", _V_true, _R9) // MOVQ _V_true, R9
|
||||
self.Emit("LEAQ", jit.Ptr(_IC, -4), _DI) // LEAQ -4(IC), DI
|
||||
self.Sjmp("JMP" , "_set_value") // JMP _set_value
|
||||
|
||||
/** V_FALSE **/
|
||||
self.Link("_decode_V_FALSE") // _decode_V_FALSE:
|
||||
self.Emit("MOVQ", _T_bool, _R8) // MOVQ _T_bool, R8
|
||||
self.Emit("MOVQ", _V_false, _R9) // MOVQ _V_false, R9
|
||||
self.Emit("LEAQ", jit.Ptr(_IC, -5), _DI) // LEAQ -5(IC), DI
|
||||
self.Sjmp("JMP" , "_set_value") // JMP _set_value
|
||||
|
||||
/** V_ARRAY **/
|
||||
self.Link("_decode_V_ARRAY") // _decode_V_ARRAY
|
||||
self.Emit("MOVL", jit.Imm(_S_vmask), _DX) // MOVL _S_vmask, DX
|
||||
self.Emit("MOVQ", jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX
|
||||
self.Emit("MOVQ", jit.Sib(_ST, _CX, 8, _ST_Vt), _AX) // MOVQ ST.Vt[CX], AX
|
||||
self.Emit("BTQ" , _AX, _DX) // BTQ AX, DX
|
||||
self.Sjmp("JNC" , "_invalid_char") // JNC _invalid_char
|
||||
|
||||
/* create a new array */
|
||||
self.Emit("MOVQ", _T_eface, _AX) // MOVQ _T_eface, AX
|
||||
self.Emit("MOVQ", jit.Imm(_A_init_len), _BX) // MOVQ _A_init_len, BX
|
||||
self.Emit("MOVQ", jit.Imm(_A_init_cap), _CX) // MOVQ _A_init_cap, CX
|
||||
self.call_go(_F_makeslice) // CALL_GO runtime.makeslice
|
||||
|
||||
/* pack into an interface */
|
||||
self.Emit("MOVQ", jit.Imm(_A_init_len), _BX) // MOVQ _A_init_len, BX
|
||||
self.Emit("MOVQ", jit.Imm(_A_init_cap), _CX) // MOVQ _A_init_cap, CX
|
||||
self.call_go(_F_convTslice) // CALL_GO runtime.convTslice
|
||||
self.Emit("MOVQ", _AX, _R8) // MOVQ AX, R8
|
||||
|
||||
/* replace current state with an array */
|
||||
self.Emit("MOVQ", jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX
|
||||
self.Emit("MOVQ", jit.Sib(_ST, _CX, 8, _ST_Vp), _SI) // MOVQ ST.Vp[CX], SI
|
||||
self.Emit("MOVQ", jit.Imm(_S_arr), jit.Sib(_ST, _CX, 8, _ST_Vt)) // MOVQ _S_arr, ST.Vt[CX]
|
||||
self.Emit("MOVQ", _T_slice, _AX) // MOVQ _T_slice, AX
|
||||
self.Emit("MOVQ", _AX, jit.Ptr(_SI, 0)) // MOVQ AX, (SI)
|
||||
self.WriteRecNotAX(2, _R8, jit.Ptr(_SI, 8), false) // MOVQ R8, 8(SI)
|
||||
|
||||
/* add a new slot for the first element */
|
||||
self.Emit("ADDQ", jit.Imm(1), _CX) // ADDQ $1, CX
|
||||
self.Emit("CMPQ", _CX, jit.Imm(types.MAX_RECURSE)) // CMPQ CX, ${types.MAX_RECURSE}
|
||||
self.Sjmp("JAE" , "_stack_overflow") // JA _stack_overflow
|
||||
self.Emit("MOVQ", jit.Ptr(_R8, 0), _AX) // MOVQ (R8), AX
|
||||
self.Emit("MOVQ", _CX, jit.Ptr(_ST, _ST_Sp)) // MOVQ CX, ST.Sp
|
||||
self.WritePtrAX(3, jit.Sib(_ST, _CX, 8, _ST_Vp), false) // MOVQ AX, ST.Vp[CX]
|
||||
self.Emit("MOVQ", jit.Imm(_S_arr_0), jit.Sib(_ST, _CX, 8, _ST_Vt)) // MOVQ _S_arr_0, ST.Vt[CX]
|
||||
self.Sjmp("JMP" , "_next") // JMP _next
|
||||
|
||||
/** V_OBJECT **/
|
||||
self.Link("_decode_V_OBJECT") // _decode_V_OBJECT:
|
||||
self.Emit("MOVL", jit.Imm(_S_vmask), _DX) // MOVL _S_vmask, DX
|
||||
self.Emit("MOVQ", jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX
|
||||
self.Emit("MOVQ", jit.Sib(_ST, _CX, 8, _ST_Vt), _AX) // MOVQ ST.Vt[CX], AX
|
||||
self.Emit("BTQ" , _AX, _DX) // BTQ AX, DX
|
||||
self.Sjmp("JNC" , "_invalid_char") // JNC _invalid_char
|
||||
self.call_go(_F_makemap_small) // CALL_GO runtime.makemap_small
|
||||
self.Emit("MOVQ", jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX
|
||||
self.Emit("MOVQ", jit.Imm(_S_obj_0), jit.Sib(_ST, _CX, 8, _ST_Vt)) // MOVQ _S_obj_0, ST.Vt[CX]
|
||||
self.Emit("MOVQ", jit.Sib(_ST, _CX, 8, _ST_Vp), _SI) // MOVQ ST.Vp[CX], SI
|
||||
self.Emit("MOVQ", _T_map, _DX) // MOVQ _T_map, DX
|
||||
self.Emit("MOVQ", _DX, jit.Ptr(_SI, 0)) // MOVQ DX, (SI)
|
||||
self.WritePtrAX(4, jit.Ptr(_SI, 8), false) // MOVQ AX, 8(SI)
|
||||
self.Sjmp("JMP" , "_next") // JMP _next
|
||||
|
||||
/** V_STRING **/
|
||||
self.Link("_decode_V_STRING") // _decode_V_STRING:
|
||||
self.Emit("MOVQ", _VAR_ss_Iv, _CX) // MOVQ ss.Iv, CX
|
||||
self.Emit("MOVQ", _IC, _AX) // MOVQ IC, AX
|
||||
self.Emit("SUBQ", _CX, _AX) // SUBQ CX, AX
|
||||
|
||||
/* check for escapes */
|
||||
self.Emit("CMPQ", _VAR_ss_Ep, jit.Imm(-1)) // CMPQ ss.Ep, $-1
|
||||
self.Sjmp("JNE" , "_unquote") // JNE _unquote
|
||||
self.Emit("SUBQ", jit.Imm(1), _AX) // SUBQ $1, AX
|
||||
self.Emit("LEAQ", jit.Sib(_IP, _CX, 1, 0), _R8) // LEAQ (IP)(CX), R8
|
||||
self.Byte(0x48, 0x8d, 0x3d) // LEAQ (PC), DI
|
||||
self.Sref("_copy_string_end", 4)
|
||||
self.Emit("BTQ", jit.Imm(_F_copy_string), _VAR_df)
|
||||
self.Sjmp("JC", "copy_string")
|
||||
self.Link("_copy_string_end")
|
||||
self.Emit("XORL", _DX, _DX)
|
||||
|
||||
/* strings with no escape sequences */
|
||||
self.Link("_noescape") // _noescape:
|
||||
self.Emit("MOVL", jit.Imm(_S_omask_key), _DI) // MOVL _S_omask, DI
|
||||
self.Emit("MOVQ", jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX
|
||||
self.Emit("MOVQ", jit.Sib(_ST, _CX, 8, _ST_Vt), _SI) // MOVQ ST.Vt[CX], SI
|
||||
self.Emit("BTQ" , _SI, _DI) // BTQ SI, DI
|
||||
self.Sjmp("JC" , "_object_key") // JC _object_key
|
||||
|
||||
/* check for pre-packed strings, avoid 1 allocation */
|
||||
self.Emit("TESTQ", _DX, _DX) // TESTQ DX, DX
|
||||
self.Sjmp("JNZ" , "_packed_str") // JNZ _packed_str
|
||||
self.Emit("MOVQ" , _AX, _BX) // MOVQ AX, BX
|
||||
self.Emit("MOVQ" , _R8, _AX) // MOVQ R8, AX
|
||||
self.call_go(_F_convTstring) // CALL_GO runtime.convTstring
|
||||
self.Emit("MOVQ" , _AX, _R9) // MOVQ AX, R9
|
||||
|
||||
/* packed string already in R9 */
|
||||
self.Link("_packed_str") // _packed_str:
|
||||
self.Emit("MOVQ", _T_string, _R8) // MOVQ _T_string, R8
|
||||
self.Emit("MOVQ", _VAR_ss_Iv, _DI) // MOVQ ss.Iv, DI
|
||||
self.Emit("SUBQ", jit.Imm(1), _DI) // SUBQ $1, DI
|
||||
self.Sjmp("JMP" , "_set_value") // JMP _set_value
|
||||
|
||||
/* the string is an object key, get the map */
|
||||
self.Link("_object_key")
|
||||
self.Emit("MOVQ", jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX
|
||||
self.Emit("MOVQ", jit.Sib(_ST, _CX, 8, _ST_Vp), _SI) // MOVQ ST.Vp[CX], SI
|
||||
self.Emit("MOVQ", jit.Ptr(_SI, 8), _SI) // MOVQ 8(SI), SI
|
||||
|
||||
/* add a new delimiter */
|
||||
self.Emit("ADDQ", jit.Imm(1), _CX) // ADDQ $1, CX
|
||||
self.Emit("CMPQ", _CX, jit.Imm(types.MAX_RECURSE)) // CMPQ CX, ${types.MAX_RECURSE}
|
||||
self.Sjmp("JAE" , "_stack_overflow") // JA _stack_overflow
|
||||
self.Emit("MOVQ", _CX, jit.Ptr(_ST, _ST_Sp)) // MOVQ CX, ST.Sp
|
||||
self.Emit("MOVQ", jit.Imm(_S_obj_delim), jit.Sib(_ST, _CX, 8, _ST_Vt)) // MOVQ _S_obj_delim, ST.Vt[CX]
|
||||
|
||||
/* add a new slot int the map */
|
||||
self.Emit("MOVQ", _AX, _DI) // MOVQ AX, DI
|
||||
self.Emit("MOVQ", _T_map, _AX) // MOVQ _T_map, AX
|
||||
self.Emit("MOVQ", _SI, _BX) // MOVQ SI, BX
|
||||
self.Emit("MOVQ", _R8, _CX) // MOVQ R9, CX
|
||||
self.call_go(_F_mapassign_faststr) // CALL_GO runtime.mapassign_faststr
|
||||
|
||||
/* add to the pointer stack */
|
||||
self.Emit("MOVQ", jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX
|
||||
self.WritePtrAX(6, jit.Sib(_ST, _CX, 8, _ST_Vp), false) // MOVQ AX, ST.Vp[CX]
|
||||
self.Sjmp("JMP" , "_next") // JMP _next
|
||||
|
||||
/* allocate memory to store the string header and unquoted result */
|
||||
self.Link("_unquote") // _unquote:
|
||||
self.Emit("ADDQ", jit.Imm(15), _AX) // ADDQ $15, AX
|
||||
self.Emit("MOVQ", _T_byte, _BX) // MOVQ _T_byte, BX
|
||||
self.Emit("MOVB", jit.Imm(0), _CX) // MOVB $0, CX
|
||||
self.call_go(_F_mallocgc) // CALL_GO runtime.mallocgc
|
||||
self.Emit("MOVQ", _AX, _R9) // MOVQ AX, R9
|
||||
|
||||
/* prepare the unquoting parameters */
|
||||
self.Emit("MOVQ" , _VAR_ss_Iv, _CX) // MOVQ ss.Iv, CX
|
||||
self.Emit("LEAQ" , jit.Sib(_IP, _CX, 1, 0), _DI) // LEAQ (IP)(CX), DI
|
||||
self.Emit("NEGQ" , _CX) // NEGQ CX
|
||||
self.Emit("LEAQ" , jit.Sib(_IC, _CX, 1, -1), _SI) // LEAQ -1(IC)(CX), SI
|
||||
self.Emit("LEAQ" , jit.Ptr(_R9, 16), _DX) // LEAQ 16(R8), DX
|
||||
self.Emit("LEAQ" , _VAR_ss_Ep, _CX) // LEAQ ss.Ep, CX
|
||||
self.Emit("XORL" , _R8, _R8) // XORL R8, R8
|
||||
self.Emit("BTQ" , jit.Imm(_F_disable_urc), _VAR_df) // BTQ ${_F_disable_urc}, fv
|
||||
self.Emit("SETCC", _R8) // SETCC R8
|
||||
self.Emit("SHLQ" , jit.Imm(types.B_UNICODE_REPLACE), _R8) // SHLQ ${types.B_UNICODE_REPLACE}, R8
|
||||
|
||||
/* unquote the string, with R9 been preserved */
|
||||
self.Emit("MOVQ", _R9, _VAR_R9) // SAVE R9
|
||||
self.call_c(_F_unquote) // CALL unquote
|
||||
self.Emit("MOVQ", _VAR_R9, _R9) // LOAD R9
|
||||
|
||||
/* check for errors */
|
||||
self.Emit("TESTQ", _AX, _AX) // TESTQ AX, AX
|
||||
self.Sjmp("JS" , "_unquote_error") // JS _unquote_error
|
||||
self.Emit("MOVL" , jit.Imm(1), _DX) // MOVL $1, DX
|
||||
self.Emit("LEAQ" , jit.Ptr(_R9, 16), _R8) // ADDQ $16, R8
|
||||
self.Emit("MOVQ" , _R8, jit.Ptr(_R9, 0)) // MOVQ R8, (R9)
|
||||
self.Emit("MOVQ" , _AX, jit.Ptr(_R9, 8)) // MOVQ AX, 8(R9)
|
||||
self.Sjmp("JMP" , "_noescape") // JMP _noescape
|
||||
|
||||
/** V_DOUBLE **/
|
||||
self.Link("_decode_V_DOUBLE") // _decode_V_DOUBLE:
|
||||
self.Emit("BTQ" , jit.Imm(_F_use_number), _VAR_df) // BTQ _F_use_number, df
|
||||
self.Sjmp("JC" , "_use_number") // JC _use_number
|
||||
self.Emit("MOVSD", _VAR_ss_Dv, _X0) // MOVSD ss.Dv, X0
|
||||
self.Sjmp("JMP" , "_use_float64") // JMP _use_float64
|
||||
|
||||
/** V_INTEGER **/
|
||||
self.Link("_decode_V_INTEGER") // _decode_V_INTEGER:
|
||||
self.Emit("BTQ" , jit.Imm(_F_use_number), _VAR_df) // BTQ _F_use_number, df
|
||||
self.Sjmp("JC" , "_use_number") // JC _use_number
|
||||
self.Emit("BTQ" , jit.Imm(_F_use_int64), _VAR_df) // BTQ _F_use_int64, df
|
||||
self.Sjmp("JC" , "_use_int64") // JC _use_int64
|
||||
//TODO: use ss.Dv directly
|
||||
self.Emit("MOVSD", _VAR_ss_Dv, _X0) // MOVSD ss.Dv, X0
|
||||
|
||||
/* represent numbers as `float64` */
|
||||
self.Link("_use_float64") // _use_float64:
|
||||
self.Emit("MOVQ" , _X0, _AX) // MOVQ X0, AX
|
||||
self.call_go(_F_convT64) // CALL_GO runtime.convT64
|
||||
self.Emit("MOVQ" , _T_float64, _R8) // MOVQ _T_float64, R8
|
||||
self.Emit("MOVQ" , _AX, _R9) // MOVQ AX, R9
|
||||
self.Emit("MOVQ" , _VAR_ss_Ep, _DI) // MOVQ ss.Ep, DI
|
||||
self.Sjmp("JMP" , "_set_value") // JMP _set_value
|
||||
|
||||
/* represent numbers as `json.Number` */
|
||||
self.Link("_use_number") // _use_number
|
||||
self.Emit("MOVQ", _VAR_ss_Ep, _AX) // MOVQ ss.Ep, AX
|
||||
self.Emit("LEAQ", jit.Sib(_IP, _AX, 1, 0), _SI) // LEAQ (IP)(AX), SI
|
||||
self.Emit("MOVQ", _IC, _CX) // MOVQ IC, CX
|
||||
self.Emit("SUBQ", _AX, _CX) // SUBQ AX, CX
|
||||
self.Emit("MOVQ", _SI, _AX) // MOVQ SI, AX
|
||||
self.Emit("MOVQ", _CX, _BX) // MOVQ CX, BX
|
||||
self.call_go(_F_convTstring) // CALL_GO runtime.convTstring
|
||||
self.Emit("MOVQ", _T_number, _R8) // MOVQ _T_number, R8
|
||||
self.Emit("MOVQ", _AX, _R9) // MOVQ AX, R9
|
||||
self.Emit("MOVQ", _VAR_ss_Ep, _DI) // MOVQ ss.Ep, DI
|
||||
self.Sjmp("JMP" , "_set_value") // JMP _set_value
|
||||
|
||||
/* represent numbers as `int64` */
|
||||
self.Link("_use_int64") // _use_int64:
|
||||
self.Emit("MOVQ", _VAR_ss_Iv, _AX) // MOVQ ss.Iv, AX
|
||||
self.call_go(_F_convT64) // CALL_GO runtime.convT64
|
||||
self.Emit("MOVQ", _T_int64, _R8) // MOVQ _T_int64, R8
|
||||
self.Emit("MOVQ", _AX, _R9) // MOVQ AX, R9
|
||||
self.Emit("MOVQ", _VAR_ss_Ep, _DI) // MOVQ ss.Ep, DI
|
||||
self.Sjmp("JMP" , "_set_value") // JMP _set_value
|
||||
|
||||
/** V_KEY_SEP **/
|
||||
self.Link("_decode_V_KEY_SEP") // _decode_V_KEY_SEP:
|
||||
self.Emit("MOVQ", jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX
|
||||
self.Emit("MOVQ", jit.Sib(_ST, _CX, 8, _ST_Vt), _AX) // MOVQ ST.Vt[CX], AX
|
||||
self.Emit("CMPQ", _AX, jit.Imm(_S_obj_delim)) // CMPQ AX, _S_obj_delim
|
||||
self.Sjmp("JNE" , "_invalid_char") // JNE _invalid_char
|
||||
self.Emit("MOVQ", jit.Imm(_S_val), jit.Sib(_ST, _CX, 8, _ST_Vt)) // MOVQ _S_val, ST.Vt[CX]
|
||||
self.Emit("MOVQ", jit.Imm(_S_obj), jit.Sib(_ST, _CX, 8, _ST_Vt - 8)) // MOVQ _S_obj, ST.Vt[CX - 1]
|
||||
self.Sjmp("JMP" , "_next") // JMP _next
|
||||
|
||||
/** V_ELEM_SEP **/
|
||||
self.Link("_decode_V_ELEM_SEP") // _decode_V_ELEM_SEP:
|
||||
self.Emit("MOVQ" , jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX
|
||||
self.Emit("MOVQ" , jit.Sib(_ST, _CX, 8, _ST_Vt), _AX) // MOVQ ST.Vt[CX], AX
|
||||
self.Emit("CMPQ" , _AX, jit.Imm(_S_arr))
|
||||
self.Sjmp("JE" , "_array_sep") // JZ _next
|
||||
self.Emit("CMPQ" , _AX, jit.Imm(_S_obj)) // CMPQ _AX, _S_arr
|
||||
self.Sjmp("JNE" , "_invalid_char") // JNE _invalid_char
|
||||
self.Emit("MOVQ" , jit.Imm(_S_obj_sep), jit.Sib(_ST, _CX, 8, _ST_Vt))
|
||||
self.Sjmp("JMP" , "_next") // JMP _next
|
||||
|
||||
/* arrays */
|
||||
self.Link("_array_sep")
|
||||
self.Emit("MOVQ", jit.Sib(_ST, _CX, 8, _ST_Vp), _SI) // MOVQ ST.Vp[CX], SI
|
||||
self.Emit("MOVQ", jit.Ptr(_SI, 8), _SI) // MOVQ 8(SI), SI
|
||||
self.Emit("MOVQ", jit.Ptr(_SI, 8), _DX) // MOVQ 8(SI), DX
|
||||
self.Emit("CMPQ", _DX, jit.Ptr(_SI, 16)) // CMPQ DX, 16(SI)
|
||||
self.Sjmp("JAE" , "_array_more") // JAE _array_more
|
||||
|
||||
/* add a slot for the new element */
|
||||
self.Link("_array_append") // _array_append:
|
||||
self.Emit("ADDQ", jit.Imm(1), jit.Ptr(_SI, 8)) // ADDQ $1, 8(SI)
|
||||
self.Emit("MOVQ", jit.Ptr(_SI, 0), _SI) // MOVQ (SI), SI
|
||||
self.Emit("ADDQ", jit.Imm(1), _CX) // ADDQ $1, CX
|
||||
self.Emit("CMPQ", _CX, jit.Imm(types.MAX_RECURSE)) // CMPQ CX, ${types.MAX_RECURSE}
|
||||
self.Sjmp("JAE" , "_stack_overflow") // JA _stack_overflow
|
||||
self.Emit("SHLQ", jit.Imm(1), _DX) // SHLQ $1, DX
|
||||
self.Emit("LEAQ", jit.Sib(_SI, _DX, 8, 0), _SI) // LEAQ (SI)(DX*8), SI
|
||||
self.Emit("MOVQ", _CX, jit.Ptr(_ST, _ST_Sp)) // MOVQ CX, ST.Sp
|
||||
self.WriteRecNotAX(7 , _SI, jit.Sib(_ST, _CX, 8, _ST_Vp), false) // MOVQ SI, ST.Vp[CX]
|
||||
self.Emit("MOVQ", jit.Imm(_S_val), jit.Sib(_ST, _CX, 8, _ST_Vt)) // MOVQ _S_val, ST.Vt[CX}
|
||||
self.Sjmp("JMP" , "_next") // JMP _next
|
||||
|
||||
/** V_ARRAY_END **/
|
||||
self.Link("_decode_V_ARRAY_END") // _decode_V_ARRAY_END:
|
||||
self.Emit("XORL", _DX, _DX) // XORL DX, DX
|
||||
self.Emit("MOVQ", jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX
|
||||
self.Emit("MOVQ", jit.Sib(_ST, _CX, 8, _ST_Vt), _AX) // MOVQ ST.Vt[CX], AX
|
||||
self.Emit("CMPQ", _AX, jit.Imm(_S_arr_0)) // CMPQ AX, _S_arr_0
|
||||
self.Sjmp("JE" , "_first_item") // JE _first_item
|
||||
self.Emit("CMPQ", _AX, jit.Imm(_S_arr)) // CMPQ AX, _S_arr
|
||||
self.Sjmp("JNE" , "_invalid_char") // JNE _invalid_char
|
||||
self.Emit("SUBQ", jit.Imm(1), jit.Ptr(_ST, _ST_Sp)) // SUBQ $1, ST.Sp
|
||||
self.Emit("MOVQ", _DX, jit.Sib(_ST, _CX, 8, _ST_Vp)) // MOVQ DX, ST.Vp[CX]
|
||||
self.Sjmp("JMP" , "_next") // JMP _next
|
||||
|
||||
/* first element of an array */
|
||||
self.Link("_first_item") // _first_item:
|
||||
self.Emit("MOVQ", jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX
|
||||
self.Emit("SUBQ", jit.Imm(2), jit.Ptr(_ST, _ST_Sp)) // SUBQ $2, ST.Sp
|
||||
self.Emit("MOVQ", jit.Sib(_ST, _CX, 8, _ST_Vp - 8), _SI) // MOVQ ST.Vp[CX - 1], SI
|
||||
self.Emit("MOVQ", jit.Ptr(_SI, 8), _SI) // MOVQ 8(SI), SI
|
||||
self.Emit("MOVQ", _DX, jit.Sib(_ST, _CX, 8, _ST_Vp - 8)) // MOVQ DX, ST.Vp[CX - 1]
|
||||
self.Emit("MOVQ", _DX, jit.Sib(_ST, _CX, 8, _ST_Vp)) // MOVQ DX, ST.Vp[CX]
|
||||
self.Emit("MOVQ", _DX, jit.Ptr(_SI, 8)) // MOVQ DX, 8(SI)
|
||||
self.Sjmp("JMP" , "_next") // JMP _next
|
||||
|
||||
/** V_OBJECT_END **/
|
||||
self.Link("_decode_V_OBJECT_END") // _decode_V_OBJECT_END:
|
||||
self.Emit("MOVL", jit.Imm(_S_omask_end), _DI) // MOVL _S_omask, DI
|
||||
self.Emit("MOVQ", jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX
|
||||
self.Emit("MOVQ", jit.Sib(_ST, _CX, 8, _ST_Vt), _AX) // MOVQ ST.Vt[CX], AX
|
||||
self.Emit("BTQ" , _AX, _DI)
|
||||
self.Sjmp("JNC" , "_invalid_char") // JNE _invalid_char
|
||||
self.Emit("XORL", _AX, _AX) // XORL AX, AX
|
||||
self.Emit("SUBQ", jit.Imm(1), jit.Ptr(_ST, _ST_Sp)) // SUBQ $1, ST.Sp
|
||||
self.Emit("MOVQ", _AX, jit.Sib(_ST, _CX, 8, _ST_Vp)) // MOVQ AX, ST.Vp[CX]
|
||||
self.Sjmp("JMP" , "_next") // JMP _next
|
||||
|
||||
/* return from decoder */
|
||||
self.Link("_return") // _return:
|
||||
self.Emit("XORL", _EP, _EP) // XORL EP, EP
|
||||
self.Emit("MOVQ", _EP, jit.Ptr(_ST, _ST_Vp)) // MOVQ EP, ST.Vp[0]
|
||||
self.Link("_epilogue") // _epilogue:
|
||||
self.Emit("SUBQ", jit.Imm(_FsmOffset), _ST) // SUBQ _FsmOffset, _ST
|
||||
self.Emit("MOVQ", jit.Ptr(_SP, _VD_offs), _BP) // MOVQ _VD_offs(SP), BP
|
||||
self.Emit("ADDQ", jit.Imm(_VD_size), _SP) // ADDQ $_VD_size, SP
|
||||
self.Emit("RET") // RET
|
||||
|
||||
/* array expand */
|
||||
self.Link("_array_more") // _array_more:
|
||||
self.Emit("MOVQ" , _T_eface, _AX) // MOVQ _T_eface, AX
|
||||
self.Emit("MOVQ" , jit.Ptr(_SI, 0), _BX) // MOVQ (SI), BX
|
||||
self.Emit("MOVQ" , jit.Ptr(_SI, 8), _CX) // MOVQ 8(SI), CX
|
||||
self.Emit("MOVQ" , jit.Ptr(_SI, 16), _DI) // MOVQ 16(SI), DI
|
||||
self.Emit("MOVQ" , _DI, _SI) // MOVQ DI, 24(SP)
|
||||
self.Emit("SHLQ" , jit.Imm(1), _SI) // SHLQ $1, SI
|
||||
self.call_go(_F_growslice) // CALL_GO runtime.growslice
|
||||
self.Emit("MOVQ" , _AX, _DI) // MOVQ AX, DI
|
||||
self.Emit("MOVQ" , _BX, _DX) // MOVQ BX, DX
|
||||
self.Emit("MOVQ" , _CX, _AX) // MOVQ CX, AX
|
||||
|
||||
/* update the slice */
|
||||
self.Emit("MOVQ", jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX
|
||||
self.Emit("MOVQ", jit.Sib(_ST, _CX, 8, _ST_Vp), _SI) // MOVQ ST.Vp[CX], SI
|
||||
self.Emit("MOVQ", jit.Ptr(_SI, 8), _SI) // MOVQ 8(SI), SI
|
||||
self.Emit("MOVQ", _DX, jit.Ptr(_SI, 8)) // MOVQ DX, 8(SI)
|
||||
self.Emit("MOVQ", _AX, jit.Ptr(_SI, 16)) // MOVQ AX, 16(AX)
|
||||
self.WriteRecNotAX(8 , _DI, jit.Ptr(_SI, 0), false) // MOVQ R10, (SI)
|
||||
self.Sjmp("JMP" , "_array_append") // JMP _array_append
|
||||
|
||||
/* copy string */
|
||||
self.Link("copy_string") // pointer: R8, length: AX, return addr: DI
|
||||
self.Emit("MOVQ", _R8, _VAR_cs_p)
|
||||
self.Emit("MOVQ", _AX, _VAR_cs_n)
|
||||
self.Emit("MOVQ", _DI, _VAR_cs_LR)
|
||||
self.Emit("MOVQ", _AX, _BX)
|
||||
self.Emit("MOVQ", _AX, _CX)
|
||||
self.Emit("MOVQ", _T_byte, _AX)
|
||||
self.call_go(_F_makeslice)
|
||||
self.Emit("MOVQ", _AX, _VAR_cs_d)
|
||||
self.Emit("MOVQ", _VAR_cs_p, _BX)
|
||||
self.Emit("MOVQ", _VAR_cs_n, _CX)
|
||||
self.call_go(_F_memmove)
|
||||
self.Emit("MOVQ", _VAR_cs_d, _R8)
|
||||
self.Emit("MOVQ", _VAR_cs_n, _AX)
|
||||
self.Emit("MOVQ", _VAR_cs_LR, _DI)
|
||||
self.Rjmp("JMP", _DI)
|
||||
|
||||
/* error handlers */
|
||||
self.Link("_stack_overflow")
|
||||
self.Emit("MOVL" , _E_recurse, _EP) // MOVQ _E_recurse, EP
|
||||
self.Sjmp("JMP" , "_error") // JMP _error
|
||||
self.Link("_vtype_error") // _vtype_error:
|
||||
self.Emit("MOVQ" , _DI, _IC) // MOVQ DI, IC
|
||||
self.Emit("MOVL" , _E_invalid, _EP) // MOVL _E_invalid, EP
|
||||
self.Sjmp("JMP" , "_error") // JMP _error
|
||||
self.Link("_invalid_char") // _invalid_char:
|
||||
self.Emit("SUBQ" , jit.Imm(1), _IC) // SUBQ $1, IC
|
||||
self.Emit("MOVL" , _E_invalid, _EP) // MOVL _E_invalid, EP
|
||||
self.Sjmp("JMP" , "_error") // JMP _error
|
||||
self.Link("_unquote_error") // _unquote_error:
|
||||
self.Emit("MOVQ" , _VAR_ss_Iv, _IC) // MOVQ ss.Iv, IC
|
||||
self.Emit("SUBQ" , jit.Imm(1), _IC) // SUBQ $1, IC
|
||||
self.Link("_parsing_error") // _parsing_error:
|
||||
self.Emit("NEGQ" , _AX) // NEGQ AX
|
||||
self.Emit("MOVQ" , _AX, _EP) // MOVQ AX, EP
|
||||
self.Link("_error") // _error:
|
||||
self.Emit("PXOR" , _X0, _X0) // PXOR X0, X0
|
||||
self.Emit("MOVOU", _X0, jit.Ptr(_VP, 0)) // MOVOU X0, (VP)
|
||||
self.Sjmp("JMP" , "_epilogue") // JMP _epilogue
|
||||
|
||||
/* invalid value type, never returns */
|
||||
self.Link("_invalid_vtype")
|
||||
self.call_go(_F_invalid_vtype) // CALL invalid_type
|
||||
self.Emit("UD2") // UD2
|
||||
|
||||
/* switch jump table */
|
||||
self.Link("_switch_table") // _switch_table:
|
||||
self.Sref("_decode_V_EOF", 0) // SREF &_decode_V_EOF, $0
|
||||
self.Sref("_decode_V_NULL", -4) // SREF &_decode_V_NULL, $-4
|
||||
self.Sref("_decode_V_TRUE", -8) // SREF &_decode_V_TRUE, $-8
|
||||
self.Sref("_decode_V_FALSE", -12) // SREF &_decode_V_FALSE, $-12
|
||||
self.Sref("_decode_V_ARRAY", -16) // SREF &_decode_V_ARRAY, $-16
|
||||
self.Sref("_decode_V_OBJECT", -20) // SREF &_decode_V_OBJECT, $-20
|
||||
self.Sref("_decode_V_STRING", -24) // SREF &_decode_V_STRING, $-24
|
||||
self.Sref("_decode_V_DOUBLE", -28) // SREF &_decode_V_DOUBLE, $-28
|
||||
self.Sref("_decode_V_INTEGER", -32) // SREF &_decode_V_INTEGER, $-32
|
||||
self.Sref("_decode_V_KEY_SEP", -36) // SREF &_decode_V_KEY_SEP, $-36
|
||||
self.Sref("_decode_V_ELEM_SEP", -40) // SREF &_decode_V_ELEM_SEP, $-40
|
||||
self.Sref("_decode_V_ARRAY_END", -44) // SREF &_decode_V_ARRAY_END, $-44
|
||||
self.Sref("_decode_V_OBJECT_END", -48) // SREF &_decode_V_OBJECT_END, $-48
|
||||
|
||||
/* fast character lookup table */
|
||||
self.Link("_decode_tab") // _decode_tab:
|
||||
self.Sref("_decode_V_EOF", 0) // SREF &_decode_V_EOF, $0
|
||||
|
||||
/* generate rest of the tabs */
|
||||
for i := 1; i < 256; i++ {
|
||||
if to, ok := _R_tab[i]; ok {
|
||||
self.Sref(to, -int64(i) * 4)
|
||||
} else {
|
||||
self.Byte(0x00, 0x00, 0x00, 0x00)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (self *_ValueDecoder) WritePtrAX(i int, rec obj.Addr, saveDI bool) {
|
||||
self.Emit("MOVQ", _V_writeBarrier, _R9)
|
||||
self.Emit("CMPL", jit.Ptr(_R9, 0), jit.Imm(0))
|
||||
self.Sjmp("JE", "_no_writeBarrier" + strconv.Itoa(i) + "_{n}")
|
||||
if saveDI {
|
||||
self.save(_DI)
|
||||
}
|
||||
self.Emit("LEAQ", rec, _DI)
|
||||
self.call(_F_gcWriteBarrierAX)
|
||||
if saveDI {
|
||||
self.load(_DI)
|
||||
}
|
||||
self.Sjmp("JMP", "_end_writeBarrier" + strconv.Itoa(i) + "_{n}")
|
||||
self.Link("_no_writeBarrier" + strconv.Itoa(i) + "_{n}")
|
||||
self.Emit("MOVQ", _AX, rec)
|
||||
self.Link("_end_writeBarrier" + strconv.Itoa(i) + "_{n}")
|
||||
}
|
||||
|
||||
func (self *_ValueDecoder) WriteRecNotAX(i int, ptr obj.Addr, rec obj.Addr, saveDI bool) {
|
||||
if rec.Reg == x86.REG_AX || rec.Index == x86.REG_AX {
|
||||
panic("rec contains AX!")
|
||||
}
|
||||
self.Emit("MOVQ", _V_writeBarrier, _AX)
|
||||
self.Emit("CMPL", jit.Ptr(_AX, 0), jit.Imm(0))
|
||||
self.Sjmp("JE", "_no_writeBarrier" + strconv.Itoa(i) + "_{n}")
|
||||
self.Emit("MOVQ", ptr, _AX)
|
||||
if saveDI {
|
||||
self.save(_DI)
|
||||
}
|
||||
self.Emit("LEAQ", rec, _DI)
|
||||
self.call(_F_gcWriteBarrierAX)
|
||||
if saveDI {
|
||||
self.load(_DI)
|
||||
}
|
||||
self.Sjmp("JMP", "_end_writeBarrier" + strconv.Itoa(i) + "_{n}")
|
||||
self.Link("_no_writeBarrier" + strconv.Itoa(i) + "_{n}")
|
||||
self.Emit("MOVQ", ptr, rec)
|
||||
self.Link("_end_writeBarrier" + strconv.Itoa(i) + "_{n}")
|
||||
}
|
||||
|
||||
/** Generic Decoder **/
|
||||
|
||||
var (
|
||||
_subr_decode_value = new(_ValueDecoder).build()
|
||||
)
|
||||
|
||||
//go:nosplit
|
||||
func invalid_vtype(vt types.ValueType) {
|
||||
throw(fmt.Sprintf("invalid value type: %d", vt))
|
||||
}
|
||||
37
vendor/github.com/bytedance/sonic/internal/decoder/generic_amd64_go117_test.s
generated
vendored
Normal file
37
vendor/github.com/bytedance/sonic/internal/decoder/generic_amd64_go117_test.s
generated
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
// +build go1.17,!go1.21
|
||||
|
||||
//
|
||||
// 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 ·decodeValueStub(SB), NOSPLIT, $0 - 72
|
||||
NO_LOCAL_POINTERS
|
||||
PXOR X0, X0
|
||||
MOVOU X0, rv+48(FP)
|
||||
MOVQ st+0(FP) , R13
|
||||
MOVQ sp+8(FP) , R10
|
||||
MOVQ sn+16(FP), R12
|
||||
MOVQ ic+24(FP), R11
|
||||
MOVQ vp+32(FP), R15
|
||||
MOVQ df+40(FP), AX
|
||||
MOVQ ·_subr_decode_value(SB), BX
|
||||
CALL BX
|
||||
MOVQ R11, rp+48(FP)
|
||||
MOVQ BX, ex+56(FP)
|
||||
RET
|
||||
37
vendor/github.com/bytedance/sonic/internal/decoder/generic_amd64_test.s
generated
vendored
Normal file
37
vendor/github.com/bytedance/sonic/internal/decoder/generic_amd64_test.s
generated
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
// +build go1.15,!go1.17
|
||||
|
||||
//
|
||||
// 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 ·decodeValueStub(SB), NOSPLIT, $0 - 72
|
||||
NO_LOCAL_POINTERS
|
||||
PXOR X0, X0
|
||||
MOVOU X0, rv+48(FP)
|
||||
MOVQ st+0(FP), BX
|
||||
MOVQ sp+8(FP), R12
|
||||
MOVQ sn+16(FP), R13
|
||||
MOVQ ic+24(FP), R14
|
||||
MOVQ vp+32(FP), R15
|
||||
MOVQ df+40(FP), R10
|
||||
MOVQ ·_subr_decode_value(SB), AX
|
||||
CALL AX
|
||||
MOVQ R14, rp+48(FP)
|
||||
MOVQ R11, ex+56(FP)
|
||||
RET
|
||||
143
vendor/github.com/bytedance/sonic/internal/decoder/pools.go
generated
vendored
Normal file
143
vendor/github.com/bytedance/sonic/internal/decoder/pools.go
generated
vendored
Normal file
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* 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 decoder
|
||||
|
||||
import (
|
||||
`sync`
|
||||
`unsafe`
|
||||
|
||||
`github.com/bytedance/sonic/internal/caching`
|
||||
`github.com/bytedance/sonic/internal/native/types`
|
||||
`github.com/bytedance/sonic/internal/rt`
|
||||
)
|
||||
|
||||
const (
|
||||
_MinSlice = 2
|
||||
_MaxStack = 4096 // 4k slots
|
||||
_MaxStackBytes = _MaxStack * _PtrBytes
|
||||
_MaxDigitNums = 800 // used in atof fallback algorithm
|
||||
)
|
||||
|
||||
const (
|
||||
_PtrBytes = _PTR_SIZE / 8
|
||||
_FsmOffset = (_MaxStack + 1) * _PtrBytes
|
||||
_DbufOffset = _FsmOffset + int64(unsafe.Sizeof(types.StateMachine{})) + types.MAX_RECURSE * _PtrBytes
|
||||
_StackSize = unsafe.Sizeof(_Stack{})
|
||||
)
|
||||
|
||||
var (
|
||||
stackPool = sync.Pool{}
|
||||
valueCache = []unsafe.Pointer(nil)
|
||||
fieldCache = []*caching.FieldMap(nil)
|
||||
fieldCacheMux = sync.Mutex{}
|
||||
programCache = caching.CreateProgramCache()
|
||||
)
|
||||
|
||||
type _Stack struct {
|
||||
sp uintptr
|
||||
sb [_MaxStack]unsafe.Pointer
|
||||
mm types.StateMachine
|
||||
vp [types.MAX_RECURSE]unsafe.Pointer
|
||||
dp [_MaxDigitNums]byte
|
||||
}
|
||||
|
||||
type _Decoder func(
|
||||
s string,
|
||||
i int,
|
||||
vp unsafe.Pointer,
|
||||
sb *_Stack,
|
||||
fv uint64,
|
||||
sv string, // DO NOT pass value to this arguement, since it is only used for local _VAR_sv
|
||||
vk unsafe.Pointer, // DO NOT pass value to this arguement, since it is only used for local _VAR_vk
|
||||
) (int, error)
|
||||
|
||||
var _KeepAlive struct {
|
||||
s string
|
||||
i int
|
||||
vp unsafe.Pointer
|
||||
sb *_Stack
|
||||
fv uint64
|
||||
sv string
|
||||
vk unsafe.Pointer
|
||||
|
||||
ret int
|
||||
err error
|
||||
|
||||
frame_decoder [_FP_offs]byte
|
||||
frame_generic [_VD_offs]byte
|
||||
}
|
||||
|
||||
var (
|
||||
argPtrs = []bool{true, false, false, true, true, false, true, false, true}
|
||||
localPtrs = []bool{}
|
||||
)
|
||||
|
||||
var (
|
||||
argPtrs_generic = []bool{true}
|
||||
localPtrs_generic = []bool{}
|
||||
)
|
||||
|
||||
func newStack() *_Stack {
|
||||
if ret := stackPool.Get(); ret == nil {
|
||||
return new(_Stack)
|
||||
} else {
|
||||
return ret.(*_Stack)
|
||||
}
|
||||
}
|
||||
|
||||
func resetStack(p *_Stack) {
|
||||
memclrNoHeapPointers(unsafe.Pointer(p), _StackSize)
|
||||
}
|
||||
|
||||
func freeStack(p *_Stack) {
|
||||
p.sp = 0
|
||||
stackPool.Put(p)
|
||||
}
|
||||
|
||||
func freezeValue(v unsafe.Pointer) uintptr {
|
||||
valueCache = append(valueCache, v)
|
||||
return uintptr(v)
|
||||
}
|
||||
|
||||
func freezeFields(v *caching.FieldMap) int64 {
|
||||
fieldCacheMux.Lock()
|
||||
fieldCache = append(fieldCache, v)
|
||||
fieldCacheMux.Unlock()
|
||||
return referenceFields(v)
|
||||
}
|
||||
|
||||
func referenceFields(v *caching.FieldMap) int64 {
|
||||
return int64(uintptr(unsafe.Pointer(v)))
|
||||
}
|
||||
|
||||
func makeDecoder(vt *rt.GoType, _ ...interface{}) (interface{}, error) {
|
||||
if pp, err := newCompiler().compile(vt.Pack()); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
return newAssembler(pp).Load(), nil
|
||||
}
|
||||
}
|
||||
|
||||
func findOrCompile(vt *rt.GoType) (_Decoder, error) {
|
||||
if val := programCache.Get(vt); val != nil {
|
||||
return val.(_Decoder), nil
|
||||
} else if ret, err := programCache.Compute(vt, makeDecoder); err == nil {
|
||||
return ret.(_Decoder), nil
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
46
vendor/github.com/bytedance/sonic/internal/decoder/primitives.go
generated
vendored
Normal file
46
vendor/github.com/bytedance/sonic/internal/decoder/primitives.go
generated
vendored
Normal 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 decoder
|
||||
|
||||
import (
|
||||
`encoding`
|
||||
`encoding/json`
|
||||
`unsafe`
|
||||
|
||||
`github.com/bytedance/sonic/internal/native`
|
||||
`github.com/bytedance/sonic/internal/rt`
|
||||
)
|
||||
|
||||
func decodeTypedPointer(s string, i int, vt *rt.GoType, vp unsafe.Pointer, sb *_Stack, fv uint64) (int, error) {
|
||||
if fn, err := findOrCompile(vt); err != nil {
|
||||
return 0, err
|
||||
} else {
|
||||
rt.MoreStack(_FP_size + _VD_size + native.MaxFrameSize)
|
||||
rt.StopProf()
|
||||
ret, err := fn(s, i, vp, sb, fv, "", nil)
|
||||
rt.StartProf()
|
||||
return ret, err
|
||||
}
|
||||
}
|
||||
|
||||
func decodeJsonUnmarshaler(vv interface{}, s string) error {
|
||||
return vv.(json.Unmarshaler).UnmarshalJSON(rt.Str2Mem(s))
|
||||
}
|
||||
|
||||
func decodeTextUnmarshaler(vv interface{}, s string) error {
|
||||
return vv.(encoding.TextUnmarshaler).UnmarshalText(rt.Str2Mem(s))
|
||||
}
|
||||
217
vendor/github.com/bytedance/sonic/internal/decoder/stream.go
generated
vendored
Normal file
217
vendor/github.com/bytedance/sonic/internal/decoder/stream.go
generated
vendored
Normal file
@@ -0,0 +1,217 @@
|
||||
/*
|
||||
* 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 decoder
|
||||
|
||||
import (
|
||||
`bytes`
|
||||
`io`
|
||||
`sync`
|
||||
|
||||
`github.com/bytedance/sonic/option`
|
||||
`github.com/bytedance/sonic/internal/native/types`
|
||||
)
|
||||
|
||||
var (
|
||||
minLeftBufferShift uint = 1
|
||||
)
|
||||
|
||||
// StreamDecoder is the decoder context object for streaming input.
|
||||
type StreamDecoder struct {
|
||||
r io.Reader
|
||||
buf []byte
|
||||
scanp int
|
||||
scanned int64
|
||||
err error
|
||||
Decoder
|
||||
}
|
||||
|
||||
var bufPool = sync.Pool{
|
||||
New: func () interface{} {
|
||||
return make([]byte, 0, option.DefaultDecoderBufferSize)
|
||||
},
|
||||
}
|
||||
|
||||
// NewStreamDecoder adapts to encoding/json.NewDecoder API.
|
||||
//
|
||||
// NewStreamDecoder returns a new decoder that reads from r.
|
||||
func NewStreamDecoder(r io.Reader) *StreamDecoder {
|
||||
return &StreamDecoder{r : r}
|
||||
}
|
||||
|
||||
// Decode decodes input stream into val with corresponding data.
|
||||
// Redundantly bytes may be read and left in its buffer, and can be used at next call.
|
||||
// Either io error from underlying io.Reader (except io.EOF)
|
||||
// or syntax error from data will be recorded and stop subsequently decoding.
|
||||
func (self *StreamDecoder) Decode(val interface{}) (err error) {
|
||||
if self.err != nil {
|
||||
return self.err
|
||||
}
|
||||
|
||||
var buf = self.buf[self.scanp:]
|
||||
var p = 0
|
||||
var recycle bool
|
||||
if cap(buf) == 0 {
|
||||
buf = bufPool.Get().([]byte)
|
||||
recycle = true
|
||||
}
|
||||
|
||||
var first = true
|
||||
var repeat = true
|
||||
read_more:
|
||||
for {
|
||||
l := len(buf)
|
||||
realloc(&buf)
|
||||
n, err := self.r.Read(buf[l:cap(buf)])
|
||||
buf = buf[:l+n]
|
||||
if err != nil {
|
||||
repeat = false
|
||||
if err == io.EOF {
|
||||
if len(buf) == 0 {
|
||||
return err
|
||||
}
|
||||
break
|
||||
}
|
||||
self.err = err
|
||||
return err
|
||||
}
|
||||
if n > 0 || first {
|
||||
break
|
||||
}
|
||||
}
|
||||
first = false
|
||||
|
||||
l := len(buf)
|
||||
if l > 0 {
|
||||
self.Decoder.Reset(string(buf))
|
||||
err = self.Decoder.Decode(val)
|
||||
if err != nil {
|
||||
if repeat && self.repeatable(err) {
|
||||
goto read_more
|
||||
}
|
||||
self.err = err
|
||||
}
|
||||
|
||||
p = self.Decoder.Pos()
|
||||
self.scanned += int64(p)
|
||||
self.scanp = 0
|
||||
}
|
||||
|
||||
if l > p {
|
||||
// remain undecoded bytes, so copy them into self.buf
|
||||
self.buf = append(self.buf[:0], buf[p:]...)
|
||||
} else {
|
||||
self.buf = nil
|
||||
recycle = true
|
||||
}
|
||||
|
||||
if recycle {
|
||||
buf = buf[:0]
|
||||
bufPool.Put(buf)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (self StreamDecoder) repeatable(err error) bool {
|
||||
if ee, ok := err.(SyntaxError); ok &&
|
||||
(ee.Code == types.ERR_EOF || (ee.Code == types.ERR_INVALID_CHAR && self.i >= len(self.s)-1)) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// InputOffset returns the input stream byte offset of the current decoder position.
|
||||
// The offset gives the location of the end of the most recently returned token and the beginning of the next token.
|
||||
func (self *StreamDecoder) InputOffset() int64 {
|
||||
return self.scanned + int64(self.scanp)
|
||||
}
|
||||
|
||||
// Buffered returns a reader of the data remaining in the Decoder's buffer.
|
||||
// The reader is valid until the next call to Decode.
|
||||
func (self *StreamDecoder) Buffered() io.Reader {
|
||||
return bytes.NewReader(self.buf[self.scanp:])
|
||||
}
|
||||
|
||||
// More reports whether there is another element in the
|
||||
// current array or object being parsed.
|
||||
func (self *StreamDecoder) More() bool {
|
||||
if self.err != nil {
|
||||
return false
|
||||
}
|
||||
c, err := self.peek()
|
||||
return err == nil && c != ']' && c != '}'
|
||||
}
|
||||
|
||||
func (self *StreamDecoder) peek() (byte, error) {
|
||||
var err error
|
||||
for {
|
||||
for i := self.scanp; i < len(self.buf); i++ {
|
||||
c := self.buf[i]
|
||||
if isSpace(c) {
|
||||
continue
|
||||
}
|
||||
self.scanp = i
|
||||
return c, nil
|
||||
}
|
||||
// buffer has been scanned, now report any error
|
||||
if err != nil {
|
||||
if err != io.EOF {
|
||||
self.err = err
|
||||
}
|
||||
return 0, err
|
||||
}
|
||||
err = self.refill()
|
||||
}
|
||||
}
|
||||
|
||||
func isSpace(c byte) bool {
|
||||
return types.SPACE_MASK & (1 << c) != 0
|
||||
}
|
||||
|
||||
func (self *StreamDecoder) refill() error {
|
||||
// Make room to read more into the buffer.
|
||||
// First slide down data already consumed.
|
||||
if self.scanp > 0 {
|
||||
self.scanned += int64(self.scanp)
|
||||
n := copy(self.buf, self.buf[self.scanp:])
|
||||
self.buf = self.buf[:n]
|
||||
self.scanp = 0
|
||||
}
|
||||
|
||||
// Grow buffer if not large enough.
|
||||
realloc(&self.buf)
|
||||
|
||||
// Read. Delay error for next iteration (after scan).
|
||||
n, err := self.r.Read(self.buf[len(self.buf):cap(self.buf)])
|
||||
self.buf = self.buf[0 : len(self.buf)+n]
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func realloc(buf *[]byte) {
|
||||
l := uint(len(*buf))
|
||||
c := uint(cap(*buf))
|
||||
if c - l <= c >> minLeftBufferShift {
|
||||
e := l+(l>>minLeftBufferShift)
|
||||
if e < option.DefaultDecoderBufferSize {
|
||||
e = option.DefaultDecoderBufferSize
|
||||
}
|
||||
tmp := make([]byte, l, e)
|
||||
copy(tmp, *buf)
|
||||
*buf = tmp
|
||||
}
|
||||
}
|
||||
|
||||
111
vendor/github.com/bytedance/sonic/internal/decoder/stubs_go115.go
generated
vendored
Normal file
111
vendor/github.com/bytedance/sonic/internal/decoder/stubs_go115.go
generated
vendored
Normal file
@@ -0,0 +1,111 @@
|
||||
// +build go1.15,!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 decoder
|
||||
|
||||
import (
|
||||
`unsafe`
|
||||
`reflect`
|
||||
|
||||
_ `github.com/chenzhuoyu/base64x`
|
||||
|
||||
`github.com/bytedance/sonic/internal/rt`
|
||||
)
|
||||
|
||||
//go:linkname _subr__b64decode github.com/chenzhuoyu/base64x._subr__b64decode
|
||||
var _subr__b64decode uintptr
|
||||
|
||||
// runtime.maxElementSize
|
||||
const _max_map_element_size uintptr = 128
|
||||
|
||||
func mapfast(vt reflect.Type) bool {
|
||||
return vt.Elem().Size() <= _max_map_element_size
|
||||
}
|
||||
|
||||
//go:nosplit
|
||||
//go:linkname throw runtime.throw
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func throw(s string)
|
||||
|
||||
//go:linkname convT64 runtime.convT64
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func convT64(v uint64) unsafe.Pointer
|
||||
|
||||
//go:linkname convTslice runtime.convTslice
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func convTslice(v []byte) unsafe.Pointer
|
||||
|
||||
//go:linkname convTstring runtime.convTstring
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func convTstring(v string) unsafe.Pointer
|
||||
|
||||
//go:noescape
|
||||
//go:linkname memequal runtime.memequal
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func memequal(a unsafe.Pointer, b unsafe.Pointer, size uintptr) bool
|
||||
|
||||
//go:noescape
|
||||
//go:linkname memmove runtime.memmove
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func memmove(to unsafe.Pointer, from unsafe.Pointer, n uintptr)
|
||||
|
||||
//go:linkname mallocgc runtime.mallocgc
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func mallocgc(size uintptr, typ *rt.GoType, needzero bool) unsafe.Pointer
|
||||
|
||||
//go:linkname makeslice runtime.makeslice
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func makeslice(et *rt.GoType, len int, cap int) unsafe.Pointer
|
||||
|
||||
//go:noescape
|
||||
//go:linkname growslice runtime.growslice
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func growslice(et *rt.GoType, old rt.GoSlice, cap int) rt.GoSlice
|
||||
|
||||
//go:linkname makemap_small runtime.makemap_small
|
||||
func makemap_small() unsafe.Pointer
|
||||
|
||||
//go:linkname mapassign runtime.mapassign
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func mapassign(t *rt.GoType, h unsafe.Pointer, k unsafe.Pointer) unsafe.Pointer
|
||||
|
||||
//go:linkname mapassign_fast32 runtime.mapassign_fast32
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func mapassign_fast32(t *rt.GoType, h unsafe.Pointer, k uint32) unsafe.Pointer
|
||||
|
||||
//go:linkname mapassign_fast64 runtime.mapassign_fast64
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func mapassign_fast64(t *rt.GoType, h unsafe.Pointer, k uint64) unsafe.Pointer
|
||||
|
||||
//go:linkname mapassign_fast64ptr runtime.mapassign_fast64ptr
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func mapassign_fast64ptr(t *rt.GoType, h unsafe.Pointer, k unsafe.Pointer) unsafe.Pointer
|
||||
|
||||
//go:linkname mapassign_faststr runtime.mapassign_faststr
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func mapassign_faststr(t *rt.GoType, h unsafe.Pointer, s string) unsafe.Pointer
|
||||
|
||||
//go:nosplit
|
||||
//go:linkname memclrHasPointers runtime.memclrHasPointers
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func memclrHasPointers(ptr unsafe.Pointer, n uintptr)
|
||||
|
||||
//go:noescape
|
||||
//go:linkname memclrNoHeapPointers runtime.memclrNoHeapPointers
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func memclrNoHeapPointers(ptr unsafe.Pointer, n uintptr)
|
||||
111
vendor/github.com/bytedance/sonic/internal/decoder/stubs_go120.go
generated
vendored
Normal file
111
vendor/github.com/bytedance/sonic/internal/decoder/stubs_go120.go
generated
vendored
Normal file
@@ -0,0 +1,111 @@
|
||||
// +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 decoder
|
||||
|
||||
import (
|
||||
`unsafe`
|
||||
`reflect`
|
||||
|
||||
_ `github.com/chenzhuoyu/base64x`
|
||||
|
||||
`github.com/bytedance/sonic/internal/rt`
|
||||
)
|
||||
|
||||
//go:linkname _subr__b64decode github.com/chenzhuoyu/base64x._subr__b64decode
|
||||
var _subr__b64decode uintptr
|
||||
|
||||
// runtime.maxElementSize
|
||||
const _max_map_element_size uintptr = 128
|
||||
|
||||
func mapfast(vt reflect.Type) bool {
|
||||
return vt.Elem().Size() <= _max_map_element_size
|
||||
}
|
||||
|
||||
//go:nosplit
|
||||
//go:linkname throw runtime.throw
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func throw(s string)
|
||||
|
||||
//go:linkname convT64 runtime.convT64
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func convT64(v uint64) unsafe.Pointer
|
||||
|
||||
//go:linkname convTslice runtime.convTslice
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func convTslice(v []byte) unsafe.Pointer
|
||||
|
||||
//go:linkname convTstring runtime.convTstring
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func convTstring(v string) unsafe.Pointer
|
||||
|
||||
//go:noescape
|
||||
//go:linkname memequal runtime.memequal
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func memequal(a unsafe.Pointer, b unsafe.Pointer, size uintptr) bool
|
||||
|
||||
//go:noescape
|
||||
//go:linkname memmove runtime.memmove
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func memmove(to unsafe.Pointer, from unsafe.Pointer, n uintptr)
|
||||
|
||||
//go:linkname mallocgc runtime.mallocgc
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func mallocgc(size uintptr, typ *rt.GoType, needzero bool) unsafe.Pointer
|
||||
|
||||
//go:linkname makeslice runtime.makeslice
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func makeslice(et *rt.GoType, len int, cap int) unsafe.Pointer
|
||||
|
||||
//go:noescape
|
||||
//go:linkname growslice reflect.growslice
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func growslice(et *rt.GoType, old rt.GoSlice, cap int) rt.GoSlice
|
||||
|
||||
//go:linkname makemap_small runtime.makemap_small
|
||||
func makemap_small() unsafe.Pointer
|
||||
|
||||
//go:linkname mapassign runtime.mapassign
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func mapassign(t *rt.GoType, h unsafe.Pointer, k unsafe.Pointer) unsafe.Pointer
|
||||
|
||||
//go:linkname mapassign_fast32 runtime.mapassign_fast32
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func mapassign_fast32(t *rt.GoType, h unsafe.Pointer, k uint32) unsafe.Pointer
|
||||
|
||||
//go:linkname mapassign_fast64 runtime.mapassign_fast64
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func mapassign_fast64(t *rt.GoType, h unsafe.Pointer, k uint64) unsafe.Pointer
|
||||
|
||||
//go:linkname mapassign_fast64ptr runtime.mapassign_fast64ptr
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func mapassign_fast64ptr(t *rt.GoType, h unsafe.Pointer, k unsafe.Pointer) unsafe.Pointer
|
||||
|
||||
//go:linkname mapassign_faststr runtime.mapassign_faststr
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func mapassign_faststr(t *rt.GoType, h unsafe.Pointer, s string) unsafe.Pointer
|
||||
|
||||
//go:nosplit
|
||||
//go:linkname memclrHasPointers runtime.memclrHasPointers
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func memclrHasPointers(ptr unsafe.Pointer, n uintptr)
|
||||
|
||||
//go:noescape
|
||||
//go:linkname memclrNoHeapPointers runtime.memclrNoHeapPointers
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func memclrNoHeapPointers(ptr unsafe.Pointer, n uintptr)
|
||||
58
vendor/github.com/bytedance/sonic/internal/decoder/types.go
generated
vendored
Normal file
58
vendor/github.com/bytedance/sonic/internal/decoder/types.go
generated
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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 decoder
|
||||
|
||||
import (
|
||||
`encoding`
|
||||
`encoding/base64`
|
||||
`encoding/json`
|
||||
`reflect`
|
||||
`unsafe`
|
||||
|
||||
`github.com/bytedance/sonic/internal/rt`
|
||||
)
|
||||
|
||||
var (
|
||||
byteType = reflect.TypeOf(byte(0))
|
||||
intType = reflect.TypeOf(int(0))
|
||||
int8Type = reflect.TypeOf(int8(0))
|
||||
int16Type = reflect.TypeOf(int16(0))
|
||||
int32Type = reflect.TypeOf(int32(0))
|
||||
int64Type = reflect.TypeOf(int64(0))
|
||||
uintType = reflect.TypeOf(uint(0))
|
||||
uint8Type = reflect.TypeOf(uint8(0))
|
||||
uint16Type = reflect.TypeOf(uint16(0))
|
||||
uint32Type = reflect.TypeOf(uint32(0))
|
||||
uint64Type = reflect.TypeOf(uint64(0))
|
||||
float32Type = reflect.TypeOf(float32(0))
|
||||
float64Type = reflect.TypeOf(float64(0))
|
||||
stringType = reflect.TypeOf("")
|
||||
bytesType = reflect.TypeOf([]byte(nil))
|
||||
jsonNumberType = reflect.TypeOf(json.Number(""))
|
||||
base64CorruptInputError = reflect.TypeOf(base64.CorruptInputError(0))
|
||||
)
|
||||
|
||||
var (
|
||||
errorType = reflect.TypeOf((*error)(nil)).Elem()
|
||||
jsonUnmarshalerType = reflect.TypeOf((*json.Unmarshaler)(nil)).Elem()
|
||||
encodingTextUnmarshalerType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem()
|
||||
)
|
||||
|
||||
func rtype(t reflect.Type) (*rt.GoItab, *rt.GoType) {
|
||||
p := (*rt.GoIface)(unsafe.Pointer(&t))
|
||||
return p.Itab, (*rt.GoType)(p.Value)
|
||||
}
|
||||
39
vendor/github.com/bytedance/sonic/internal/decoder/utils.go
generated
vendored
Normal file
39
vendor/github.com/bytedance/sonic/internal/decoder/utils.go
generated
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* 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 decoder
|
||||
|
||||
import (
|
||||
`unsafe`
|
||||
|
||||
`github.com/bytedance/sonic/loader`
|
||||
)
|
||||
|
||||
//go:nosplit
|
||||
func pbool(v bool) uintptr {
|
||||
return freezeValue(unsafe.Pointer(&v))
|
||||
}
|
||||
|
||||
//go:nosplit
|
||||
func ptodec(p loader.Function) _Decoder {
|
||||
return *(*_Decoder)(unsafe.Pointer(&p))
|
||||
}
|
||||
|
||||
func assert_eq(v int64, exp int64, msg string) {
|
||||
if v != exp {
|
||||
panic(msg)
|
||||
}
|
||||
}
|
||||
0
vendor/github.com/bytedance/sonic/internal/encoder/asm.s
generated
vendored
Normal file
0
vendor/github.com/bytedance/sonic/internal/encoder/asm.s
generated
vendored
Normal file
1199
vendor/github.com/bytedance/sonic/internal/encoder/assembler_amd64_go116.go
generated
vendored
Normal file
1199
vendor/github.com/bytedance/sonic/internal/encoder/assembler_amd64_go116.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1202
vendor/github.com/bytedance/sonic/internal/encoder/assembler_amd64_go117.go
generated
vendored
Normal file
1202
vendor/github.com/bytedance/sonic/internal/encoder/assembler_amd64_go117.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
885
vendor/github.com/bytedance/sonic/internal/encoder/compiler.go
generated
vendored
Normal file
885
vendor/github.com/bytedance/sonic/internal/encoder/compiler.go
generated
vendored
Normal file
@@ -0,0 +1,885 @@
|
||||
/*
|
||||
* 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 encoder
|
||||
|
||||
import (
|
||||
`fmt`
|
||||
`reflect`
|
||||
`strconv`
|
||||
`strings`
|
||||
`unsafe`
|
||||
|
||||
`github.com/bytedance/sonic/internal/resolver`
|
||||
`github.com/bytedance/sonic/internal/rt`
|
||||
`github.com/bytedance/sonic/option`
|
||||
)
|
||||
|
||||
type _Op uint8
|
||||
|
||||
const (
|
||||
_OP_null _Op = iota + 1
|
||||
_OP_empty_arr
|
||||
_OP_empty_obj
|
||||
_OP_bool
|
||||
_OP_i8
|
||||
_OP_i16
|
||||
_OP_i32
|
||||
_OP_i64
|
||||
_OP_u8
|
||||
_OP_u16
|
||||
_OP_u32
|
||||
_OP_u64
|
||||
_OP_f32
|
||||
_OP_f64
|
||||
_OP_str
|
||||
_OP_bin
|
||||
_OP_quote
|
||||
_OP_number
|
||||
_OP_eface
|
||||
_OP_iface
|
||||
_OP_byte
|
||||
_OP_text
|
||||
_OP_deref
|
||||
_OP_index
|
||||
_OP_load
|
||||
_OP_save
|
||||
_OP_drop
|
||||
_OP_drop_2
|
||||
_OP_recurse
|
||||
_OP_is_nil
|
||||
_OP_is_nil_p1
|
||||
_OP_is_zero_1
|
||||
_OP_is_zero_2
|
||||
_OP_is_zero_4
|
||||
_OP_is_zero_8
|
||||
_OP_is_zero_map
|
||||
_OP_goto
|
||||
_OP_map_iter
|
||||
_OP_map_stop
|
||||
_OP_map_check_key
|
||||
_OP_map_write_key
|
||||
_OP_map_value_next
|
||||
_OP_slice_len
|
||||
_OP_slice_next
|
||||
_OP_marshal
|
||||
_OP_marshal_p
|
||||
_OP_marshal_text
|
||||
_OP_marshal_text_p
|
||||
_OP_cond_set
|
||||
_OP_cond_testc
|
||||
)
|
||||
|
||||
const (
|
||||
_INT_SIZE = 32 << (^uint(0) >> 63)
|
||||
_PTR_SIZE = 32 << (^uintptr(0) >> 63)
|
||||
_PTR_BYTE = unsafe.Sizeof(uintptr(0))
|
||||
)
|
||||
|
||||
const (
|
||||
_MAX_ILBUF = 100000 // cutoff at 100k of IL instructions
|
||||
_MAX_FIELDS = 50 // cutoff at 50 fields struct
|
||||
)
|
||||
|
||||
var _OpNames = [256]string {
|
||||
_OP_null : "null",
|
||||
_OP_empty_arr : "empty_arr",
|
||||
_OP_empty_obj : "empty_obj",
|
||||
_OP_bool : "bool",
|
||||
_OP_i8 : "i8",
|
||||
_OP_i16 : "i16",
|
||||
_OP_i32 : "i32",
|
||||
_OP_i64 : "i64",
|
||||
_OP_u8 : "u8",
|
||||
_OP_u16 : "u16",
|
||||
_OP_u32 : "u32",
|
||||
_OP_u64 : "u64",
|
||||
_OP_f32 : "f32",
|
||||
_OP_f64 : "f64",
|
||||
_OP_str : "str",
|
||||
_OP_bin : "bin",
|
||||
_OP_quote : "quote",
|
||||
_OP_number : "number",
|
||||
_OP_eface : "eface",
|
||||
_OP_iface : "iface",
|
||||
_OP_byte : "byte",
|
||||
_OP_text : "text",
|
||||
_OP_deref : "deref",
|
||||
_OP_index : "index",
|
||||
_OP_load : "load",
|
||||
_OP_save : "save",
|
||||
_OP_drop : "drop",
|
||||
_OP_drop_2 : "drop_2",
|
||||
_OP_recurse : "recurse",
|
||||
_OP_is_nil : "is_nil",
|
||||
_OP_is_nil_p1 : "is_nil_p1",
|
||||
_OP_is_zero_1 : "is_zero_1",
|
||||
_OP_is_zero_2 : "is_zero_2",
|
||||
_OP_is_zero_4 : "is_zero_4",
|
||||
_OP_is_zero_8 : "is_zero_8",
|
||||
_OP_is_zero_map : "is_zero_map",
|
||||
_OP_goto : "goto",
|
||||
_OP_map_iter : "map_iter",
|
||||
_OP_map_stop : "map_stop",
|
||||
_OP_map_check_key : "map_check_key",
|
||||
_OP_map_write_key : "map_write_key",
|
||||
_OP_map_value_next : "map_value_next",
|
||||
_OP_slice_len : "slice_len",
|
||||
_OP_slice_next : "slice_next",
|
||||
_OP_marshal : "marshal",
|
||||
_OP_marshal_p : "marshal_p",
|
||||
_OP_marshal_text : "marshal_text",
|
||||
_OP_marshal_text_p : "marshal_text_p",
|
||||
_OP_cond_set : "cond_set",
|
||||
_OP_cond_testc : "cond_testc",
|
||||
}
|
||||
|
||||
func (self _Op) String() string {
|
||||
if ret := _OpNames[self]; ret != "" {
|
||||
return ret
|
||||
} else {
|
||||
return "<invalid>"
|
||||
}
|
||||
}
|
||||
|
||||
func _OP_int() _Op {
|
||||
switch _INT_SIZE {
|
||||
case 32: return _OP_i32
|
||||
case 64: return _OP_i64
|
||||
default: panic("unsupported int size")
|
||||
}
|
||||
}
|
||||
|
||||
func _OP_uint() _Op {
|
||||
switch _INT_SIZE {
|
||||
case 32: return _OP_u32
|
||||
case 64: return _OP_u64
|
||||
default: panic("unsupported uint size")
|
||||
}
|
||||
}
|
||||
|
||||
func _OP_uintptr() _Op {
|
||||
switch _PTR_SIZE {
|
||||
case 32: return _OP_u32
|
||||
case 64: return _OP_u64
|
||||
default: panic("unsupported pointer size")
|
||||
}
|
||||
}
|
||||
|
||||
func _OP_is_zero_ints() _Op {
|
||||
switch _INT_SIZE {
|
||||
case 32: return _OP_is_zero_4
|
||||
case 64: return _OP_is_zero_8
|
||||
default: panic("unsupported integer size")
|
||||
}
|
||||
}
|
||||
|
||||
type _Instr struct {
|
||||
u uint64 // union {op: 8, _: 8, vi: 48}, vi maybe int or len(str)
|
||||
p unsafe.Pointer // maybe GoString.Ptr, or *GoType
|
||||
}
|
||||
|
||||
func packOp(op _Op) uint64 {
|
||||
return uint64(op) << 56
|
||||
}
|
||||
|
||||
func newInsOp(op _Op) _Instr {
|
||||
return _Instr{u: packOp(op)}
|
||||
}
|
||||
|
||||
func newInsVi(op _Op, vi int) _Instr {
|
||||
return _Instr{u: packOp(op) | rt.PackInt(vi)}
|
||||
}
|
||||
|
||||
func newInsVs(op _Op, vs string) _Instr {
|
||||
return _Instr {
|
||||
u: packOp(op) | rt.PackInt(len(vs)),
|
||||
p: (*rt.GoString)(unsafe.Pointer(&vs)).Ptr,
|
||||
}
|
||||
}
|
||||
|
||||
func newInsVt(op _Op, vt reflect.Type) _Instr {
|
||||
return _Instr {
|
||||
u: packOp(op),
|
||||
p: unsafe.Pointer(rt.UnpackType(vt)),
|
||||
}
|
||||
}
|
||||
|
||||
func newInsVp(op _Op, vt reflect.Type, pv bool) _Instr {
|
||||
i := 0
|
||||
if pv {
|
||||
i = 1
|
||||
}
|
||||
return _Instr {
|
||||
u: packOp(op) | rt.PackInt(i),
|
||||
p: unsafe.Pointer(rt.UnpackType(vt)),
|
||||
}
|
||||
}
|
||||
|
||||
func (self _Instr) op() _Op {
|
||||
return _Op(self.u >> 56)
|
||||
}
|
||||
|
||||
func (self _Instr) vi() int {
|
||||
return rt.UnpackInt(self.u)
|
||||
}
|
||||
|
||||
func (self _Instr) vf() uint8 {
|
||||
return (*rt.GoType)(self.p).KindFlags
|
||||
}
|
||||
|
||||
func (self _Instr) vs() (v string) {
|
||||
(*rt.GoString)(unsafe.Pointer(&v)).Ptr = self.p
|
||||
(*rt.GoString)(unsafe.Pointer(&v)).Len = self.vi()
|
||||
return
|
||||
}
|
||||
|
||||
func (self _Instr) vk() reflect.Kind {
|
||||
return (*rt.GoType)(self.p).Kind()
|
||||
}
|
||||
|
||||
func (self _Instr) vt() reflect.Type {
|
||||
return (*rt.GoType)(self.p).Pack()
|
||||
}
|
||||
|
||||
func (self _Instr) vp() (vt reflect.Type, pv bool) {
|
||||
return (*rt.GoType)(self.p).Pack(), rt.UnpackInt(self.u) == 1
|
||||
}
|
||||
|
||||
func (self _Instr) i64() int64 {
|
||||
return int64(self.vi())
|
||||
}
|
||||
|
||||
func (self _Instr) vlen() int {
|
||||
return int((*rt.GoType)(self.p).Size)
|
||||
}
|
||||
|
||||
func (self _Instr) isBranch() bool {
|
||||
switch self.op() {
|
||||
case _OP_goto : fallthrough
|
||||
case _OP_is_nil : fallthrough
|
||||
case _OP_is_nil_p1 : fallthrough
|
||||
case _OP_is_zero_1 : fallthrough
|
||||
case _OP_is_zero_2 : fallthrough
|
||||
case _OP_is_zero_4 : fallthrough
|
||||
case _OP_is_zero_8 : fallthrough
|
||||
case _OP_map_check_key : fallthrough
|
||||
case _OP_map_write_key : fallthrough
|
||||
case _OP_slice_next : fallthrough
|
||||
case _OP_cond_testc : return true
|
||||
default : return false
|
||||
}
|
||||
}
|
||||
|
||||
func (self _Instr) disassemble() string {
|
||||
switch self.op() {
|
||||
case _OP_byte : return fmt.Sprintf("%-18s%s", self.op().String(), strconv.QuoteRune(rune(self.vi())))
|
||||
case _OP_text : return fmt.Sprintf("%-18s%s", self.op().String(), strconv.Quote(self.vs()))
|
||||
case _OP_index : return fmt.Sprintf("%-18s%d", self.op().String(), self.vi())
|
||||
case _OP_recurse : fallthrough
|
||||
case _OP_map_iter : fallthrough
|
||||
case _OP_marshal : fallthrough
|
||||
case _OP_marshal_p : fallthrough
|
||||
case _OP_marshal_text : fallthrough
|
||||
case _OP_marshal_text_p : return fmt.Sprintf("%-18s%s", self.op().String(), self.vt())
|
||||
case _OP_goto : fallthrough
|
||||
case _OP_is_nil : fallthrough
|
||||
case _OP_is_nil_p1 : fallthrough
|
||||
case _OP_is_zero_1 : fallthrough
|
||||
case _OP_is_zero_2 : fallthrough
|
||||
case _OP_is_zero_4 : fallthrough
|
||||
case _OP_is_zero_8 : fallthrough
|
||||
case _OP_is_zero_map : fallthrough
|
||||
case _OP_cond_testc : fallthrough
|
||||
case _OP_map_check_key : fallthrough
|
||||
case _OP_map_write_key : return fmt.Sprintf("%-18sL_%d", self.op().String(), self.vi())
|
||||
case _OP_slice_next : return fmt.Sprintf("%-18sL_%d, %s", self.op().String(), self.vi(), self.vt())
|
||||
default : return self.op().String()
|
||||
}
|
||||
}
|
||||
|
||||
type (
|
||||
_Program []_Instr
|
||||
)
|
||||
|
||||
func (self _Program) pc() int {
|
||||
return len(self)
|
||||
}
|
||||
|
||||
func (self _Program) tag(n int) {
|
||||
if n >= _MaxStack {
|
||||
panic("type nesting too deep")
|
||||
}
|
||||
}
|
||||
|
||||
func (self _Program) pin(i int) {
|
||||
v := &self[i]
|
||||
v.u &= 0xffff000000000000
|
||||
v.u |= rt.PackInt(self.pc())
|
||||
}
|
||||
|
||||
func (self _Program) rel(v []int) {
|
||||
for _, i := range v {
|
||||
self.pin(i)
|
||||
}
|
||||
}
|
||||
|
||||
func (self *_Program) add(op _Op) {
|
||||
*self = append(*self, newInsOp(op))
|
||||
}
|
||||
|
||||
func (self *_Program) key(op _Op) {
|
||||
*self = append(*self,
|
||||
newInsVi(_OP_byte, '"'),
|
||||
newInsOp(op),
|
||||
newInsVi(_OP_byte, '"'),
|
||||
)
|
||||
}
|
||||
|
||||
func (self *_Program) int(op _Op, vi int) {
|
||||
*self = append(*self, newInsVi(op, vi))
|
||||
}
|
||||
|
||||
func (self *_Program) str(op _Op, vs string) {
|
||||
*self = append(*self, newInsVs(op, vs))
|
||||
}
|
||||
|
||||
func (self *_Program) rtt(op _Op, vt reflect.Type) {
|
||||
*self = append(*self, newInsVt(op, vt))
|
||||
}
|
||||
|
||||
func (self *_Program) vp(op _Op, vt reflect.Type, pv bool) {
|
||||
*self = append(*self, newInsVp(op, vt, pv))
|
||||
}
|
||||
|
||||
func (self _Program) disassemble() string {
|
||||
nb := len(self)
|
||||
tab := make([]bool, nb + 1)
|
||||
ret := make([]string, 0, nb + 1)
|
||||
|
||||
/* prescan to get all the labels */
|
||||
for _, ins := range self {
|
||||
if ins.isBranch() {
|
||||
tab[ins.vi()] = true
|
||||
}
|
||||
}
|
||||
|
||||
/* disassemble each instruction */
|
||||
for i, ins := range self {
|
||||
if !tab[i] {
|
||||
ret = append(ret, "\t" + ins.disassemble())
|
||||
} else {
|
||||
ret = append(ret, fmt.Sprintf("L_%d:\n\t%s", i, ins.disassemble()))
|
||||
}
|
||||
}
|
||||
|
||||
/* add the last label, if needed */
|
||||
if tab[nb] {
|
||||
ret = append(ret, fmt.Sprintf("L_%d:", nb))
|
||||
}
|
||||
|
||||
/* add an "end" indicator, and join all the strings */
|
||||
return strings.Join(append(ret, "\tend"), "\n")
|
||||
}
|
||||
|
||||
type _Compiler struct {
|
||||
opts option.CompileOptions
|
||||
pv bool
|
||||
tab map[reflect.Type]bool
|
||||
rec map[reflect.Type]uint8
|
||||
}
|
||||
|
||||
func newCompiler() *_Compiler {
|
||||
return &_Compiler {
|
||||
opts: option.DefaultCompileOptions(),
|
||||
tab: map[reflect.Type]bool{},
|
||||
rec: map[reflect.Type]uint8{},
|
||||
}
|
||||
}
|
||||
|
||||
func (self *_Compiler) apply(opts option.CompileOptions) *_Compiler {
|
||||
self.opts = opts
|
||||
if self.opts.RecursiveDepth > 0 {
|
||||
self.rec = map[reflect.Type]uint8{}
|
||||
}
|
||||
return self
|
||||
}
|
||||
|
||||
func (self *_Compiler) rescue(ep *error) {
|
||||
if val := recover(); val != nil {
|
||||
if err, ok := val.(error); ok {
|
||||
*ep = err
|
||||
} else {
|
||||
panic(val)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (self *_Compiler) compile(vt reflect.Type, pv bool) (ret _Program, err error) {
|
||||
defer self.rescue(&err)
|
||||
self.compileOne(&ret, 0, vt, pv)
|
||||
return
|
||||
}
|
||||
|
||||
func (self *_Compiler) compileOne(p *_Program, sp int, vt reflect.Type, pv bool) {
|
||||
if self.tab[vt] {
|
||||
p.vp(_OP_recurse, vt, pv)
|
||||
} else {
|
||||
self.compileRec(p, sp, vt, pv)
|
||||
}
|
||||
}
|
||||
|
||||
func (self *_Compiler) compileRec(p *_Program, sp int, vt reflect.Type, pv bool) {
|
||||
pr := self.pv
|
||||
pt := reflect.PtrTo(vt)
|
||||
|
||||
/* check for addressable `json.Marshaler` with pointer receiver */
|
||||
if pv && pt.Implements(jsonMarshalerType) {
|
||||
p.rtt(_OP_marshal_p, pt)
|
||||
return
|
||||
}
|
||||
|
||||
/* check for `json.Marshaler` */
|
||||
if vt.Implements(jsonMarshalerType) {
|
||||
self.compileMarshaler(p, _OP_marshal, vt, jsonMarshalerType)
|
||||
return
|
||||
}
|
||||
|
||||
/* check for addressable `encoding.TextMarshaler` with pointer receiver */
|
||||
if pv && pt.Implements(encodingTextMarshalerType) {
|
||||
p.rtt(_OP_marshal_text_p, pt)
|
||||
return
|
||||
}
|
||||
|
||||
/* check for `encoding.TextMarshaler` */
|
||||
if vt.Implements(encodingTextMarshalerType) {
|
||||
self.compileMarshaler(p, _OP_marshal_text, vt, encodingTextMarshalerType)
|
||||
return
|
||||
}
|
||||
|
||||
/* enter the recursion, and compile the type */
|
||||
self.pv = pv
|
||||
self.tab[vt] = true
|
||||
self.compileOps(p, sp, vt)
|
||||
|
||||
/* exit the recursion */
|
||||
self.pv = pr
|
||||
delete(self.tab, vt)
|
||||
}
|
||||
|
||||
func (self *_Compiler) compileOps(p *_Program, sp int, vt reflect.Type) {
|
||||
switch vt.Kind() {
|
||||
case reflect.Bool : p.add(_OP_bool)
|
||||
case reflect.Int : p.add(_OP_int())
|
||||
case reflect.Int8 : p.add(_OP_i8)
|
||||
case reflect.Int16 : p.add(_OP_i16)
|
||||
case reflect.Int32 : p.add(_OP_i32)
|
||||
case reflect.Int64 : p.add(_OP_i64)
|
||||
case reflect.Uint : p.add(_OP_uint())
|
||||
case reflect.Uint8 : p.add(_OP_u8)
|
||||
case reflect.Uint16 : p.add(_OP_u16)
|
||||
case reflect.Uint32 : p.add(_OP_u32)
|
||||
case reflect.Uint64 : p.add(_OP_u64)
|
||||
case reflect.Uintptr : p.add(_OP_uintptr())
|
||||
case reflect.Float32 : p.add(_OP_f32)
|
||||
case reflect.Float64 : p.add(_OP_f64)
|
||||
case reflect.String : self.compileString (p, vt)
|
||||
case reflect.Array : self.compileArray (p, sp, vt.Elem(), vt.Len())
|
||||
case reflect.Interface : self.compileInterface (p, vt)
|
||||
case reflect.Map : self.compileMap (p, sp, vt)
|
||||
case reflect.Ptr : self.compilePtr (p, sp, vt.Elem())
|
||||
case reflect.Slice : self.compileSlice (p, sp, vt.Elem())
|
||||
case reflect.Struct : self.compileStruct (p, sp, vt)
|
||||
default : panic (error_type(vt))
|
||||
}
|
||||
}
|
||||
|
||||
func (self *_Compiler) compileNil(p *_Program, sp int, vt reflect.Type, nil_op _Op, fn func(*_Program, int, reflect.Type)) {
|
||||
x := p.pc()
|
||||
p.add(_OP_is_nil)
|
||||
fn(p, sp, vt)
|
||||
e := p.pc()
|
||||
p.add(_OP_goto)
|
||||
p.pin(x)
|
||||
p.add(nil_op)
|
||||
p.pin(e)
|
||||
}
|
||||
|
||||
func (self *_Compiler) compilePtr(p *_Program, sp int, vt reflect.Type) {
|
||||
self.compileNil(p, sp, vt, _OP_null, self.compilePtrBody)
|
||||
}
|
||||
|
||||
func (self *_Compiler) compilePtrBody(p *_Program, sp int, vt reflect.Type) {
|
||||
p.tag(sp)
|
||||
p.add(_OP_save)
|
||||
p.add(_OP_deref)
|
||||
self.compileOne(p, sp + 1, vt, true)
|
||||
p.add(_OP_drop)
|
||||
}
|
||||
|
||||
func (self *_Compiler) compileMap(p *_Program, sp int, vt reflect.Type) {
|
||||
self.compileNil(p, sp, vt, _OP_empty_obj, self.compileMapBody)
|
||||
}
|
||||
|
||||
func (self *_Compiler) compileMapBody(p *_Program, sp int, vt reflect.Type) {
|
||||
p.tag(sp + 1)
|
||||
p.int(_OP_byte, '{')
|
||||
p.add(_OP_save)
|
||||
p.rtt(_OP_map_iter, vt)
|
||||
p.add(_OP_save)
|
||||
i := p.pc()
|
||||
p.add(_OP_map_check_key)
|
||||
u := p.pc()
|
||||
p.add(_OP_map_write_key)
|
||||
self.compileMapBodyKey(p, vt.Key())
|
||||
p.pin(u)
|
||||
p.int(_OP_byte, ':')
|
||||
p.add(_OP_map_value_next)
|
||||
self.compileOne(p, sp + 2, vt.Elem(), false)
|
||||
j := p.pc()
|
||||
p.add(_OP_map_check_key)
|
||||
p.int(_OP_byte, ',')
|
||||
v := p.pc()
|
||||
p.add(_OP_map_write_key)
|
||||
self.compileMapBodyKey(p, vt.Key())
|
||||
p.pin(v)
|
||||
p.int(_OP_byte, ':')
|
||||
p.add(_OP_map_value_next)
|
||||
self.compileOne(p, sp + 2, vt.Elem(), false)
|
||||
p.int(_OP_goto, j)
|
||||
p.pin(i)
|
||||
p.pin(j)
|
||||
p.add(_OP_map_stop)
|
||||
p.add(_OP_drop_2)
|
||||
p.int(_OP_byte, '}')
|
||||
}
|
||||
|
||||
func (self *_Compiler) compileMapBodyKey(p *_Program, vk reflect.Type) {
|
||||
if !vk.Implements(encodingTextMarshalerType) {
|
||||
self.compileMapBodyTextKey(p, vk)
|
||||
} else {
|
||||
self.compileMapBodyUtextKey(p, vk)
|
||||
}
|
||||
}
|
||||
|
||||
func (self *_Compiler) compileMapBodyTextKey(p *_Program, vk reflect.Type) {
|
||||
switch vk.Kind() {
|
||||
case reflect.Invalid : panic("map key is nil")
|
||||
case reflect.Bool : p.key(_OP_bool)
|
||||
case reflect.Int : p.key(_OP_int())
|
||||
case reflect.Int8 : p.key(_OP_i8)
|
||||
case reflect.Int16 : p.key(_OP_i16)
|
||||
case reflect.Int32 : p.key(_OP_i32)
|
||||
case reflect.Int64 : p.key(_OP_i64)
|
||||
case reflect.Uint : p.key(_OP_uint())
|
||||
case reflect.Uint8 : p.key(_OP_u8)
|
||||
case reflect.Uint16 : p.key(_OP_u16)
|
||||
case reflect.Uint32 : p.key(_OP_u32)
|
||||
case reflect.Uint64 : p.key(_OP_u64)
|
||||
case reflect.Uintptr : p.key(_OP_uintptr())
|
||||
case reflect.Float32 : p.key(_OP_f32)
|
||||
case reflect.Float64 : p.key(_OP_f64)
|
||||
case reflect.String : self.compileString(p, vk)
|
||||
default : panic(error_type(vk))
|
||||
}
|
||||
}
|
||||
|
||||
func (self *_Compiler) compileMapBodyUtextKey(p *_Program, vk reflect.Type) {
|
||||
if vk.Kind() != reflect.Ptr {
|
||||
p.rtt(_OP_marshal_text, vk)
|
||||
} else {
|
||||
self.compileMapBodyUtextPtr(p, vk)
|
||||
}
|
||||
}
|
||||
|
||||
func (self *_Compiler) compileMapBodyUtextPtr(p *_Program, vk reflect.Type) {
|
||||
i := p.pc()
|
||||
p.add(_OP_is_nil)
|
||||
p.rtt(_OP_marshal_text, vk)
|
||||
j := p.pc()
|
||||
p.add(_OP_goto)
|
||||
p.pin(i)
|
||||
p.str(_OP_text, "\"\"")
|
||||
p.pin(j)
|
||||
}
|
||||
|
||||
func (self *_Compiler) compileSlice(p *_Program, sp int, vt reflect.Type) {
|
||||
self.compileNil(p, sp, vt, _OP_empty_arr, self.compileSliceBody)
|
||||
}
|
||||
|
||||
func (self *_Compiler) compileSliceBody(p *_Program, sp int, vt reflect.Type) {
|
||||
if isSimpleByte(vt) {
|
||||
p.add(_OP_bin)
|
||||
} else {
|
||||
self.compileSliceArray(p, sp, vt)
|
||||
}
|
||||
}
|
||||
|
||||
func (self *_Compiler) compileSliceArray(p *_Program, sp int, vt reflect.Type) {
|
||||
p.tag(sp)
|
||||
p.int(_OP_byte, '[')
|
||||
p.add(_OP_save)
|
||||
p.add(_OP_slice_len)
|
||||
i := p.pc()
|
||||
p.rtt(_OP_slice_next, vt)
|
||||
self.compileOne(p, sp + 1, vt, true)
|
||||
j := p.pc()
|
||||
p.rtt(_OP_slice_next, vt)
|
||||
p.int(_OP_byte, ',')
|
||||
self.compileOne(p, sp + 1, vt, true)
|
||||
p.int(_OP_goto, j)
|
||||
p.pin(i)
|
||||
p.pin(j)
|
||||
p.add(_OP_drop)
|
||||
p.int(_OP_byte, ']')
|
||||
}
|
||||
|
||||
func (self *_Compiler) compileArray(p *_Program, sp int, vt reflect.Type, nb int) {
|
||||
p.tag(sp)
|
||||
p.int(_OP_byte, '[')
|
||||
p.add(_OP_save)
|
||||
|
||||
/* first item */
|
||||
if nb != 0 {
|
||||
self.compileOne(p, sp + 1, vt, self.pv)
|
||||
p.add(_OP_load)
|
||||
}
|
||||
|
||||
/* remaining items */
|
||||
for i := 1; i < nb; i++ {
|
||||
p.int(_OP_byte, ',')
|
||||
p.int(_OP_index, i * int(vt.Size()))
|
||||
self.compileOne(p, sp + 1, vt, self.pv)
|
||||
p.add(_OP_load)
|
||||
}
|
||||
|
||||
/* end of array */
|
||||
p.add(_OP_drop)
|
||||
p.int(_OP_byte, ']')
|
||||
}
|
||||
|
||||
func (self *_Compiler) compileString(p *_Program, vt reflect.Type) {
|
||||
if vt != jsonNumberType {
|
||||
p.add(_OP_str)
|
||||
} else {
|
||||
p.add(_OP_number)
|
||||
}
|
||||
}
|
||||
|
||||
func (self *_Compiler) compileStruct(p *_Program, sp int, vt reflect.Type) {
|
||||
if sp >= self.opts.MaxInlineDepth || p.pc() >= _MAX_ILBUF || (sp > 0 && vt.NumField() >= _MAX_FIELDS) {
|
||||
p.vp(_OP_recurse, vt, self.pv)
|
||||
if self.opts.RecursiveDepth > 0 {
|
||||
if self.pv {
|
||||
self.rec[vt] = 1
|
||||
} else {
|
||||
self.rec[vt] = 0
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.compileStructBody(p, sp, vt)
|
||||
}
|
||||
}
|
||||
|
||||
func (self *_Compiler) compileStructBody(p *_Program, sp int, vt reflect.Type) {
|
||||
p.tag(sp)
|
||||
p.int(_OP_byte, '{')
|
||||
p.add(_OP_save)
|
||||
p.add(_OP_cond_set)
|
||||
|
||||
/* compile each field */
|
||||
for _, fv := range resolver.ResolveStruct(vt) {
|
||||
var s []int
|
||||
var o resolver.Offset
|
||||
|
||||
/* "omitempty" for arrays */
|
||||
if fv.Type.Kind() == reflect.Array {
|
||||
if fv.Type.Len() == 0 && (fv.Opts & resolver.F_omitempty) != 0 {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
/* index to the field */
|
||||
for _, o = range fv.Path {
|
||||
if p.int(_OP_index, int(o.Size)); o.Kind == resolver.F_deref {
|
||||
s = append(s, p.pc())
|
||||
p.add(_OP_is_nil)
|
||||
p.add(_OP_deref)
|
||||
}
|
||||
}
|
||||
|
||||
/* check for "omitempty" option */
|
||||
if fv.Type.Kind() != reflect.Struct && fv.Type.Kind() != reflect.Array && (fv.Opts & resolver.F_omitempty) != 0 {
|
||||
s = append(s, p.pc())
|
||||
self.compileStructFieldZero(p, fv.Type)
|
||||
}
|
||||
|
||||
/* add the comma if not the first element */
|
||||
i := p.pc()
|
||||
p.add(_OP_cond_testc)
|
||||
p.int(_OP_byte, ',')
|
||||
p.pin(i)
|
||||
|
||||
/* compile the key and value */
|
||||
ft := fv.Type
|
||||
p.str(_OP_text, Quote(fv.Name) + ":")
|
||||
|
||||
/* check for "stringnize" option */
|
||||
if (fv.Opts & resolver.F_stringize) == 0 {
|
||||
self.compileOne(p, sp + 1, ft, self.pv)
|
||||
} else {
|
||||
self.compileStructFieldStr(p, sp + 1, ft)
|
||||
}
|
||||
|
||||
/* patch the skipping jumps and reload the struct pointer */
|
||||
p.rel(s)
|
||||
p.add(_OP_load)
|
||||
}
|
||||
|
||||
/* end of object */
|
||||
p.add(_OP_drop)
|
||||
p.int(_OP_byte, '}')
|
||||
}
|
||||
|
||||
func (self *_Compiler) compileStructFieldStr(p *_Program, sp int, vt reflect.Type) {
|
||||
pc := -1
|
||||
ft := vt
|
||||
sv := false
|
||||
|
||||
/* dereference the pointer if needed */
|
||||
if ft.Kind() == reflect.Ptr {
|
||||
ft = ft.Elem()
|
||||
}
|
||||
|
||||
/* check if it can be stringized */
|
||||
switch ft.Kind() {
|
||||
case reflect.Bool : sv = true
|
||||
case reflect.Int : sv = true
|
||||
case reflect.Int8 : sv = true
|
||||
case reflect.Int16 : sv = true
|
||||
case reflect.Int32 : sv = true
|
||||
case reflect.Int64 : sv = true
|
||||
case reflect.Uint : sv = true
|
||||
case reflect.Uint8 : sv = true
|
||||
case reflect.Uint16 : sv = true
|
||||
case reflect.Uint32 : sv = true
|
||||
case reflect.Uint64 : sv = true
|
||||
case reflect.Uintptr : sv = true
|
||||
case reflect.Float32 : sv = true
|
||||
case reflect.Float64 : sv = true
|
||||
case reflect.String : sv = true
|
||||
}
|
||||
|
||||
/* if it's not, ignore the "string" and follow the regular path */
|
||||
if !sv {
|
||||
self.compileOne(p, sp, vt, self.pv)
|
||||
return
|
||||
}
|
||||
|
||||
/* dereference the pointer */
|
||||
if vt.Kind() == reflect.Ptr {
|
||||
pc = p.pc()
|
||||
vt = vt.Elem()
|
||||
p.add(_OP_is_nil)
|
||||
p.add(_OP_deref)
|
||||
}
|
||||
|
||||
/* special case of a double-quoted string */
|
||||
if ft != jsonNumberType && ft.Kind() == reflect.String {
|
||||
p.add(_OP_quote)
|
||||
} else {
|
||||
self.compileStructFieldQuoted(p, sp, vt)
|
||||
}
|
||||
|
||||
/* the "null" case of the pointer */
|
||||
if pc != -1 {
|
||||
e := p.pc()
|
||||
p.add(_OP_goto)
|
||||
p.pin(pc)
|
||||
p.add(_OP_null)
|
||||
p.pin(e)
|
||||
}
|
||||
}
|
||||
|
||||
func (self *_Compiler) compileStructFieldZero(p *_Program, vt reflect.Type) {
|
||||
switch vt.Kind() {
|
||||
case reflect.Bool : p.add(_OP_is_zero_1)
|
||||
case reflect.Int : p.add(_OP_is_zero_ints())
|
||||
case reflect.Int8 : p.add(_OP_is_zero_1)
|
||||
case reflect.Int16 : p.add(_OP_is_zero_2)
|
||||
case reflect.Int32 : p.add(_OP_is_zero_4)
|
||||
case reflect.Int64 : p.add(_OP_is_zero_8)
|
||||
case reflect.Uint : p.add(_OP_is_zero_ints())
|
||||
case reflect.Uint8 : p.add(_OP_is_zero_1)
|
||||
case reflect.Uint16 : p.add(_OP_is_zero_2)
|
||||
case reflect.Uint32 : p.add(_OP_is_zero_4)
|
||||
case reflect.Uint64 : p.add(_OP_is_zero_8)
|
||||
case reflect.Uintptr : p.add(_OP_is_nil)
|
||||
case reflect.Float32 : p.add(_OP_is_zero_4)
|
||||
case reflect.Float64 : p.add(_OP_is_zero_8)
|
||||
case reflect.String : p.add(_OP_is_nil_p1)
|
||||
case reflect.Interface : p.add(_OP_is_nil_p1)
|
||||
case reflect.Map : p.add(_OP_is_zero_map)
|
||||
case reflect.Ptr : p.add(_OP_is_nil)
|
||||
case reflect.Slice : p.add(_OP_is_nil_p1)
|
||||
default : panic(error_type(vt))
|
||||
}
|
||||
}
|
||||
|
||||
func (self *_Compiler) compileStructFieldQuoted(p *_Program, sp int, vt reflect.Type) {
|
||||
p.int(_OP_byte, '"')
|
||||
self.compileOne(p, sp, vt, self.pv)
|
||||
p.int(_OP_byte, '"')
|
||||
}
|
||||
|
||||
func (self *_Compiler) compileInterface(p *_Program, vt reflect.Type) {
|
||||
x := p.pc()
|
||||
p.add(_OP_is_nil_p1)
|
||||
|
||||
/* iface and efaces are different */
|
||||
if vt.NumMethod() == 0 {
|
||||
p.add(_OP_eface)
|
||||
} else {
|
||||
p.add(_OP_iface)
|
||||
}
|
||||
|
||||
/* the "null" value */
|
||||
e := p.pc()
|
||||
p.add(_OP_goto)
|
||||
p.pin(x)
|
||||
p.add(_OP_null)
|
||||
p.pin(e)
|
||||
}
|
||||
|
||||
func (self *_Compiler) compileMarshaler(p *_Program, op _Op, vt reflect.Type, mt reflect.Type) {
|
||||
pc := p.pc()
|
||||
vk := vt.Kind()
|
||||
|
||||
/* direct receiver */
|
||||
if vk != reflect.Ptr {
|
||||
p.rtt(op, vt)
|
||||
return
|
||||
}
|
||||
|
||||
/* value receiver with a pointer type, check for nil before calling the marshaler */
|
||||
p.add(_OP_is_nil)
|
||||
p.rtt(op, vt)
|
||||
i := p.pc()
|
||||
p.add(_OP_goto)
|
||||
p.pin(pc)
|
||||
p.add(_OP_null)
|
||||
p.pin(i)
|
||||
}
|
||||
66
vendor/github.com/bytedance/sonic/internal/encoder/debug_go116.go
generated
vendored
Normal file
66
vendor/github.com/bytedance/sonic/internal/encoder/debug_go116.go
generated
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
// +build go1.15,!go1.17
|
||||
|
||||
/*
|
||||
* 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 encoder
|
||||
|
||||
import (
|
||||
`os`
|
||||
`strings`
|
||||
`runtime`
|
||||
`runtime/debug`
|
||||
|
||||
`github.com/bytedance/sonic/internal/jit`
|
||||
)
|
||||
|
||||
var (
|
||||
debugSyncGC = os.Getenv("SONIC_SYNC_GC") != ""
|
||||
debugAsyncGC = os.Getenv("SONIC_NO_ASYNC_GC") == ""
|
||||
)
|
||||
|
||||
var (
|
||||
_Instr_End _Instr = newInsOp(_OP_null)
|
||||
|
||||
_F_gc = jit.Func(runtime.GC)
|
||||
_F_force_gc = jit.Func(debug.FreeOSMemory)
|
||||
_F_println = jit.Func(println_wrapper)
|
||||
)
|
||||
|
||||
func println_wrapper(i int, op1 int, op2 int){
|
||||
println(i, " Intrs ", op1, _OpNames[op1], "next: ", op2, _OpNames[op2])
|
||||
}
|
||||
|
||||
func (self *_Assembler) force_gc() {
|
||||
self.call_go(_F_gc)
|
||||
self.call_go(_F_force_gc)
|
||||
}
|
||||
|
||||
func (self *_Assembler) debug_instr(i int, v *_Instr) {
|
||||
if debugSyncGC {
|
||||
if (i+1 == len(self.p)) {
|
||||
self.print_gc(i, v, &_Instr_End)
|
||||
} else {
|
||||
next := &(self.p[i+1])
|
||||
self.print_gc(i, v, next)
|
||||
name := _OpNames[next.op()]
|
||||
if strings.Contains(name, "save") {
|
||||
return
|
||||
}
|
||||
}
|
||||
self.force_gc()
|
||||
}
|
||||
}
|
||||
205
vendor/github.com/bytedance/sonic/internal/encoder/debug_go117.go
generated
vendored
Normal file
205
vendor/github.com/bytedance/sonic/internal/encoder/debug_go117.go
generated
vendored
Normal file
@@ -0,0 +1,205 @@
|
||||
// +build go1.17,!go1.21
|
||||
|
||||
/*
|
||||
* 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 encoder
|
||||
|
||||
import (
|
||||
`fmt`
|
||||
`os`
|
||||
`runtime`
|
||||
`strings`
|
||||
`unsafe`
|
||||
|
||||
`github.com/bytedance/sonic/internal/jit`
|
||||
`github.com/twitchyliquid64/golang-asm/obj`
|
||||
)
|
||||
|
||||
const _FP_debug = 128
|
||||
|
||||
var (
|
||||
debugSyncGC = os.Getenv("SONIC_SYNC_GC") != ""
|
||||
debugAsyncGC = os.Getenv("SONIC_NO_ASYNC_GC") == ""
|
||||
debugCheckPtr = os.Getenv("SONIC_CHECK_POINTER") != ""
|
||||
)
|
||||
|
||||
var (
|
||||
_Instr_End = newInsOp(_OP_is_nil)
|
||||
|
||||
_F_gc = jit.Func(gc)
|
||||
_F_println = jit.Func(println_wrapper)
|
||||
_F_print = jit.Func(print)
|
||||
)
|
||||
|
||||
func (self *_Assembler) dsave(r ...obj.Addr) {
|
||||
for i, v := range r {
|
||||
if i > _FP_debug / 8 - 1 {
|
||||
panic("too many registers to save")
|
||||
} else {
|
||||
self.Emit("MOVQ", v, jit.Ptr(_SP, _FP_fargs + _FP_saves + _FP_locals + int64(i) * 8))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (self *_Assembler) dload(r ...obj.Addr) {
|
||||
for i, v := range r {
|
||||
if i > _FP_debug / 8 - 1 {
|
||||
panic("too many registers to load")
|
||||
} else {
|
||||
self.Emit("MOVQ", jit.Ptr(_SP, _FP_fargs + _FP_saves + _FP_locals + int64(i) * 8), v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func println_wrapper(i int, op1 int, op2 int){
|
||||
println(i, " Intrs ", op1, _OpNames[op1], "next: ", op2, _OpNames[op2])
|
||||
}
|
||||
|
||||
func print(i int){
|
||||
println(i)
|
||||
}
|
||||
|
||||
func gc() {
|
||||
if !debugSyncGC {
|
||||
return
|
||||
}
|
||||
runtime.GC()
|
||||
// debug.FreeOSMemory()
|
||||
}
|
||||
|
||||
func (self *_Assembler) dcall(fn obj.Addr) {
|
||||
self.Emit("MOVQ", fn, _R10) // MOVQ ${fn}, R10
|
||||
self.Rjmp("CALL", _R10) // CALL R10
|
||||
}
|
||||
|
||||
func (self *_Assembler) debug_gc() {
|
||||
if !debugSyncGC {
|
||||
return
|
||||
}
|
||||
self.dsave(_REG_debug...)
|
||||
self.dcall(_F_gc)
|
||||
self.dload(_REG_debug...)
|
||||
}
|
||||
|
||||
func (self *_Assembler) debug_instr(i int, v *_Instr) {
|
||||
if debugSyncGC {
|
||||
if i+1 == len(self.p) {
|
||||
self.print_gc(i, v, &_Instr_End)
|
||||
} else {
|
||||
next := &(self.p[i+1])
|
||||
self.print_gc(i, v, next)
|
||||
name := _OpNames[next.op()]
|
||||
if strings.Contains(name, "save") {
|
||||
return
|
||||
}
|
||||
}
|
||||
// self.debug_gc()
|
||||
}
|
||||
}
|
||||
|
||||
//go:noescape
|
||||
//go:linkname checkptrBase runtime.checkptrBase
|
||||
func checkptrBase(p unsafe.Pointer) uintptr
|
||||
|
||||
//go:noescape
|
||||
//go:linkname findObject runtime.findObject
|
||||
func findObject(p, refBase, refOff uintptr) (base uintptr, s unsafe.Pointer, objIndex uintptr)
|
||||
|
||||
var (
|
||||
_F_checkptr = jit.Func(checkptr)
|
||||
_F_printptr = jit.Func(printptr)
|
||||
)
|
||||
|
||||
var (
|
||||
_R10 = jit.Reg("R10")
|
||||
)
|
||||
var _REG_debug = []obj.Addr {
|
||||
jit.Reg("AX"),
|
||||
jit.Reg("BX"),
|
||||
jit.Reg("CX"),
|
||||
jit.Reg("DX"),
|
||||
jit.Reg("DI"),
|
||||
jit.Reg("SI"),
|
||||
jit.Reg("BP"),
|
||||
jit.Reg("SP"),
|
||||
jit.Reg("R8"),
|
||||
jit.Reg("R9"),
|
||||
jit.Reg("R10"),
|
||||
jit.Reg("R11"),
|
||||
jit.Reg("R12"),
|
||||
jit.Reg("R13"),
|
||||
jit.Reg("R14"),
|
||||
jit.Reg("R15"),
|
||||
}
|
||||
|
||||
func checkptr(ptr uintptr) {
|
||||
if ptr == 0 {
|
||||
return
|
||||
}
|
||||
fmt.Printf("pointer: %x\n", ptr)
|
||||
f := checkptrBase(unsafe.Pointer(uintptr(ptr)))
|
||||
if f == 0 {
|
||||
fmt.Printf("! unknown-based pointer: %x\n", ptr)
|
||||
} else if f == 1 {
|
||||
fmt.Printf("! stack pointer: %x\n", ptr)
|
||||
} else {
|
||||
fmt.Printf("base: %x\n", f)
|
||||
}
|
||||
findobj(ptr)
|
||||
}
|
||||
|
||||
func findobj(ptr uintptr) {
|
||||
base, s, objIndex := findObject(ptr, 0, 0)
|
||||
if s != nil && base == 0 {
|
||||
fmt.Printf("! invalid pointer: %x\n", ptr)
|
||||
}
|
||||
fmt.Printf("objIndex: %d\n", objIndex)
|
||||
}
|
||||
|
||||
func (self *_Assembler) check_ptr(ptr obj.Addr, lea bool) {
|
||||
if !debugCheckPtr {
|
||||
return
|
||||
}
|
||||
|
||||
self.dsave(_REG_debug...)
|
||||
if lea {
|
||||
self.Emit("LEAQ", ptr, _R10)
|
||||
} else {
|
||||
self.Emit("MOVQ", ptr, _R10)
|
||||
}
|
||||
self.Emit("MOVQ", _R10, jit.Ptr(_SP, 0))
|
||||
self.dcall(_F_checkptr)
|
||||
self.dload(_REG_debug...)
|
||||
}
|
||||
|
||||
func printptr(i int, ptr uintptr) {
|
||||
fmt.Printf("[%d] ptr: %x\n", i, ptr)
|
||||
}
|
||||
|
||||
func (self *_Assembler) print_ptr(i int, ptr obj.Addr, lea bool) {
|
||||
self.dsave(_REG_debug...)
|
||||
if lea {
|
||||
self.Emit("LEAQ", ptr, _R10)
|
||||
} else {
|
||||
self.Emit("MOVQ", ptr, _R10)
|
||||
}
|
||||
|
||||
self.Emit("MOVQ", jit.Imm(int64(i)), _AX)
|
||||
self.Emit("MOVQ", _R10, _BX)
|
||||
self.dcall(_F_printptr)
|
||||
self.dload(_REG_debug...)
|
||||
}
|
||||
328
vendor/github.com/bytedance/sonic/internal/encoder/encoder.go
generated
vendored
Normal file
328
vendor/github.com/bytedance/sonic/internal/encoder/encoder.go
generated
vendored
Normal file
@@ -0,0 +1,328 @@
|
||||
/*
|
||||
* 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 encoder
|
||||
|
||||
import (
|
||||
`bytes`
|
||||
`encoding/json`
|
||||
`reflect`
|
||||
`runtime`
|
||||
`unsafe`
|
||||
|
||||
`github.com/bytedance/sonic/internal/native`
|
||||
`github.com/bytedance/sonic/internal/native/types`
|
||||
`github.com/bytedance/sonic/internal/rt`
|
||||
`github.com/bytedance/sonic/utf8`
|
||||
`github.com/bytedance/sonic/option`
|
||||
)
|
||||
|
||||
// Options is a set of encoding options.
|
||||
type Options uint64
|
||||
|
||||
const (
|
||||
bitSortMapKeys = iota
|
||||
bitEscapeHTML
|
||||
bitCompactMarshaler
|
||||
bitNoQuoteTextMarshaler
|
||||
bitNoNullSliceOrMap
|
||||
bitValidateString
|
||||
|
||||
// used for recursive compile
|
||||
bitPointerValue = 63
|
||||
)
|
||||
|
||||
const (
|
||||
// SortMapKeys indicates that the keys of a map needs to be sorted
|
||||
// before serializing into JSON.
|
||||
// WARNING: This hurts performance A LOT, USE WITH CARE.
|
||||
SortMapKeys Options = 1 << bitSortMapKeys
|
||||
|
||||
// EscapeHTML indicates encoder to escape all HTML characters
|
||||
// after serializing into JSON (see https://pkg.go.dev/encoding/json#HTMLEscape).
|
||||
// WARNING: This hurts performance A LOT, USE WITH CARE.
|
||||
EscapeHTML Options = 1 << bitEscapeHTML
|
||||
|
||||
// CompactMarshaler indicates that the output JSON from json.Marshaler
|
||||
// is always compact and needs no validation
|
||||
CompactMarshaler Options = 1 << bitCompactMarshaler
|
||||
|
||||
// NoQuoteTextMarshaler indicates that the output text from encoding.TextMarshaler
|
||||
// is always escaped string and needs no quoting
|
||||
NoQuoteTextMarshaler Options = 1 << bitNoQuoteTextMarshaler
|
||||
|
||||
// NoNullSliceOrMap indicates all empty Array or Object are encoded as '[]' or '{}',
|
||||
// instead of 'null'
|
||||
NoNullSliceOrMap Options = 1 << bitNoNullSliceOrMap
|
||||
|
||||
// ValidateString indicates that encoder should validate the input string
|
||||
// before encoding it into JSON.
|
||||
ValidateString Options = 1 << bitValidateString
|
||||
|
||||
// CompatibleWithStd is used to be compatible with std encoder.
|
||||
CompatibleWithStd Options = SortMapKeys | EscapeHTML | CompactMarshaler
|
||||
)
|
||||
|
||||
// Encoder represents a specific set of encoder configurations.
|
||||
type Encoder struct {
|
||||
Opts Options
|
||||
prefix string
|
||||
indent string
|
||||
}
|
||||
|
||||
// Encode returns the JSON encoding of v.
|
||||
func (self *Encoder) Encode(v interface{}) ([]byte, error) {
|
||||
if self.indent != "" || self.prefix != "" {
|
||||
return EncodeIndented(v, self.prefix, self.indent, self.Opts)
|
||||
}
|
||||
return Encode(v, self.Opts)
|
||||
}
|
||||
|
||||
// SortKeys enables the SortMapKeys option.
|
||||
func (self *Encoder) SortKeys() *Encoder {
|
||||
self.Opts |= SortMapKeys
|
||||
return self
|
||||
}
|
||||
|
||||
// SetEscapeHTML specifies if option EscapeHTML opens
|
||||
func (self *Encoder) SetEscapeHTML(f bool) {
|
||||
if f {
|
||||
self.Opts |= EscapeHTML
|
||||
} else {
|
||||
self.Opts &= ^EscapeHTML
|
||||
}
|
||||
}
|
||||
|
||||
// SetValidateString specifies if option ValidateString opens
|
||||
func (self *Encoder) SetValidateString(f bool) {
|
||||
if f {
|
||||
self.Opts |= ValidateString
|
||||
} else {
|
||||
self.Opts &= ^ValidateString
|
||||
}
|
||||
}
|
||||
|
||||
// SetCompactMarshaler specifies if option CompactMarshaler opens
|
||||
func (self *Encoder) SetCompactMarshaler(f bool) {
|
||||
if f {
|
||||
self.Opts |= CompactMarshaler
|
||||
} else {
|
||||
self.Opts &= ^CompactMarshaler
|
||||
}
|
||||
}
|
||||
|
||||
// SetNoQuoteTextMarshaler specifies if option NoQuoteTextMarshaler opens
|
||||
func (self *Encoder) SetNoQuoteTextMarshaler(f bool) {
|
||||
if f {
|
||||
self.Opts |= NoQuoteTextMarshaler
|
||||
} else {
|
||||
self.Opts &= ^NoQuoteTextMarshaler
|
||||
}
|
||||
}
|
||||
|
||||
// SetIndent instructs the encoder to format each subsequent encoded
|
||||
// value as if indented by the package-level function EncodeIndent().
|
||||
// Calling SetIndent("", "") disables indentation.
|
||||
func (enc *Encoder) SetIndent(prefix, indent string) {
|
||||
enc.prefix = prefix
|
||||
enc.indent = indent
|
||||
}
|
||||
|
||||
// Quote returns the JSON-quoted version of s.
|
||||
func Quote(s string) string {
|
||||
var n int
|
||||
var p []byte
|
||||
|
||||
/* check for empty string */
|
||||
if s == "" {
|
||||
return `""`
|
||||
}
|
||||
|
||||
/* allocate space for result */
|
||||
n = len(s) + 2
|
||||
p = make([]byte, 0, n)
|
||||
|
||||
/* call the encoder */
|
||||
_ = encodeString(&p, s)
|
||||
return rt.Mem2Str(p)
|
||||
}
|
||||
|
||||
// Encode returns the JSON encoding of val, encoded with opts.
|
||||
func Encode(val interface{}, opts Options) ([]byte, error) {
|
||||
var ret []byte
|
||||
|
||||
buf := newBytes()
|
||||
err := encodeInto(&buf, val, opts)
|
||||
|
||||
/* check for errors */
|
||||
if err != nil {
|
||||
freeBytes(buf)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
/* htmlescape or correct UTF-8 if opts enable */
|
||||
old := buf
|
||||
buf = encodeFinish(old, opts)
|
||||
pbuf := ((*rt.GoSlice)(unsafe.Pointer(&buf))).Ptr
|
||||
pold := ((*rt.GoSlice)(unsafe.Pointer(&old))).Ptr
|
||||
|
||||
/* return when allocated a new buffer */
|
||||
if pbuf != pold {
|
||||
freeBytes(old)
|
||||
return buf, nil
|
||||
}
|
||||
|
||||
/* make a copy of the result */
|
||||
ret = make([]byte, len(buf))
|
||||
copy(ret, buf)
|
||||
|
||||
freeBytes(buf)
|
||||
/* return the buffer into pool */
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// EncodeInto is like Encode but uses a user-supplied buffer instead of allocating
|
||||
// a new one.
|
||||
func EncodeInto(buf *[]byte, val interface{}, opts Options) error {
|
||||
err := encodeInto(buf, val, opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*buf = encodeFinish(*buf, opts)
|
||||
return err
|
||||
}
|
||||
|
||||
func encodeInto(buf *[]byte, val interface{}, opts Options) error {
|
||||
stk := newStack()
|
||||
efv := rt.UnpackEface(val)
|
||||
err := encodeTypedPointer(buf, efv.Type, &efv.Value, stk, uint64(opts))
|
||||
|
||||
/* return the stack into pool */
|
||||
if err != nil {
|
||||
resetStack(stk)
|
||||
}
|
||||
freeStack(stk)
|
||||
|
||||
/* avoid GC ahead */
|
||||
runtime.KeepAlive(buf)
|
||||
runtime.KeepAlive(efv)
|
||||
return err
|
||||
}
|
||||
|
||||
func encodeFinish(buf []byte, opts Options) []byte {
|
||||
if opts & EscapeHTML != 0 {
|
||||
buf = HTMLEscape(nil, buf)
|
||||
}
|
||||
if opts & ValidateString != 0 && !utf8.Validate(buf) {
|
||||
buf = utf8.CorrectWith(nil, buf, `\ufffd`)
|
||||
}
|
||||
return buf
|
||||
}
|
||||
|
||||
var typeByte = rt.UnpackType(reflect.TypeOf(byte(0)))
|
||||
|
||||
// HTMLEscape appends to dst the JSON-encoded src with <, >, &, U+2028 and U+2029
|
||||
// characters inside string literals changed to \u003c, \u003e, \u0026, \u2028, \u2029
|
||||
// so that the JSON will be safe to embed inside HTML <script> tags.
|
||||
// For historical reasons, web browsers don't honor standard HTML
|
||||
// escaping within <script> tags, so an alternative JSON encoding must
|
||||
// be used.
|
||||
func HTMLEscape(dst []byte, src []byte) []byte {
|
||||
return htmlEscape(dst, src)
|
||||
}
|
||||
|
||||
// EncodeIndented is like Encode but applies Indent to format the output.
|
||||
// Each JSON element in the output will begin on a new line beginning with prefix
|
||||
// followed by one or more copies of indent according to the indentation nesting.
|
||||
func EncodeIndented(val interface{}, prefix string, indent string, opts Options) ([]byte, error) {
|
||||
var err error
|
||||
var out []byte
|
||||
var buf *bytes.Buffer
|
||||
|
||||
/* encode into the buffer */
|
||||
out = newBytes()
|
||||
err = EncodeInto(&out, val, opts)
|
||||
|
||||
/* check for errors */
|
||||
if err != nil {
|
||||
freeBytes(out)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
/* indent the JSON */
|
||||
buf = newBuffer()
|
||||
err = json.Indent(buf, out, prefix, indent)
|
||||
|
||||
/* check for errors */
|
||||
if err != nil {
|
||||
freeBytes(out)
|
||||
freeBuffer(buf)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
/* copy to the result buffer */
|
||||
ret := make([]byte, buf.Len())
|
||||
copy(ret, buf.Bytes())
|
||||
|
||||
/* return the buffers into pool */
|
||||
freeBytes(out)
|
||||
freeBuffer(buf)
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// Pretouch compiles vt ahead-of-time to avoid JIT compilation on-the-fly, in
|
||||
// order to reduce the first-hit latency.
|
||||
//
|
||||
// Opts are the compile options, for example, "option.WithCompileRecursiveDepth" is
|
||||
// a compile option to set the depth of recursive compile for the nested struct type.
|
||||
func Pretouch(vt reflect.Type, opts ...option.CompileOption) error {
|
||||
cfg := option.DefaultCompileOptions()
|
||||
for _, opt := range opts {
|
||||
opt(&cfg)
|
||||
break
|
||||
}
|
||||
return pretouchRec(map[reflect.Type]uint8{vt: 0}, cfg)
|
||||
}
|
||||
|
||||
// Valid validates json and returns first non-blank character position,
|
||||
// if it is only one valid json value.
|
||||
// Otherwise returns invalid character position using start.
|
||||
//
|
||||
// Note: it does not check for the invalid UTF-8 characters.
|
||||
func Valid(data []byte) (ok bool, start int) {
|
||||
n := len(data)
|
||||
if n == 0 {
|
||||
return false, -1
|
||||
}
|
||||
s := rt.Mem2Str(data)
|
||||
p := 0
|
||||
m := types.NewStateMachine()
|
||||
ret := native.ValidateOne(&s, &p, m)
|
||||
types.FreeStateMachine(m)
|
||||
|
||||
if ret < 0 {
|
||||
return false, p-1
|
||||
}
|
||||
|
||||
/* check for trailing spaces */
|
||||
for ;p < n; p++ {
|
||||
if (types.SPACE_MASK & (1 << data[p])) == 0 {
|
||||
return false, p
|
||||
}
|
||||
}
|
||||
|
||||
return true, ret
|
||||
}
|
||||
65
vendor/github.com/bytedance/sonic/internal/encoder/errors.go
generated
vendored
Normal file
65
vendor/github.com/bytedance/sonic/internal/encoder/errors.go
generated
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* 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 encoder
|
||||
|
||||
import (
|
||||
`encoding/json`
|
||||
`fmt`
|
||||
`reflect`
|
||||
`strconv`
|
||||
`unsafe`
|
||||
|
||||
`github.com/bytedance/sonic/internal/rt`
|
||||
)
|
||||
|
||||
var _ERR_too_deep = &json.UnsupportedValueError {
|
||||
Str : "Value nesting too deep",
|
||||
Value : reflect.ValueOf("..."),
|
||||
}
|
||||
|
||||
var _ERR_nan_or_infinite = &json.UnsupportedValueError {
|
||||
Str : "NaN or ±Infinite",
|
||||
Value : reflect.ValueOf("NaN or ±Infinite"),
|
||||
}
|
||||
|
||||
func error_type(vtype reflect.Type) error {
|
||||
return &json.UnsupportedTypeError{Type: vtype}
|
||||
}
|
||||
|
||||
func error_number(number json.Number) error {
|
||||
return &json.UnsupportedValueError {
|
||||
Str : "invalid number literal: " + strconv.Quote(string(number)),
|
||||
Value : reflect.ValueOf(number),
|
||||
}
|
||||
}
|
||||
|
||||
func error_marshaler(ret []byte, pos int) error {
|
||||
return fmt.Errorf("invalid Marshaler output json syntax at %d: %q", pos, ret)
|
||||
}
|
||||
|
||||
const (
|
||||
panicNilPointerOfNonEmptyString int = 1 + iota
|
||||
)
|
||||
|
||||
func goPanic(code int, val unsafe.Pointer) {
|
||||
switch(code){
|
||||
case panicNilPointerOfNonEmptyString:
|
||||
panic(fmt.Sprintf("val: %#v has nil pointer while its length is not zero!", (*rt.GoString)(val)))
|
||||
default:
|
||||
panic("encoder error!")
|
||||
}
|
||||
}
|
||||
199
vendor/github.com/bytedance/sonic/internal/encoder/mapiter.go
generated
vendored
Normal file
199
vendor/github.com/bytedance/sonic/internal/encoder/mapiter.go
generated
vendored
Normal file
@@ -0,0 +1,199 @@
|
||||
/*
|
||||
* 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 encoder
|
||||
|
||||
import (
|
||||
"encoding"
|
||||
"reflect"
|
||||
"sync"
|
||||
"unsafe"
|
||||
|
||||
"github.com/bytedance/sonic/internal/native"
|
||||
"github.com/bytedance/sonic/internal/rt"
|
||||
)
|
||||
|
||||
type _MapPair struct {
|
||||
k string // when the map key is integer, k is pointed to m
|
||||
v unsafe.Pointer
|
||||
m [32]byte
|
||||
}
|
||||
|
||||
type _MapIterator struct {
|
||||
it rt.GoMapIterator // must be the first field
|
||||
kv rt.GoSlice // slice of _MapPair
|
||||
ki int
|
||||
}
|
||||
|
||||
var (
|
||||
iteratorPool = sync.Pool{}
|
||||
iteratorPair = rt.UnpackType(reflect.TypeOf(_MapPair{}))
|
||||
)
|
||||
|
||||
func init() {
|
||||
if unsafe.Offsetof(_MapIterator{}.it) != 0 {
|
||||
panic("_MapIterator.it is not the first field")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func newIterator() *_MapIterator {
|
||||
if v := iteratorPool.Get(); v == nil {
|
||||
return new(_MapIterator)
|
||||
} else {
|
||||
return resetIterator(v.(*_MapIterator))
|
||||
}
|
||||
}
|
||||
|
||||
func resetIterator(p *_MapIterator) *_MapIterator {
|
||||
p.ki = 0
|
||||
p.it = rt.GoMapIterator{}
|
||||
p.kv.Len = 0
|
||||
return p
|
||||
}
|
||||
|
||||
func (self *_MapIterator) at(i int) *_MapPair {
|
||||
return (*_MapPair)(unsafe.Pointer(uintptr(self.kv.Ptr) + uintptr(i) * unsafe.Sizeof(_MapPair{})))
|
||||
}
|
||||
|
||||
func (self *_MapIterator) add() (p *_MapPair) {
|
||||
p = self.at(self.kv.Len)
|
||||
self.kv.Len++
|
||||
return
|
||||
}
|
||||
|
||||
func (self *_MapIterator) data() (p []_MapPair) {
|
||||
*(*rt.GoSlice)(unsafe.Pointer(&p)) = self.kv
|
||||
return
|
||||
}
|
||||
|
||||
func (self *_MapIterator) append(t *rt.GoType, k unsafe.Pointer, v unsafe.Pointer) (err error) {
|
||||
p := self.add()
|
||||
p.v = v
|
||||
|
||||
/* check for strings */
|
||||
if tk := t.Kind(); tk != reflect.String {
|
||||
return self.appendGeneric(p, t, tk, k)
|
||||
}
|
||||
|
||||
/* fast path for strings */
|
||||
p.k = *(*string)(k)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (self *_MapIterator) appendGeneric(p *_MapPair, t *rt.GoType, v reflect.Kind, k unsafe.Pointer) error {
|
||||
switch v {
|
||||
case reflect.Int : p.k = rt.Mem2Str(p.m[:native.I64toa(&p.m[0], int64(*(*int)(k)))]) ; return nil
|
||||
case reflect.Int8 : p.k = rt.Mem2Str(p.m[:native.I64toa(&p.m[0], int64(*(*int8)(k)))]) ; return nil
|
||||
case reflect.Int16 : p.k = rt.Mem2Str(p.m[:native.I64toa(&p.m[0], int64(*(*int16)(k)))]) ; return nil
|
||||
case reflect.Int32 : p.k = rt.Mem2Str(p.m[:native.I64toa(&p.m[0], int64(*(*int32)(k)))]) ; return nil
|
||||
case reflect.Int64 : p.k = rt.Mem2Str(p.m[:native.I64toa(&p.m[0], *(*int64)(k))]) ; return nil
|
||||
case reflect.Uint : p.k = rt.Mem2Str(p.m[:native.U64toa(&p.m[0], uint64(*(*uint)(k)))]) ; return nil
|
||||
case reflect.Uint8 : p.k = rt.Mem2Str(p.m[:native.U64toa(&p.m[0], uint64(*(*uint8)(k)))]) ; return nil
|
||||
case reflect.Uint16 : p.k = rt.Mem2Str(p.m[:native.U64toa(&p.m[0], uint64(*(*uint16)(k)))]) ; return nil
|
||||
case reflect.Uint32 : p.k = rt.Mem2Str(p.m[:native.U64toa(&p.m[0], uint64(*(*uint32)(k)))]) ; return nil
|
||||
case reflect.Uint64 : p.k = rt.Mem2Str(p.m[:native.U64toa(&p.m[0], *(*uint64)(k))]) ; return nil
|
||||
case reflect.Uintptr : p.k = rt.Mem2Str(p.m[:native.U64toa(&p.m[0], uint64(*(*uintptr)(k)))]) ; return nil
|
||||
case reflect.Interface : return self.appendInterface(p, t, k)
|
||||
case reflect.Struct, reflect.Ptr : return self.appendConcrete(p, t, k)
|
||||
default : panic("unexpected map key type")
|
||||
}
|
||||
}
|
||||
|
||||
func (self *_MapIterator) appendConcrete(p *_MapPair, t *rt.GoType, k unsafe.Pointer) (err error) {
|
||||
// compiler has already checked that the type implements the encoding.MarshalText interface
|
||||
if !t.Indirect() {
|
||||
k = *(*unsafe.Pointer)(k)
|
||||
}
|
||||
eface := rt.GoEface{Value: k, Type: t}.Pack()
|
||||
out, err := eface.(encoding.TextMarshaler).MarshalText()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
p.k = rt.Mem2Str(out)
|
||||
return
|
||||
}
|
||||
|
||||
func (self *_MapIterator) appendInterface(p *_MapPair, t *rt.GoType, k unsafe.Pointer) (err error) {
|
||||
if len(rt.IfaceType(t).Methods) == 0 {
|
||||
panic("unexpected map key type")
|
||||
} else if p.k, err = asText(k); err == nil {
|
||||
return nil
|
||||
} else {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func iteratorStop(p *_MapIterator) {
|
||||
iteratorPool.Put(p)
|
||||
}
|
||||
|
||||
func iteratorNext(p *_MapIterator) {
|
||||
i := p.ki
|
||||
t := &p.it
|
||||
|
||||
/* check for unordered iteration */
|
||||
if i < 0 {
|
||||
mapiternext(t)
|
||||
return
|
||||
}
|
||||
|
||||
/* check for end of iteration */
|
||||
if p.ki >= p.kv.Len {
|
||||
t.K = nil
|
||||
t.V = nil
|
||||
return
|
||||
}
|
||||
|
||||
/* update the key-value pair, and increase the pointer */
|
||||
t.K = unsafe.Pointer(&p.at(p.ki).k)
|
||||
t.V = p.at(p.ki).v
|
||||
p.ki++
|
||||
}
|
||||
|
||||
func iteratorStart(t *rt.GoMapType, m *rt.GoMap, fv uint64) (*_MapIterator, error) {
|
||||
it := newIterator()
|
||||
mapiterinit(t, m, &it.it)
|
||||
|
||||
/* check for key-sorting, empty map don't need sorting */
|
||||
if m.Count == 0 || (fv & uint64(SortMapKeys)) == 0 {
|
||||
it.ki = -1
|
||||
return it, nil
|
||||
}
|
||||
|
||||
/* pre-allocate space if needed */
|
||||
if m.Count > it.kv.Cap {
|
||||
it.kv = growslice(iteratorPair, it.kv, m.Count)
|
||||
}
|
||||
|
||||
/* dump all the key-value pairs */
|
||||
for ; it.it.K != nil; mapiternext(&it.it) {
|
||||
if err := it.append(t.Key, it.it.K, it.it.V); err != nil {
|
||||
iteratorStop(it)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
/* sort the keys, map with only 1 item don't need sorting */
|
||||
if it.ki = 1; m.Count > 1 {
|
||||
radixQsort(it.data(), 0, maxDepth(it.kv.Len))
|
||||
}
|
||||
|
||||
/* load the first pair into iterator */
|
||||
it.it.V = it.at(0).v
|
||||
it.it.K = unsafe.Pointer(&it.at(0).k)
|
||||
return it, nil
|
||||
}
|
||||
193
vendor/github.com/bytedance/sonic/internal/encoder/pools.go
generated
vendored
Normal file
193
vendor/github.com/bytedance/sonic/internal/encoder/pools.go
generated
vendored
Normal file
@@ -0,0 +1,193 @@
|
||||
/*
|
||||
* 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 encoder
|
||||
|
||||
import (
|
||||
`bytes`
|
||||
`sync`
|
||||
`unsafe`
|
||||
`errors`
|
||||
`reflect`
|
||||
|
||||
`github.com/bytedance/sonic/internal/caching`
|
||||
`github.com/bytedance/sonic/option`
|
||||
`github.com/bytedance/sonic/internal/rt`
|
||||
)
|
||||
|
||||
const (
|
||||
_MaxStack = 4096 // 4k states
|
||||
|
||||
_StackSize = unsafe.Sizeof(_Stack{})
|
||||
)
|
||||
|
||||
var (
|
||||
bytesPool = sync.Pool{}
|
||||
stackPool = sync.Pool{}
|
||||
bufferPool = sync.Pool{}
|
||||
programCache = caching.CreateProgramCache()
|
||||
)
|
||||
|
||||
type _State struct {
|
||||
x int
|
||||
f uint64
|
||||
p unsafe.Pointer
|
||||
q unsafe.Pointer
|
||||
}
|
||||
|
||||
type _Stack struct {
|
||||
sp uint64
|
||||
sb [_MaxStack]_State
|
||||
}
|
||||
|
||||
type _Encoder func(
|
||||
rb *[]byte,
|
||||
vp unsafe.Pointer,
|
||||
sb *_Stack,
|
||||
fv uint64,
|
||||
) error
|
||||
|
||||
var _KeepAlive struct {
|
||||
rb *[]byte
|
||||
vp unsafe.Pointer
|
||||
sb *_Stack
|
||||
fv uint64
|
||||
err error
|
||||
frame [_FP_offs]byte
|
||||
}
|
||||
|
||||
var errCallShadow = errors.New("DON'T CALL THIS!")
|
||||
|
||||
// Faker func of _Encoder, used to export its stackmap as _Encoder's
|
||||
func _Encoder_Shadow(rb *[]byte, vp unsafe.Pointer, sb *_Stack, fv uint64) (err error) {
|
||||
// align to assembler_amd64.go: _FP_offs
|
||||
var frame [_FP_offs]byte
|
||||
|
||||
// must keep all args and frames noticeable to GC
|
||||
_KeepAlive.rb = rb
|
||||
_KeepAlive.vp = vp
|
||||
_KeepAlive.sb = sb
|
||||
_KeepAlive.fv = fv
|
||||
_KeepAlive.err = err
|
||||
_KeepAlive.frame = frame
|
||||
|
||||
return errCallShadow
|
||||
}
|
||||
|
||||
func newBytes() []byte {
|
||||
if ret := bytesPool.Get(); ret != nil {
|
||||
return ret.([]byte)
|
||||
} else {
|
||||
return make([]byte, 0, option.DefaultEncoderBufferSize)
|
||||
}
|
||||
}
|
||||
|
||||
func newStack() *_Stack {
|
||||
if ret := stackPool.Get(); ret == nil {
|
||||
return new(_Stack)
|
||||
} else {
|
||||
return ret.(*_Stack)
|
||||
}
|
||||
}
|
||||
|
||||
func resetStack(p *_Stack) {
|
||||
memclrNoHeapPointers(unsafe.Pointer(p), _StackSize)
|
||||
}
|
||||
|
||||
func newBuffer() *bytes.Buffer {
|
||||
if ret := bufferPool.Get(); ret != nil {
|
||||
return ret.(*bytes.Buffer)
|
||||
} else {
|
||||
return bytes.NewBuffer(make([]byte, 0, option.DefaultEncoderBufferSize))
|
||||
}
|
||||
}
|
||||
|
||||
func freeBytes(p []byte) {
|
||||
p = p[:0]
|
||||
bytesPool.Put(p)
|
||||
}
|
||||
|
||||
func freeStack(p *_Stack) {
|
||||
p.sp = 0
|
||||
stackPool.Put(p)
|
||||
}
|
||||
|
||||
func freeBuffer(p *bytes.Buffer) {
|
||||
p.Reset()
|
||||
bufferPool.Put(p)
|
||||
}
|
||||
|
||||
func makeEncoder(vt *rt.GoType, ex ...interface{}) (interface{}, error) {
|
||||
if pp, err := newCompiler().compile(vt.Pack(), ex[0].(bool)); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
as := newAssembler(pp)
|
||||
as.name = vt.String()
|
||||
return as.Load(), nil
|
||||
}
|
||||
}
|
||||
|
||||
func findOrCompile(vt *rt.GoType, pv bool) (_Encoder, error) {
|
||||
if val := programCache.Get(vt); val != nil {
|
||||
return val.(_Encoder), nil
|
||||
} else if ret, err := programCache.Compute(vt, makeEncoder, pv); err == nil {
|
||||
return ret.(_Encoder), nil
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
func pretouchType(_vt reflect.Type, opts option.CompileOptions, v uint8) (map[reflect.Type]uint8, error) {
|
||||
/* compile function */
|
||||
compiler := newCompiler().apply(opts)
|
||||
encoder := func(vt *rt.GoType, ex ...interface{}) (interface{}, error) {
|
||||
if pp, err := compiler.compile(_vt, ex[0].(bool)); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
as := newAssembler(pp)
|
||||
as.name = vt.String()
|
||||
return as.Load(), nil
|
||||
}
|
||||
}
|
||||
|
||||
/* find or compile */
|
||||
vt := rt.UnpackType(_vt)
|
||||
if val := programCache.Get(vt); val != nil {
|
||||
return nil, nil
|
||||
} else if _, err := programCache.Compute(vt, encoder, v == 1); err == nil {
|
||||
return compiler.rec, nil
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
func pretouchRec(vtm map[reflect.Type]uint8, opts option.CompileOptions) error {
|
||||
if opts.RecursiveDepth < 0 || len(vtm) == 0 {
|
||||
return nil
|
||||
}
|
||||
next := make(map[reflect.Type]uint8)
|
||||
for vt, v := range vtm {
|
||||
sub, err := pretouchType(vt, opts, v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for svt, v := range sub {
|
||||
next[svt] = v
|
||||
}
|
||||
}
|
||||
opts.RecursiveDepth -= 1
|
||||
return pretouchRec(next, opts)
|
||||
}
|
||||
168
vendor/github.com/bytedance/sonic/internal/encoder/primitives.go
generated
vendored
Normal file
168
vendor/github.com/bytedance/sonic/internal/encoder/primitives.go
generated
vendored
Normal file
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
* 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 encoder
|
||||
|
||||
import (
|
||||
`encoding`
|
||||
`encoding/json`
|
||||
`unsafe`
|
||||
|
||||
`github.com/bytedance/sonic/internal/jit`
|
||||
`github.com/bytedance/sonic/internal/native`
|
||||
`github.com/bytedance/sonic/internal/rt`
|
||||
)
|
||||
|
||||
/** Encoder Primitives **/
|
||||
|
||||
func encodeNil(rb *[]byte) error {
|
||||
*rb = append(*rb, 'n', 'u', 'l', 'l')
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeString(buf *[]byte, val string) error {
|
||||
var sidx int
|
||||
var pbuf *rt.GoSlice
|
||||
var pstr *rt.GoString
|
||||
|
||||
/* opening quote */
|
||||
*buf = append(*buf, '"')
|
||||
pbuf = (*rt.GoSlice)(unsafe.Pointer(buf))
|
||||
pstr = (*rt.GoString)(unsafe.Pointer(&val))
|
||||
|
||||
/* encode with native library */
|
||||
for sidx < pstr.Len {
|
||||
sn := pstr.Len - sidx
|
||||
dn := pbuf.Cap - pbuf.Len
|
||||
sp := padd(pstr.Ptr, sidx)
|
||||
dp := padd(pbuf.Ptr, pbuf.Len)
|
||||
nb := native.Quote(sp, sn, dp, &dn, 0)
|
||||
|
||||
/* check for errors */
|
||||
if pbuf.Len += dn; nb >= 0 {
|
||||
break
|
||||
}
|
||||
|
||||
/* not enough space, grow the slice and try again */
|
||||
sidx += ^nb
|
||||
*pbuf = growslice(rt.UnpackType(byteType), *pbuf, pbuf.Cap * 2)
|
||||
}
|
||||
|
||||
/* closing quote */
|
||||
*buf = append(*buf, '"')
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeTypedPointer(buf *[]byte, vt *rt.GoType, vp *unsafe.Pointer, sb *_Stack, fv uint64) error {
|
||||
if vt == nil {
|
||||
return encodeNil(buf)
|
||||
} else if fn, err := findOrCompile(vt, (fv&(1<<bitPointerValue)) != 0); err != nil {
|
||||
return err
|
||||
} else if vt.Indirect() {
|
||||
rt.MoreStack(_FP_size + native.MaxFrameSize)
|
||||
rt.StopProf()
|
||||
err := fn(buf, *vp, sb, fv)
|
||||
rt.StartProf()
|
||||
return err
|
||||
} else {
|
||||
rt.MoreStack(_FP_size + native.MaxFrameSize)
|
||||
rt.StopProf()
|
||||
err := fn(buf, unsafe.Pointer(vp), sb, fv)
|
||||
rt.StartProf()
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
func encodeJsonMarshaler(buf *[]byte, val json.Marshaler, opt Options) error {
|
||||
if ret, err := val.MarshalJSON(); err != nil {
|
||||
return err
|
||||
} else {
|
||||
if opt & CompactMarshaler != 0 {
|
||||
return compact(buf, ret)
|
||||
}
|
||||
if ok, s := Valid(ret); !ok {
|
||||
return error_marshaler(ret, s)
|
||||
}
|
||||
*buf = append(*buf, ret...)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func encodeTextMarshaler(buf *[]byte, val encoding.TextMarshaler, opt Options) error {
|
||||
if ret, err := val.MarshalText(); err != nil {
|
||||
return err
|
||||
} else {
|
||||
if opt & NoQuoteTextMarshaler != 0 {
|
||||
*buf = append(*buf, ret...)
|
||||
return nil
|
||||
}
|
||||
return encodeString(buf, rt.Mem2Str(ret) )
|
||||
}
|
||||
}
|
||||
|
||||
func htmlEscape(dst []byte, src []byte) []byte {
|
||||
var sidx int
|
||||
|
||||
dst = append(dst, src[:0]...) // avoid check nil dst
|
||||
sbuf := (*rt.GoSlice)(unsafe.Pointer(&src))
|
||||
dbuf := (*rt.GoSlice)(unsafe.Pointer(&dst))
|
||||
|
||||
/* grow dst if it is shorter */
|
||||
if cap(dst) - len(dst) < len(src) + native.BufPaddingSize {
|
||||
cap := len(src) * 3 / 2 + native.BufPaddingSize
|
||||
*dbuf = growslice(typeByte, *dbuf, cap)
|
||||
}
|
||||
|
||||
for sidx < sbuf.Len {
|
||||
sp := padd(sbuf.Ptr, sidx)
|
||||
dp := padd(dbuf.Ptr, dbuf.Len)
|
||||
|
||||
sn := sbuf.Len - sidx
|
||||
dn := dbuf.Cap - dbuf.Len
|
||||
nb := native.HTMLEscape(sp, sn, dp, &dn)
|
||||
|
||||
/* check for errors */
|
||||
if dbuf.Len += dn; nb >= 0 {
|
||||
break
|
||||
}
|
||||
|
||||
/* not enough space, grow the slice and try again */
|
||||
sidx += ^nb
|
||||
*dbuf = growslice(typeByte, *dbuf, dbuf.Cap * 2)
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
var (
|
||||
argPtrs = []bool { true, true, true, false }
|
||||
localPtrs = []bool{}
|
||||
)
|
||||
|
||||
var (
|
||||
_F_assertI2I = jit.Func(assertI2I)
|
||||
)
|
||||
|
||||
func asText(v unsafe.Pointer) (string, error) {
|
||||
text := assertI2I(_T_encoding_TextMarshaler, *(*rt.GoIface)(v))
|
||||
r, e := (*(*encoding.TextMarshaler)(unsafe.Pointer(&text))).MarshalText()
|
||||
return rt.Mem2Str(r), e
|
||||
}
|
||||
|
||||
func asJson(v unsafe.Pointer) (string, error) {
|
||||
text := assertI2I(_T_json_Marshaler, *(*rt.GoIface)(v))
|
||||
r, e := (*(*json.Marshaler)(unsafe.Pointer(&text))).MarshalJSON()
|
||||
return rt.Mem2Str(r), e
|
||||
}
|
||||
206
vendor/github.com/bytedance/sonic/internal/encoder/sort.go
generated
vendored
Normal file
206
vendor/github.com/bytedance/sonic/internal/encoder/sort.go
generated
vendored
Normal file
@@ -0,0 +1,206 @@
|
||||
/*
|
||||
* 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 encoder
|
||||
|
||||
// Algorithm 3-way Radix Quicksort, d means the radix.
|
||||
// Reference: https://algs4.cs.princeton.edu/51radix/Quick3string.java.html
|
||||
func radixQsort(kvs []_MapPair, d, maxDepth int) {
|
||||
for len(kvs) > 11 {
|
||||
// To avoid the worst case of quickSort (time: O(n^2)), use introsort here.
|
||||
// Reference: https://en.wikipedia.org/wiki/Introsort and
|
||||
// https://github.com/golang/go/issues/467
|
||||
if maxDepth == 0 {
|
||||
heapSort(kvs, 0, len(kvs))
|
||||
return
|
||||
}
|
||||
maxDepth--
|
||||
|
||||
p := pivot(kvs, d)
|
||||
lt, i, gt := 0, 0, len(kvs)
|
||||
for i < gt {
|
||||
c := byteAt(kvs[i].k, d)
|
||||
if c < p {
|
||||
swap(kvs, lt, i)
|
||||
i++
|
||||
lt++
|
||||
} else if c > p {
|
||||
gt--
|
||||
swap(kvs, i, gt)
|
||||
} else {
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
||||
// kvs[0:lt] < v = kvs[lt:gt] < kvs[gt:len(kvs)]
|
||||
// Native implemention:
|
||||
// radixQsort(kvs[:lt], d, maxDepth)
|
||||
// if p > -1 {
|
||||
// radixQsort(kvs[lt:gt], d+1, maxDepth)
|
||||
// }
|
||||
// radixQsort(kvs[gt:], d, maxDepth)
|
||||
// Optimize as follows: make recursive calls only for the smaller parts.
|
||||
// Reference: https://www.geeksforgeeks.org/quicksort-tail-call-optimization-reducing-worst-case-space-log-n/
|
||||
if p == -1 {
|
||||
if lt > len(kvs) - gt {
|
||||
radixQsort(kvs[gt:], d, maxDepth)
|
||||
kvs = kvs[:lt]
|
||||
} else {
|
||||
radixQsort(kvs[:lt], d, maxDepth)
|
||||
kvs = kvs[gt:]
|
||||
}
|
||||
} else {
|
||||
ml := maxThree(lt, gt-lt, len(kvs)-gt)
|
||||
if ml == lt {
|
||||
radixQsort(kvs[lt:gt], d+1, maxDepth)
|
||||
radixQsort(kvs[gt:], d, maxDepth)
|
||||
kvs = kvs[:lt]
|
||||
} else if ml == gt-lt {
|
||||
radixQsort(kvs[:lt], d, maxDepth)
|
||||
radixQsort(kvs[gt:], d, maxDepth)
|
||||
kvs = kvs[lt:gt]
|
||||
d += 1
|
||||
} else {
|
||||
radixQsort(kvs[:lt], d, maxDepth)
|
||||
radixQsort(kvs[lt:gt], d+1, maxDepth)
|
||||
kvs = kvs[gt:]
|
||||
}
|
||||
}
|
||||
}
|
||||
insertRadixSort(kvs, d)
|
||||
}
|
||||
|
||||
func insertRadixSort(kvs []_MapPair, d int) {
|
||||
for i := 1; i < len(kvs); i++ {
|
||||
for j := i; j > 0 && lessFrom(kvs[j].k, kvs[j-1].k, d); j-- {
|
||||
swap(kvs, j, j-1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func pivot(kvs []_MapPair, d int) int {
|
||||
m := len(kvs) >> 1
|
||||
if len(kvs) > 40 {
|
||||
// Tukey's ``Ninther,'' median of three mediankvs of three.
|
||||
t := len(kvs) / 8
|
||||
return medianThree(
|
||||
medianThree(byteAt(kvs[0].k, d), byteAt(kvs[t].k, d), byteAt(kvs[2*t].k, d)),
|
||||
medianThree(byteAt(kvs[m].k, d), byteAt(kvs[m-t].k, d), byteAt(kvs[m+t].k, d)),
|
||||
medianThree(byteAt(kvs[len(kvs)-1].k, d),
|
||||
byteAt(kvs[len(kvs)-1-t].k, d),
|
||||
byteAt(kvs[len(kvs)-1-2*t].k, d)))
|
||||
}
|
||||
return medianThree(byteAt(kvs[0].k, d), byteAt(kvs[m].k, d), byteAt(kvs[len(kvs)-1].k, d))
|
||||
}
|
||||
|
||||
func medianThree(i, j, k int) int {
|
||||
if i > j {
|
||||
i, j = j, i
|
||||
} // i < j
|
||||
if k < i {
|
||||
return i
|
||||
}
|
||||
if k > j {
|
||||
return j
|
||||
}
|
||||
return k
|
||||
}
|
||||
|
||||
func maxThree(i, j, k int) int {
|
||||
max := i
|
||||
if max < j {
|
||||
max = j
|
||||
}
|
||||
if max < k {
|
||||
max = k
|
||||
}
|
||||
return max
|
||||
}
|
||||
|
||||
// maxDepth returns a threshold at which quicksort should switch
|
||||
// to heapsort. It returnkvs 2*ceil(lg(n+1)).
|
||||
func maxDepth(n int) int {
|
||||
var depth int
|
||||
for i := n; i > 0; i >>= 1 {
|
||||
depth++
|
||||
}
|
||||
return depth * 2
|
||||
}
|
||||
|
||||
// siftDown implements the heap property on kvs[lo:hi].
|
||||
// first is an offset into the array where the root of the heap lies.
|
||||
func siftDown(kvs []_MapPair, lo, hi, first int) {
|
||||
root := lo
|
||||
for {
|
||||
child := 2*root + 1
|
||||
if child >= hi {
|
||||
break
|
||||
}
|
||||
if child+1 < hi && kvs[first+child].k < kvs[first+child+1].k {
|
||||
child++
|
||||
}
|
||||
if kvs[first+root].k >= kvs[first+child].k {
|
||||
return
|
||||
}
|
||||
swap(kvs, first+root, first+child)
|
||||
root = child
|
||||
}
|
||||
}
|
||||
|
||||
func heapSort(kvs []_MapPair, a, b int) {
|
||||
first := a
|
||||
lo := 0
|
||||
hi := b - a
|
||||
|
||||
// Build heap with the greatest element at top.
|
||||
for i := (hi - 1) / 2; i >= 0; i-- {
|
||||
siftDown(kvs, i, hi, first)
|
||||
}
|
||||
|
||||
// Pop elements, the largest first, into end of kvs.
|
||||
for i := hi - 1; i >= 0; i-- {
|
||||
swap(kvs, first, first+i)
|
||||
siftDown(kvs, lo, i, first)
|
||||
}
|
||||
}
|
||||
|
||||
// Note that _MapPair.k is NOT pointed to _MapPair.m when map key is integer after swap
|
||||
func swap(kvs []_MapPair, a, b int) {
|
||||
kvs[a].k, kvs[b].k = kvs[b].k, kvs[a].k
|
||||
kvs[a].v, kvs[b].v = kvs[b].v, kvs[a].v
|
||||
}
|
||||
|
||||
// Compare two strings from the pos d.
|
||||
func lessFrom(a, b string, d int) bool {
|
||||
l := len(a)
|
||||
if l > len(b) {
|
||||
l = len(b)
|
||||
}
|
||||
for i := d; i < l; i++ {
|
||||
if a[i] == b[i] {
|
||||
continue
|
||||
}
|
||||
return a[i] < b[i]
|
||||
}
|
||||
return len(a) < len(b)
|
||||
}
|
||||
|
||||
func byteAt(b string, p int) int {
|
||||
if p < len(b) {
|
||||
return int(b[p])
|
||||
}
|
||||
return -1
|
||||
}
|
||||
84
vendor/github.com/bytedance/sonic/internal/encoder/stream.go
generated
vendored
Normal file
84
vendor/github.com/bytedance/sonic/internal/encoder/stream.go
generated
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* 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 encoder
|
||||
|
||||
import (
|
||||
`encoding/json`
|
||||
`io`
|
||||
)
|
||||
|
||||
// StreamEncoder uses io.Writer as input.
|
||||
type StreamEncoder struct {
|
||||
w io.Writer
|
||||
Encoder
|
||||
}
|
||||
|
||||
// NewStreamEncoder adapts to encoding/json.NewDecoder API.
|
||||
//
|
||||
// NewStreamEncoder returns a new encoder that write to w.
|
||||
func NewStreamEncoder(w io.Writer) *StreamEncoder {
|
||||
return &StreamEncoder{w: w}
|
||||
}
|
||||
|
||||
// Encode encodes interface{} as JSON to io.Writer
|
||||
func (enc *StreamEncoder) Encode(val interface{}) (err error) {
|
||||
out := newBytes()
|
||||
|
||||
/* encode into the buffer */
|
||||
err = EncodeInto(&out, val, enc.Opts)
|
||||
if err != nil {
|
||||
goto free_bytes
|
||||
}
|
||||
|
||||
if enc.indent != "" || enc.prefix != "" {
|
||||
/* indent the JSON */
|
||||
buf := newBuffer()
|
||||
err = json.Indent(buf, out, enc.prefix, enc.indent)
|
||||
if err != nil {
|
||||
freeBuffer(buf)
|
||||
goto free_bytes
|
||||
}
|
||||
|
||||
// according to standard library, terminate each value with a newline...
|
||||
buf.WriteByte('\n')
|
||||
|
||||
/* copy into io.Writer */
|
||||
_, err = io.Copy(enc.w, buf)
|
||||
if err != nil {
|
||||
freeBuffer(buf)
|
||||
goto free_bytes
|
||||
}
|
||||
|
||||
} else {
|
||||
/* copy into io.Writer */
|
||||
var n int
|
||||
for len(out) > 0 {
|
||||
n, err = enc.w.Write(out)
|
||||
out = out[n:]
|
||||
if err != nil {
|
||||
goto free_bytes
|
||||
}
|
||||
}
|
||||
|
||||
// according to standard library, terminate each value with a newline...
|
||||
enc.w.Write([]byte{'\n'})
|
||||
}
|
||||
|
||||
free_bytes:
|
||||
freeBytes(out)
|
||||
return err
|
||||
}
|
||||
65
vendor/github.com/bytedance/sonic/internal/encoder/stubs_go116.go
generated
vendored
Normal file
65
vendor/github.com/bytedance/sonic/internal/encoder/stubs_go116.go
generated
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
// +build go1.15,!go1.17
|
||||
|
||||
/*
|
||||
* 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 encoder
|
||||
|
||||
import (
|
||||
`unsafe`
|
||||
|
||||
_ `github.com/chenzhuoyu/base64x`
|
||||
|
||||
`github.com/bytedance/sonic/internal/rt`
|
||||
)
|
||||
|
||||
//go:linkname _subr__b64encode github.com/chenzhuoyu/base64x._subr__b64encode
|
||||
var _subr__b64encode uintptr
|
||||
|
||||
//go:noescape
|
||||
//go:linkname memmove runtime.memmove
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func memmove(to unsafe.Pointer, from unsafe.Pointer, n uintptr)
|
||||
|
||||
//go:linkname growslice runtime.growslice
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func growslice(et *rt.GoType, old rt.GoSlice, cap int) rt.GoSlice
|
||||
|
||||
//go:linkname assertI2I runtime.assertI2I
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func assertI2I(inter *rt.GoType, i rt.GoIface) rt.GoIface
|
||||
|
||||
//go:linkname mapiternext runtime.mapiternext
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func mapiternext(it *rt.GoMapIterator)
|
||||
|
||||
//go:linkname mapiterinit runtime.mapiterinit
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func mapiterinit(t *rt.GoMapType, m *rt.GoMap, it *rt.GoMapIterator)
|
||||
|
||||
//go:linkname isValidNumber encoding/json.isValidNumber
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func isValidNumber(s string) bool
|
||||
|
||||
//go:noescape
|
||||
//go:linkname memclrNoHeapPointers runtime.memclrNoHeapPointers
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func memclrNoHeapPointers(ptr unsafe.Pointer, n uintptr)
|
||||
|
||||
var _runtime_writeBarrier uintptr = rt.GcwbAddr()
|
||||
|
||||
//go:linkname gcWriteBarrierAX runtime.gcWriteBarrier
|
||||
func gcWriteBarrierAX()
|
||||
66
vendor/github.com/bytedance/sonic/internal/encoder/stubs_go117.go
generated
vendored
Normal file
66
vendor/github.com/bytedance/sonic/internal/encoder/stubs_go117.go
generated
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
// +build go1.17,!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 encoder
|
||||
|
||||
import (
|
||||
`unsafe`
|
||||
|
||||
_ `github.com/chenzhuoyu/base64x`
|
||||
|
||||
`github.com/bytedance/sonic/internal/rt`
|
||||
)
|
||||
|
||||
//go:linkname _subr__b64encode github.com/chenzhuoyu/base64x._subr__b64encode
|
||||
var _subr__b64encode uintptr
|
||||
|
||||
//go:noescape
|
||||
//go:linkname memmove runtime.memmove
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func memmove(to unsafe.Pointer, from unsafe.Pointer, n uintptr)
|
||||
|
||||
//go:linkname growslice runtime.growslice
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func growslice(et *rt.GoType, old rt.GoSlice, cap int) rt.GoSlice
|
||||
|
||||
//go:linkname assertI2I runtime.assertI2I2
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func assertI2I(inter *rt.GoType, i rt.GoIface) rt.GoIface
|
||||
|
||||
//go:linkname mapiternext runtime.mapiternext
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func mapiternext(it *rt.GoMapIterator)
|
||||
|
||||
//go:linkname mapiterinit runtime.mapiterinit
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func mapiterinit(t *rt.GoMapType, m *rt.GoMap, it *rt.GoMapIterator)
|
||||
|
||||
//go:linkname isValidNumber encoding/json.isValidNumber
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func isValidNumber(s string) bool
|
||||
|
||||
//go:noescape
|
||||
//go:linkname memclrNoHeapPointers runtime.memclrNoHeapPointers
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func memclrNoHeapPointers(ptr unsafe.Pointer, n uintptr)
|
||||
|
||||
//go:linkname _runtime_writeBarrier runtime.writeBarrier
|
||||
var _runtime_writeBarrier uintptr
|
||||
|
||||
//go:linkname gcWriteBarrierAX runtime.gcWriteBarrier
|
||||
func gcWriteBarrierAX()
|
||||
66
vendor/github.com/bytedance/sonic/internal/encoder/stubs_go120.go
generated
vendored
Normal file
66
vendor/github.com/bytedance/sonic/internal/encoder/stubs_go120.go
generated
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
// +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 encoder
|
||||
|
||||
import (
|
||||
`unsafe`
|
||||
|
||||
_ `github.com/chenzhuoyu/base64x`
|
||||
|
||||
`github.com/bytedance/sonic/internal/rt`
|
||||
)
|
||||
|
||||
//go:linkname _subr__b64encode github.com/chenzhuoyu/base64x._subr__b64encode
|
||||
var _subr__b64encode uintptr
|
||||
|
||||
//go:noescape
|
||||
//go:linkname memmove runtime.memmove
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func memmove(to unsafe.Pointer, from unsafe.Pointer, n uintptr)
|
||||
|
||||
//go:linkname growslice reflect.growslice
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func growslice(et *rt.GoType, old rt.GoSlice, cap int) rt.GoSlice
|
||||
|
||||
//go:linkname assertI2I runtime.assertI2I2
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func assertI2I(inter *rt.GoType, i rt.GoIface) rt.GoIface
|
||||
|
||||
//go:linkname mapiternext runtime.mapiternext
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func mapiternext(it *rt.GoMapIterator)
|
||||
|
||||
//go:linkname mapiterinit runtime.mapiterinit
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func mapiterinit(t *rt.GoMapType, m *rt.GoMap, it *rt.GoMapIterator)
|
||||
|
||||
//go:linkname isValidNumber encoding/json.isValidNumber
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func isValidNumber(s string) bool
|
||||
|
||||
//go:noescape
|
||||
//go:linkname memclrNoHeapPointers runtime.memclrNoHeapPointers
|
||||
//goland:noinspection GoUnusedParameter
|
||||
func memclrNoHeapPointers(ptr unsafe.Pointer, n uintptr)
|
||||
|
||||
//go:linkname _runtime_writeBarrier runtime.writeBarrier
|
||||
var _runtime_writeBarrier uintptr
|
||||
|
||||
//go:linkname gcWriteBarrierAX runtime.gcWriteBarrier
|
||||
func gcWriteBarrierAX()
|
||||
47
vendor/github.com/bytedance/sonic/internal/encoder/types.go
generated
vendored
Normal file
47
vendor/github.com/bytedance/sonic/internal/encoder/types.go
generated
vendored
Normal 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 encoder
|
||||
|
||||
import (
|
||||
`encoding`
|
||||
`encoding/json`
|
||||
`reflect`
|
||||
)
|
||||
|
||||
var (
|
||||
byteType = reflect.TypeOf(byte(0))
|
||||
jsonNumberType = reflect.TypeOf(json.Number(""))
|
||||
jsonUnsupportedValueType = reflect.TypeOf(new(json.UnsupportedValueError))
|
||||
)
|
||||
|
||||
var (
|
||||
errorType = reflect.TypeOf((*error)(nil)).Elem()
|
||||
jsonMarshalerType = reflect.TypeOf((*json.Marshaler)(nil)).Elem()
|
||||
encodingTextMarshalerType = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem()
|
||||
)
|
||||
|
||||
func isSimpleByte(vt reflect.Type) bool {
|
||||
if vt.Kind() != byteType.Kind() {
|
||||
return false
|
||||
} else {
|
||||
return !isEitherMarshaler(vt) && !isEitherMarshaler(reflect.PtrTo(vt))
|
||||
}
|
||||
}
|
||||
|
||||
func isEitherMarshaler(vt reflect.Type) bool {
|
||||
return vt.Implements(jsonMarshalerType) || vt.Implements(encodingTextMarshalerType)
|
||||
}
|
||||
52
vendor/github.com/bytedance/sonic/internal/encoder/utils.go
generated
vendored
Normal file
52
vendor/github.com/bytedance/sonic/internal/encoder/utils.go
generated
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* 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 encoder
|
||||
|
||||
import (
|
||||
`encoding/json`
|
||||
`unsafe`
|
||||
|
||||
`github.com/bytedance/sonic/loader`
|
||||
)
|
||||
|
||||
//go:nosplit
|
||||
func padd(p unsafe.Pointer, v int) unsafe.Pointer {
|
||||
return unsafe.Pointer(uintptr(p) + uintptr(v))
|
||||
}
|
||||
|
||||
//go:nosplit
|
||||
func ptoenc(p loader.Function) _Encoder {
|
||||
return *(*_Encoder)(unsafe.Pointer(&p))
|
||||
}
|
||||
|
||||
func compact(p *[]byte, v []byte) error {
|
||||
buf := newBuffer()
|
||||
err := json.Compact(buf, v)
|
||||
|
||||
/* check for errors */
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
/* add to result */
|
||||
v = buf.Bytes()
|
||||
*p = append(*p, v...)
|
||||
|
||||
/* return the buffer into pool */
|
||||
freeBuffer(buf)
|
||||
return nil
|
||||
}
|
||||
67
vendor/github.com/bytedance/sonic/internal/jit/arch_amd64.go
generated
vendored
Normal file
67
vendor/github.com/bytedance/sonic/internal/jit/arch_amd64.go
generated
vendored
Normal 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
0
vendor/github.com/bytedance/sonic/internal/jit/asm.s
generated
vendored
Normal file
281
vendor/github.com/bytedance/sonic/internal/jit/assembler_amd64.go
generated
vendored
Normal file
281
vendor/github.com/bytedance/sonic/internal/jit/assembler_amd64.go
generated
vendored
Normal file
@@ -0,0 +1,281 @@
|
||||
/*
|
||||
* 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) StorePtr(ptr int64, to obj.Addr, tmp obj.Addr) {
|
||||
if (to.Type != obj.TYPE_MEM) || (tmp.Type != obj.TYPE_REG) {
|
||||
panic("must store imm to memory, tmp must be register")
|
||||
}
|
||||
if (ptr >> 32) != 0 {
|
||||
self.Emit("MOVQ", Imm(ptr), tmp)
|
||||
self.Emit("MOVQ", tmp, to)
|
||||
} else {
|
||||
self.Emit("MOVQ", Imm(ptr), to);
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
120
vendor/github.com/bytedance/sonic/internal/jit/backend.go
generated
vendored
Normal file
120
vendor/github.com/bytedance/sonic/internal/jit/backend.go
generated
vendored
Normal 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
|
||||
}
|
||||
54
vendor/github.com/bytedance/sonic/internal/jit/runtime.go
generated
vendored
Normal file
54
vendor/github.com/bytedance/sonic/internal/jit/runtime.go
generated
vendored
Normal 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))))
|
||||
}
|
||||
0
vendor/github.com/bytedance/sonic/internal/loader/asm.s
generated
vendored
Normal file
0
vendor/github.com/bytedance/sonic/internal/loader/asm.s
generated
vendored
Normal file
124
vendor/github.com/bytedance/sonic/internal/loader/funcdata.go
generated
vendored
Normal file
124
vendor/github.com/bytedance/sonic/internal/loader/funcdata.go
generated
vendored
Normal 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)))
|
||||
|
||||
}
|
||||
169
vendor/github.com/bytedance/sonic/internal/loader/funcdata_go115.go
generated
vendored
Normal file
169
vendor/github.com/bytedance/sonic/internal/loader/funcdata_go115.go
generated
vendored
Normal 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)
|
||||
}
|
||||
175
vendor/github.com/bytedance/sonic/internal/loader/funcdata_go116.go
generated
vendored
Normal file
175
vendor/github.com/bytedance/sonic/internal/loader/funcdata_go116.go
generated
vendored
Normal 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)
|
||||
}
|
||||
201
vendor/github.com/bytedance/sonic/internal/loader/funcdata_go118.go
generated
vendored
Normal file
201
vendor/github.com/bytedance/sonic/internal/loader/funcdata_go118.go
generated
vendored
Normal 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)
|
||||
}
|
||||
201
vendor/github.com/bytedance/sonic/internal/loader/funcdata_go120.go
generated
vendored
Normal file
201
vendor/github.com/bytedance/sonic/internal/loader/funcdata_go120.go
generated
vendored
Normal 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)
|
||||
}
|
||||
74
vendor/github.com/bytedance/sonic/internal/loader/loader.go
generated
vendored
Normal file
74
vendor/github.com/bytedance/sonic/internal/loader/loader.go
generated
vendored
Normal 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)
|
||||
}
|
||||
}
|
||||
111
vendor/github.com/bytedance/sonic/internal/loader/loader_windows.go
generated
vendored
Normal file
111
vendor/github.com/bytedance/sonic/internal/loader/loader_windows.go
generated
vendored
Normal 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
|
||||
}
|
||||
135
vendor/github.com/bytedance/sonic/internal/native/avx/native_amd64.go
generated
vendored
Normal file
135
vendor/github.com/bytedance/sonic/internal/native/avx/native_amd64.go
generated
vendored
Normal 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{}, m *types.StateMachine) (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)
|
||||
15342
vendor/github.com/bytedance/sonic/internal/native/avx/native_amd64.s
generated
vendored
Normal file
15342
vendor/github.com/bytedance/sonic/internal/native/avx/native_amd64.s
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
49
vendor/github.com/bytedance/sonic/internal/native/avx/native_export_amd64.go
generated
vendored
Normal file
49
vendor/github.com/bytedance/sonic/internal/native/avx/native_export_amd64.go
generated
vendored
Normal 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
|
||||
)
|
||||
109
vendor/github.com/bytedance/sonic/internal/native/avx/native_subr_amd64.go
generated
vendored
Normal file
109
vendor/github.com/bytedance/sonic/internal/native/avx/native_subr_amd64.go
generated
vendored
Normal 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__() + 31264
|
||||
_subr__f64toa = __native_entry__() + 192
|
||||
_subr__get_by_path = __native_entry__() + 25856
|
||||
_subr__html_escape = __native_entry__() + 9040
|
||||
_subr__i64toa = __native_entry__() + 3488
|
||||
_subr__lspace = __native_entry__() + 16
|
||||
_subr__quote = __native_entry__() + 4880
|
||||
_subr__skip_array = __native_entry__() + 17952
|
||||
_subr__skip_number = __native_entry__() + 21952
|
||||
_subr__skip_object = __native_entry__() + 20368
|
||||
_subr__skip_one = __native_entry__() + 22112
|
||||
_subr__skip_one_fast = __native_entry__() + 22352
|
||||
_subr__u64toa = __native_entry__() + 3600
|
||||
_subr__unquote = __native_entry__() + 6672
|
||||
_subr__validate_one = __native_entry__() + 22176
|
||||
_subr__validate_utf8 = __native_entry__() + 30000
|
||||
_subr__validate_utf8_fast = __native_entry__() + 30672
|
||||
_subr__value = __native_entry__() + 12224
|
||||
_subr__vnumber = __native_entry__() + 15616
|
||||
_subr__vsigned = __native_entry__() + 17232
|
||||
_subr__vstring = __native_entry__() + 14064
|
||||
_subr__vunsigned = __native_entry__() + 17600
|
||||
)
|
||||
|
||||
const (
|
||||
_stack__f32toa = 48
|
||||
_stack__f64toa = 80
|
||||
_stack__get_by_path = 304
|
||||
_stack__html_escape = 64
|
||||
_stack__i64toa = 16
|
||||
_stack__lspace = 8
|
||||
_stack__quote = 56
|
||||
_stack__skip_array = 128
|
||||
_stack__skip_number = 72
|
||||
_stack__skip_object = 128
|
||||
_stack__skip_one = 128
|
||||
_stack__skip_one_fast = 200
|
||||
_stack__u64toa = 8
|
||||
_stack__unquote = 88
|
||||
_stack__validate_one = 128
|
||||
_stack__validate_utf8 = 48
|
||||
_stack__validate_utf8_fast = 24
|
||||
_stack__value = 328
|
||||
_stack__vnumber = 240
|
||||
_stack__vsigned = 16
|
||||
_stack__vstring = 136
|
||||
_stack__vunsigned = 16
|
||||
)
|
||||
|
||||
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
|
||||
)
|
||||
135
vendor/github.com/bytedance/sonic/internal/native/avx2/native_amd64.go
generated
vendored
Normal file
135
vendor/github.com/bytedance/sonic/internal/native/avx2/native_amd64.go
generated
vendored
Normal 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{}, m *types.StateMachine) (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)
|
||||
15972
vendor/github.com/bytedance/sonic/internal/native/avx2/native_amd64.s
generated
vendored
Normal file
15972
vendor/github.com/bytedance/sonic/internal/native/avx2/native_amd64.s
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
49
vendor/github.com/bytedance/sonic/internal/native/avx2/native_export_amd64.go
generated
vendored
Normal file
49
vendor/github.com/bytedance/sonic/internal/native/avx2/native_export_amd64.go
generated
vendored
Normal 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
|
||||
)
|
||||
109
vendor/github.com/bytedance/sonic/internal/native/avx2/native_subr_amd64.go
generated
vendored
Normal file
109
vendor/github.com/bytedance/sonic/internal/native/avx2/native_subr_amd64.go
generated
vendored
Normal 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__() + 33888
|
||||
_subr__f64toa = __native_entry__() + 288
|
||||
_subr__get_by_path = __native_entry__() + 28336
|
||||
_subr__html_escape = __native_entry__() + 10496
|
||||
_subr__i64toa = __native_entry__() + 3584
|
||||
_subr__lspace = __native_entry__() + 64
|
||||
_subr__quote = __native_entry__() + 5072
|
||||
_subr__skip_array = __native_entry__() + 20688
|
||||
_subr__skip_number = __native_entry__() + 24912
|
||||
_subr__skip_object = __native_entry__() + 22736
|
||||
_subr__skip_one = __native_entry__() + 25072
|
||||
_subr__skip_one_fast = __native_entry__() + 25488
|
||||
_subr__u64toa = __native_entry__() + 3696
|
||||
_subr__unquote = __native_entry__() + 7888
|
||||
_subr__validate_one = __native_entry__() + 25136
|
||||
_subr__validate_utf8 = __native_entry__() + 30320
|
||||
_subr__validate_utf8_fast = __native_entry__() + 31280
|
||||
_subr__value = __native_entry__() + 15024
|
||||
_subr__vnumber = __native_entry__() + 18352
|
||||
_subr__vsigned = __native_entry__() + 19968
|
||||
_subr__vstring = __native_entry__() + 17024
|
||||
_subr__vunsigned = __native_entry__() + 20336
|
||||
)
|
||||
|
||||
const (
|
||||
_stack__f32toa = 48
|
||||
_stack__f64toa = 80
|
||||
_stack__get_by_path = 296
|
||||
_stack__html_escape = 72
|
||||
_stack__i64toa = 16
|
||||
_stack__lspace = 8
|
||||
_stack__quote = 56
|
||||
_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 = 72
|
||||
_stack__validate_one = 128
|
||||
_stack__validate_utf8 = 48
|
||||
_stack__validate_utf8_fast = 176
|
||||
_stack__value = 328
|
||||
_stack__vnumber = 240
|
||||
_stack__vsigned = 16
|
||||
_stack__vstring = 112
|
||||
_stack__vunsigned = 16
|
||||
)
|
||||
|
||||
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
|
||||
)
|
||||
202
vendor/github.com/bytedance/sonic/internal/native/dispatch_amd64.go
generated
vendored
Normal file
202
vendor/github.com/bytedance/sonic/internal/native/dispatch_amd64.go
generated
vendored
Normal 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{}, m *types.StateMachine) 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.")
|
||||
}
|
||||
}
|
||||
137
vendor/github.com/bytedance/sonic/internal/native/dispatch_amd64.s
generated
vendored
Normal file
137
vendor/github.com/bytedance/sonic/internal/native/dispatch_amd64.s
generated
vendored
Normal 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·com∕bytedance∕sonic∕internal∕cpu·HasAVX2(SB), $0
|
||||
JE 2(PC)
|
||||
JMP github·com∕bytedance∕sonic∕internal∕native∕avx2·__quote(SB)
|
||||
CMPB github·com∕bytedance∕sonic∕internal∕cpu·HasAVX(SB), $0
|
||||
JE 2(PC)
|
||||
JMP github·com∕bytedance∕sonic∕internal∕native∕avx·__quote(SB)
|
||||
JMP github·com∕bytedance∕sonic∕internal∕native∕sse·__quote(SB)
|
||||
|
||||
TEXT ·Unquote(SB), NOSPLIT, $0 - 48
|
||||
CMPB github·com∕bytedance∕sonic∕internal∕cpu·HasAVX2(SB), $0
|
||||
JE 2(PC)
|
||||
JMP github·com∕bytedance∕sonic∕internal∕native∕avx2·__unquote(SB)
|
||||
CMPB github·com∕bytedance∕sonic∕internal∕cpu·HasAVX(SB), $0
|
||||
JE 2(PC)
|
||||
JMP github·com∕bytedance∕sonic∕internal∕native∕avx·__unquote(SB)
|
||||
JMP github·com∕bytedance∕sonic∕internal∕native∕sse·__unquote(SB)
|
||||
|
||||
TEXT ·HTMLEscape(SB), NOSPLIT, $0 - 40
|
||||
CMPB github·com∕bytedance∕sonic∕internal∕cpu·HasAVX2(SB), $0
|
||||
JE 2(PC)
|
||||
JMP github·com∕bytedance∕sonic∕internal∕native∕avx2·__html_escape(SB)
|
||||
CMPB github·com∕bytedance∕sonic∕internal∕cpu·HasAVX(SB), $0
|
||||
JE 2(PC)
|
||||
JMP github·com∕bytedance∕sonic∕internal∕native∕avx·__html_escape(SB)
|
||||
JMP github·com∕bytedance∕sonic∕internal∕native∕sse·__html_escape(SB)
|
||||
|
||||
TEXT ·Value(SB), NOSPLIT, $0 - 48
|
||||
CMPB github·com∕bytedance∕sonic∕internal∕cpu·HasAVX2(SB), $0
|
||||
JE 2(PC)
|
||||
JMP github·com∕bytedance∕sonic∕internal∕native∕avx2·__value(SB)
|
||||
CMPB github·com∕bytedance∕sonic∕internal∕cpu·HasAVX(SB), $0
|
||||
JE 2(PC)
|
||||
JMP github·com∕bytedance∕sonic∕internal∕native∕avx·__value(SB)
|
||||
JMP github·com∕bytedance∕sonic∕internal∕native∕sse·__value(SB)
|
||||
|
||||
TEXT ·SkipOne(SB), NOSPLIT, $0 - 40
|
||||
CMPB github·com∕bytedance∕sonic∕internal∕cpu·HasAVX2(SB), $0
|
||||
JE 2(PC)
|
||||
JMP github·com∕bytedance∕sonic∕internal∕native∕avx2·__skip_one(SB)
|
||||
CMPB github·com∕bytedance∕sonic∕internal∕cpu·HasAVX(SB), $0
|
||||
JE 2(PC)
|
||||
JMP github·com∕bytedance∕sonic∕internal∕native∕avx·__skip_one(SB)
|
||||
JMP github·com∕bytedance∕sonic∕internal∕native∕sse·__skip_one(SB)
|
||||
|
||||
TEXT ·SkipOneFast(SB), NOSPLIT, $0 - 24
|
||||
CMPB github·com∕bytedance∕sonic∕internal∕cpu·HasAVX2(SB), $0
|
||||
JE 2(PC)
|
||||
JMP github·com∕bytedance∕sonic∕internal∕native∕avx2·__skip_one_fast(SB)
|
||||
CMPB github·com∕bytedance∕sonic∕internal∕cpu·HasAVX(SB), $0
|
||||
JE 2(PC)
|
||||
JMP github·com∕bytedance∕sonic∕internal∕native∕avx·__skip_one_fast(SB)
|
||||
JMP github·com∕bytedance∕sonic∕internal∕native∕sse·__skip_one_fast(SB)
|
||||
|
||||
TEXT ·GetByPath(SB), NOSPLIT, $0 - 40
|
||||
CMPB github·com∕bytedance∕sonic∕internal∕cpu·HasAVX2(SB), $0
|
||||
JE 2(PC)
|
||||
JMP github·com∕bytedance∕sonic∕internal∕native∕avx2·__get_by_path(SB)
|
||||
CMPB github·com∕bytedance∕sonic∕internal∕cpu·HasAVX(SB), $0
|
||||
JE 2(PC)
|
||||
JMP github·com∕bytedance∕sonic∕internal∕native∕avx·__get_by_path(SB)
|
||||
JMP github·com∕bytedance∕sonic∕internal∕native∕sse·__get_by_path(SB)
|
||||
|
||||
TEXT ·ValidateOne(SB), NOSPLIT, $0 - 32
|
||||
CMPB github·com∕bytedance∕sonic∕internal∕cpu·HasAVX2(SB), $0
|
||||
JE 2(PC)
|
||||
JMP github·com∕bytedance∕sonic∕internal∕native∕avx2·__validate_one(SB)
|
||||
CMPB github·com∕bytedance∕sonic∕internal∕cpu·HasAVX(SB), $0
|
||||
JE 2(PC)
|
||||
JMP github·com∕bytedance∕sonic∕internal∕native∕avx·__validate_one(SB)
|
||||
JMP github·com∕bytedance∕sonic∕internal∕native∕sse·__validate_one(SB)
|
||||
|
||||
TEXT ·ValidateUTF8(SB), NOSPLIT, $0 - 40
|
||||
CMPB github·com∕bytedance∕sonic∕internal∕cpu·HasAVX2(SB), $0
|
||||
JE 2(PC)
|
||||
JMP github·com∕bytedance∕sonic∕internal∕native∕avx2·__validate_utf8(SB)
|
||||
CMPB github·com∕bytedance∕sonic∕internal∕cpu·HasAVX(SB), $0
|
||||
JE 2(PC)
|
||||
JMP github·com∕bytedance∕sonic∕internal∕native∕avx·__validate_utf8(SB)
|
||||
JMP github·com∕bytedance∕sonic∕internal∕native∕sse·__validate_utf8(SB)
|
||||
|
||||
TEXT ·ValidateUTF8Fast(SB), NOSPLIT, $0 - 16
|
||||
CMPB github·com∕bytedance∕sonic∕internal∕cpu·HasAVX2(SB), $0
|
||||
JE 2(PC)
|
||||
JMP github·com∕bytedance∕sonic∕internal∕native∕avx2·__validate_utf8_fast(SB)
|
||||
CMPB github·com∕bytedance∕sonic∕internal∕cpu·HasAVX(SB), $0
|
||||
JE 2(PC)
|
||||
JMP github·com∕bytedance∕sonic∕internal∕native∕avx·__validate_utf8_fast(SB)
|
||||
JMP github·com∕bytedance∕sonic∕internal∕native∕sse·__validate_utf8_fast(SB)
|
||||
|
||||
TEXT ·I64toa(SB), NOSPLIT, $0 - 32
|
||||
CMPB github·com∕bytedance∕sonic∕internal∕cpu·HasAVX2(SB), $0
|
||||
JE 2(PC)
|
||||
JMP github·com∕bytedance∕sonic∕internal∕native∕avx2·__i64toa(SB)
|
||||
CMPB github·com∕bytedance∕sonic∕internal∕cpu·HasAVX(SB), $0
|
||||
JE 2(PC)
|
||||
JMP github·com∕bytedance∕sonic∕internal∕native∕avx·__i64toa(SB)
|
||||
JMP github·com∕bytedance∕sonic∕internal∕native∕sse·__i64toa(SB)
|
||||
|
||||
TEXT ·U64toa(SB), NOSPLIT, $0 - 32
|
||||
CMPB github·com∕bytedance∕sonic∕internal∕cpu·HasAVX2(SB), $0
|
||||
JE 2(PC)
|
||||
JMP github·com∕bytedance∕sonic∕internal∕native∕avx2·__u64toa(SB)
|
||||
CMPB github·com∕bytedance∕sonic∕internal∕cpu·HasAVX(SB), $0
|
||||
JE 2(PC)
|
||||
JMP github·com∕bytedance∕sonic∕internal∕native∕avx·__u64toa(SB)
|
||||
JMP github·com∕bytedance∕sonic∕internal∕native∕sse·__u64toa(SB)
|
||||
|
||||
TEXT ·F64toa(SB), NOSPLIT, $0 - 32
|
||||
CMPB github·com∕bytedance∕sonic∕internal∕cpu·HasAVX2(SB), $0
|
||||
JE 2(PC)
|
||||
JMP github·com∕bytedance∕sonic∕internal∕native∕avx2·__f64toa(SB)
|
||||
CMPB github·com∕bytedance∕sonic∕internal∕cpu·HasAVX(SB), $0
|
||||
JE 2(PC)
|
||||
JMP github·com∕bytedance∕sonic∕internal∕native∕avx·__f64toa(SB)
|
||||
JMP github·com∕bytedance∕sonic∕internal∕native∕sse·__f64toa(SB)
|
||||
|
||||
138
vendor/github.com/bytedance/sonic/internal/native/fastfloat_amd64_test.tmpl
generated
vendored
Normal file
138
vendor/github.com/bytedance/sonic/internal/native/fastfloat_amd64_test.tmpl
generated
vendored
Normal 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
151
vendor/github.com/bytedance/sonic/internal/native/fastint_amd64_test.tmpl
generated
vendored
Normal file
151
vendor/github.com/bytedance/sonic/internal/native/fastint_amd64_test.tmpl
generated
vendored
Normal 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
133
vendor/github.com/bytedance/sonic/internal/native/native_amd64.tmpl
generated
vendored
Normal file
133
vendor/github.com/bytedance/sonic/internal/native/native_amd64.tmpl
generated
vendored
Normal 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{}, m *types.StateMachine) (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)
|
||||
593
vendor/github.com/bytedance/sonic/internal/native/native_amd64_test.tmpl
generated
vendored
Normal file
593
vendor/github.com/bytedance/sonic/internal/native/native_amd64_test.tmpl
generated
vendored
Normal 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)
|
||||
}
|
||||
}
|
||||
47
vendor/github.com/bytedance/sonic/internal/native/native_export_amd64.tmpl
generated
vendored
Normal file
47
vendor/github.com/bytedance/sonic/internal/native/native_export_amd64.tmpl
generated
vendored
Normal 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
|
||||
)
|
||||
135
vendor/github.com/bytedance/sonic/internal/native/sse/native_amd64.go
generated
vendored
Normal file
135
vendor/github.com/bytedance/sonic/internal/native/sse/native_amd64.go
generated
vendored
Normal 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{}, m *types.StateMachine) (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)
|
||||
15479
vendor/github.com/bytedance/sonic/internal/native/sse/native_amd64.s
generated
vendored
Normal file
15479
vendor/github.com/bytedance/sonic/internal/native/sse/native_amd64.s
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
49
vendor/github.com/bytedance/sonic/internal/native/sse/native_export_amd64.go
generated
vendored
Normal file
49
vendor/github.com/bytedance/sonic/internal/native/sse/native_export_amd64.go
generated
vendored
Normal 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
|
||||
)
|
||||
109
vendor/github.com/bytedance/sonic/internal/native/sse/native_subr_amd64.go
generated
vendored
Normal file
109
vendor/github.com/bytedance/sonic/internal/native/sse/native_subr_amd64.go
generated
vendored
Normal 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__() + 31760
|
||||
_subr__f64toa = __native_entry__() + 160
|
||||
_subr__get_by_path = __native_entry__() + 26384
|
||||
_subr__html_escape = __native_entry__() + 9072
|
||||
_subr__i64toa = __native_entry__() + 3424
|
||||
_subr__lspace = __native_entry__() + 16
|
||||
_subr__quote = __native_entry__() + 4864
|
||||
_subr__skip_array = __native_entry__() + 18112
|
||||
_subr__skip_number = __native_entry__() + 22128
|
||||
_subr__skip_object = __native_entry__() + 20512
|
||||
_subr__skip_one = __native_entry__() + 22288
|
||||
_subr__skip_one_fast = __native_entry__() + 22512
|
||||
_subr__u64toa = __native_entry__() + 3552
|
||||
_subr__unquote = __native_entry__() + 6704
|
||||
_subr__validate_one = __native_entry__() + 22336
|
||||
_subr__validate_utf8 = __native_entry__() + 30528
|
||||
_subr__validate_utf8_fast = __native_entry__() + 31200
|
||||
_subr__value = __native_entry__() + 12272
|
||||
_subr__vnumber = __native_entry__() + 15728
|
||||
_subr__vsigned = __native_entry__() + 17376
|
||||
_subr__vstring = __native_entry__() + 14112
|
||||
_subr__vunsigned = __native_entry__() + 17760
|
||||
)
|
||||
|
||||
const (
|
||||
_stack__f32toa = 48
|
||||
_stack__f64toa = 80
|
||||
_stack__get_by_path = 240
|
||||
_stack__html_escape = 64
|
||||
_stack__i64toa = 16
|
||||
_stack__lspace = 8
|
||||
_stack__quote = 64
|
||||
_stack__skip_array = 128
|
||||
_stack__skip_number = 72
|
||||
_stack__skip_object = 128
|
||||
_stack__skip_one = 128
|
||||
_stack__skip_one_fast = 136
|
||||
_stack__u64toa = 8
|
||||
_stack__unquote = 88
|
||||
_stack__validate_one = 128
|
||||
_stack__validate_utf8 = 48
|
||||
_stack__validate_utf8_fast = 24
|
||||
_stack__value = 328
|
||||
_stack__vnumber = 240
|
||||
_stack__vsigned = 16
|
||||
_stack__vstring = 136
|
||||
_stack__vunsigned = 16
|
||||
)
|
||||
|
||||
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
|
||||
)
|
||||
138
vendor/github.com/bytedance/sonic/internal/native/types/types.go
generated
vendored
Normal file
138
vendor/github.com/bytedance/sonic/internal/native/types/types.go
generated
vendored
Normal 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 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
|
||||
|
||||
// error code used in ast
|
||||
ERR_NOT_FOUND ParsingError = 33
|
||||
ERR_UNSUPPORT_TYPE ParsingError = 34
|
||||
)
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
0
vendor/github.com/bytedance/sonic/internal/resolver/asm.s
generated
vendored
Normal file
0
vendor/github.com/bytedance/sonic/internal/resolver/asm.s
generated
vendored
Normal file
214
vendor/github.com/bytedance/sonic/internal/resolver/resolver.go
generated
vendored
Normal file
214
vendor/github.com/bytedance/sonic/internal/resolver/resolver.go
generated
vendored
Normal 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 */
|
||||
idx := len(path) - 1
|
||||
fvt := path[idx].Type
|
||||
|
||||
/* 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
|
||||
}
|
||||
46
vendor/github.com/bytedance/sonic/internal/resolver/stubs.go
generated
vendored
Normal file
46
vendor/github.com/bytedance/sonic/internal/resolver/stubs.go
generated
vendored
Normal 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
|
||||
60
vendor/github.com/bytedance/sonic/internal/rt/asm_amd64.s
generated
vendored
Normal file
60
vendor/github.com/bytedance/sonic/internal/rt/asm_amd64.s
generated
vendored
Normal 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·com∕bytedance∕sonic∕internal∕rt·StopProfiling(SB), $0
|
||||
JEQ _ret_1
|
||||
MOVL $1, AX
|
||||
LEAQ github·com∕bytedance∕sonic∕internal∕rt·yieldCount(SB), CX
|
||||
LOCK
|
||||
XADDL AX, (CX)
|
||||
MOVL runtime·prof+4(SB), AX
|
||||
TESTL AX, AX
|
||||
JEQ _ret_1
|
||||
MOVL AX, github·com∕bytedance∕sonic∕internal∕rt·oldHz(SB)
|
||||
MOVL $0, runtime·prof+4(SB)
|
||||
_ret_1:
|
||||
RET
|
||||
|
||||
|
||||
TEXT ·StartProf(SB), NOSPLIT, $0-0
|
||||
NO_LOCAL_POINTERS
|
||||
CMPB github·com∕bytedance∕sonic∕internal∕rt·StopProfiling(SB), $0
|
||||
JEQ _ret_2
|
||||
MOVL $-1, AX
|
||||
LEAQ github·com∕bytedance∕sonic∕internal∕rt·yieldCount(SB), CX
|
||||
LOCK
|
||||
XADDL AX, (CX)
|
||||
CMPL github·com∕bytedance∕sonic∕internal∕rt·yieldCount(SB), $0
|
||||
JNE _ret_2
|
||||
CMPL runtime·prof+4(SB), $0
|
||||
JNE _ret_2
|
||||
CMPL github·com∕bytedance∕sonic∕internal∕rt·oldHz(SB), $0
|
||||
JNE _branch_1
|
||||
MOVL $100, github·com∕bytedance∕sonic∕internal∕rt·oldHz(SB)
|
||||
_branch_1:
|
||||
MOVL github·com∕bytedance∕sonic∕internal∕rt·oldHz(SB), AX
|
||||
MOVL AX, runtime·prof+4(SB)
|
||||
_ret_2:
|
||||
RET
|
||||
|
||||
10
vendor/github.com/bytedance/sonic/internal/rt/asm_arm64.s
generated
vendored
Normal file
10
vendor/github.com/bytedance/sonic/internal/rt/asm_arm64.s
generated
vendored
Normal 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
|
||||
112
vendor/github.com/bytedance/sonic/internal/rt/fastmem.go
generated
vendored
Normal file
112
vendor/github.com/bytedance/sonic/internal/rt/fastmem.go
generated
vendored
Normal file
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* 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
|
||||
}
|
||||
}
|
||||
|
||||
//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
|
||||
}
|
||||
213
vendor/github.com/bytedance/sonic/internal/rt/fastvalue.go
generated
vendored
Normal file
213
vendor/github.com/bytedance/sonic/internal/rt/fastvalue.go
generated
vendored
Normal file
@@ -0,0 +1,213 @@
|
||||
/*
|
||||
* 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()
|
||||
)
|
||||
|
||||
// GoType.KindFlags const
|
||||
const (
|
||||
F_direct = 1 << 5
|
||||
F_kind_mask = (1 << 5) - 1
|
||||
)
|
||||
|
||||
// GoType.Flags const
|
||||
const (
|
||||
tflagUncommon uint8 = 1 << 0
|
||||
tflagExtraStar uint8 = 1 << 1
|
||||
tflagNamed uint8 = 1 << 2
|
||||
tflagRegularMemory uint8 = 1 << 3
|
||||
)
|
||||
|
||||
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) IsNamed() bool {
|
||||
return (self.Flags & tflagNamed) != 0
|
||||
}
|
||||
|
||||
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
124
vendor/github.com/bytedance/sonic/internal/rt/gcwb.go
generated
vendored
Normal 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
36
vendor/github.com/bytedance/sonic/internal/rt/int48.go
generated
vendored
Normal 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)
|
||||
}
|
||||
181
vendor/github.com/bytedance/sonic/internal/rt/stackmap.go
generated
vendored
Normal file
181
vendor/github.com/bytedance/sonic/internal/rt/stackmap.go
generated
vendored
Normal file
@@ -0,0 +1,181 @@
|
||||
/**
|
||||
* 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
|
||||
}
|
||||
|
||||
//go:nocheckptr
|
||||
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)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user