2
0
Fork 0
mirror of https://github.com/ii64/sonic.git synced 2026-06-21 00:46:43 +08:00

feat: CPU feature detection support

This commit is contained in:
chenzhuoyu 2021-06-10 16:36:04 +08:00 committed by Oxygen
parent accee2e689
commit 34fa8d64a8
47 changed files with 10838 additions and 2470 deletions

View file

@ -8,13 +8,15 @@ header:
- '**/*.s'
paths-ignore:
- 'ast/asm.s' # empty file
- 'encoder/asm.s' # empty file
- 'internal/caching/asm.s' # empty file
- 'internal/jit/asm.s' # empty file
- 'internal/native/native_amd64.s' # auto-generated by asm2asm
- 'internal/native/native_subr_amd64.go' # auto-generated by asm2asm
- 'internal/resolver/asm.s' # empty file
- 'internal/rt/asm.s' # empty file
- 'ast/asm.s' # empty file
- 'encoder/asm.s' # empty file
- 'internal/caching/asm.s' # empty file
- 'internal/jit/asm.s' # empty file
- 'internal/native/avx/native_amd64.s' # auto-generated by asm2asm
- 'internal/native/avx/native_subr_amd64.go' # auto-generated by asm2asm
- 'internal/native/avx2/native_amd64.s' # auto-generated by asm2asm
- 'internal/native/avx2/native_subr_amd64.go' # auto-generated by asm2asm
- 'internal/resolver/asm.s' # empty file
- 'internal/rt/asm.s' # empty file
comment: on-failure

113
Makefile
View file

@ -14,39 +14,92 @@
# limitations under the License.
#
.PHONY: all clean
ARCH := avx avx2
TMP_DIR := output
OUT_DIR := internal/native
SRC_FILE := native/native.c
CFLAGS := -mavx
CFLAGS += -mavx2
CFLAGS += -mbmi
CFLAGS += -mbmi2
CFLAGS += -mfma
CFLAGS += -msse
CFLAGS += -msse2
CFLAGS += -msse3
CFLAGS += -msse4
CFLAGS += -mssse3
CFLAGS += -mno-red-zone
CFLAGS += -ffast-math
CFLAGS += -fno-asynchronous-unwind-tables
CFLAGS += -fno-builtin
CFLAGS += -fno-exceptions
CFLAGS += -fno-rtti
CFLAGS += -fno-stack-protector
CFLAGS += -nostdlib
CFLAGS += -O3
CPU_avx := amd64
CPU_avx2 := amd64
NATIVE_ASM := $(wildcard native/*.S)
NATIVE_SRC := $(wildcard native/*.h)
NATIVE_SRC += $(wildcard native/*.c)
TMPL_avx := fastint_amd64_test fastfloat_amd64_test native_amd64_test native_export_amd64
TMPL_avx2 := fastint_amd64_test fastfloat_amd64_test native_amd64_test native_export_amd64
all: internal/native/native_amd64.s
CFLAGS_avx := -msse2 -mavx -mno-avx2 -DUSE_SSE=1 -DUSE_AVX=1 -DUSE_AVX2=0
CFLAGS_avx2 := -msse2 -mavx -mavx2 -DUSE_SSE=1 -DUSE_AVX=1 -DUSE_AVX2=1
CC_amd64 := clang
ASM2ASM_amd64 := tools/asm2asm/asm2asm.py
CFLAGS := -mno-red-zone
CFLAGS += -fno-asynchronous-unwind-tables
CFLAGS += -fno-builtin
CFLAGS += -fno-exceptions
CFLAGS += -fno-rtti
CFLAGS += -fno-stack-protector
CFLAGS += -nostdlib
CFLAGS += -O3
NATIVE_SRC := $(wildcard native/*.h)
NATIVE_SRC += $(wildcard native/*.c)
.PHONY: all clean ${ARCH}
define build_tmpl
$(eval @arch := $(1))
$(eval @tmpl := $(2))
$(eval @dest := $(3))
${@dest}: ${@tmpl}
mkdir -p $(dir ${@dest})
echo '// Code generated by Makefile, DO NOT EDIT.' > ${@dest}
echo >> ${@dest}
sed -e 's/{{PACKAGE}}/${@arch}/g' ${@tmpl} >> ${@dest}
endef
define build_arch
$(eval @cpu := $(value CPU_$(1)))
$(eval @deps := $(foreach tmpl,$(value TMPL_$(1)),${OUT_DIR}/$(1)/${tmpl}.go))
$(eval @asmin := ${TMP_DIR}/$(1)/native.s)
$(eval @asmout := ${OUT_DIR}/$(1)/native_${@cpu}.s)
$(eval @stubin := ${OUT_DIR}/native_${@cpu}.tmpl)
$(eval @stubout := ${OUT_DIR}/$(1)/native_${@cpu}.go)
$(1): ${@asmout} ${@deps}
${@asmout}: ${@stubout} ${NATIVE_SRC}
mkdir -p ${TMP_DIR}/$(1)
$${CC_${@cpu}} $${CFLAGS} $${CFLAGS_$(1)} -S -o ${TMP_DIR}/$(1)/native.s ${SRC_FILE}
python3 $${ASM2ASM_${@cpu}} ${@asmout} ${TMP_DIR}/$(1)/native.s
asmfmt -w ${@asmout}
$(eval $(call \
build_tmpl, \
$(1), \
${@stubin}, \
${@stubout} \
))
$(foreach \
tmpl, \
$(value TMPL_$(1)), \
$(eval $(call \
build_tmpl, \
$(1), \
${OUT_DIR}/${tmpl}.tmpl, \
${OUT_DIR}/$(1)/${tmpl}.go \
)) \
)
endef
all: ${ARCH}
clean:
rm -vf internal/native/native_amd64.s output/*.s
rm -vfr ${TMP_DIR}/{sse,avx,avx2}
rm -vfr ${OUT_DIR}/{sse,avx,avx2}
internal/native/native_amd64.s: ${NATIVE_SRC} ${NATIVE_ASM} internal/native/native_amd64.go
mkdir -p output
clang ${CFLAGS} -S -o output/native.s native/native.c
python3 tools/asm2asm/asm2asm.py internal/native/native_amd64.s output/native.s ${NATIVE_ASM}
asmfmt -w internal/native/native_amd64.s
$(foreach \
arch, \
${ARCH}, \
$(eval $(call build_arch,${arch})) \
)

View file

@ -21,7 +21,7 @@ import (
`fmt`
`unsafe`
`github.com/bytedance/sonic/internal/native`
`github.com/bytedance/sonic/internal/native/types`
`github.com/bytedance/sonic/internal/rt`
)
@ -36,23 +36,23 @@ const (
)
const (
V_RAW native.ValueType = 1 << 4
V_NUMBER native.ValueType = 10
V_ARRAY_RAW = V_RAW | native.V_ARRAY
V_OBJECT_RAW = V_RAW | native.V_OBJECT
MASK_RAW = V_RAW - 1
V_RAW types.ValueType = 1 << 4
V_NUMBER types.ValueType = 10
V_ARRAY_RAW = V_RAW | types.V_ARRAY
V_OBJECT_RAW = V_RAW | types.V_OBJECT
MASK_RAW = V_RAW - 1
)
type Node struct {
v int64
t native.ValueType
t types.ValueType
p unsafe.Pointer
m map[string]unsafe.Pointer
}
/** Node Type Accessor **/
func (self *Node) Type() native.ValueType {
func (self *Node) Type() types.ValueType {
return self.t & MASK_RAW
}
@ -69,12 +69,12 @@ func (self *Node) Raw() string {
// Bool returns bool value represented by this node
//
// If node type is not native.V_TRUE or native.V_FALSE, or V_RAW (must be a bool json value)
// If node type is not types.V_TRUE or types.V_FALSE, or V_RAW (must be a bool json value)
// it will panic
func (self *Node) Bool() bool {
switch self.t {
case native.V_TRUE : return true
case native.V_FALSE : return false
case types.V_TRUE : return true
case types.V_FALSE : return false
case V_RAW :
n := self.parseRaw()
return n.Bool()
@ -86,9 +86,9 @@ func (self *Node) Bool() bool {
func (self *Node) Int64() int64 {
switch self.t {
case V_NUMBER : return numberToInt64(self)
case native.V_TRUE : return 1
case native.V_FALSE : return 0
case V_RAW :
case types.V_TRUE : return 1
case types.V_FALSE : return 0
case V_RAW :
n := self.parseRaw()
return n.Int64()
default : panic("value cannot be represented as an integer")
@ -109,36 +109,36 @@ func (self *Node) Number() json.Number {
// String as above.
func (self *Node) String() string {
switch self.t {
case V_NUMBER : return toNumber(self).String()
case native.V_NULL : return "null"
case native.V_TRUE : return "true"
case native.V_FALSE : return "false"
case native.V_STRING : return addr2str(self.p, self.v)
case V_NUMBER : return toNumber(self).String()
case types.V_NULL : return "null"
case types.V_TRUE : return "true"
case types.V_FALSE : return "false"
case types.V_STRING : return addr2str(self.p, self.v)
case V_RAW :
n := self.parseRaw()
return n.String()
default : panic("value cannot be represented as a simple string")
default : panic("value cannot be represented as a simple string")
}
}
// Float64 as above.
func (self *Node) Float64() float64 {
switch self.t {
case V_NUMBER : return numberToFloat64(self)
case native.V_TRUE : return 1.0
case native.V_FALSE : return 0.0
case V_NUMBER : return numberToFloat64(self)
case types.V_TRUE : return 1.0
case types.V_FALSE : return 0.0
case V_RAW :
n := self.parseRaw()
return n.Float64()
default : panic("value cannot be represented as an integer")
default : panic("value cannot be represented as an integer")
}
}
// IsRaw returns true if the node is type of below three:
//
// 1. V_RAW (never parsed)
// 2. native.V_Object_RAW (partially parsed)
// 3. native.V_Array_RAW (partially parsed)
// 2. types.V_Object_RAW (partially parsed)
// 3. types.V_Array_RAW (partially parsed)
func (self *Node) IsRaw() bool {
return self.t&V_RAW != 0
}
@ -148,9 +148,9 @@ func (self *Node) IsRaw() bool {
// Len returns children count of a array|object|string node
// For partially loaded node, it also works but only counts the parsed children
func (self *Node) Len() int {
if self.t == native.V_ARRAY || self.t == native.V_OBJECT || self.t == V_ARRAY_RAW || self.t == V_OBJECT_RAW {
if self.t == types.V_ARRAY || self.t == types.V_OBJECT || self.t == V_ARRAY_RAW || self.t == V_OBJECT_RAW {
return int(self.v & _LEN_MASK)
} else if self.t == native.V_STRING {
} else if self.t == types.V_STRING {
return int(self.v)
} else {
panic("value does not have a length")
@ -159,7 +159,7 @@ func (self *Node) Len() int {
// Cap returns malloc capacity of a array|object node for children
func (self *Node) Cap() int {
if self.t == native.V_ARRAY || self.t == native.V_OBJECT || self.t == V_ARRAY_RAW || self.t == V_OBJECT_RAW {
if self.t == types.V_ARRAY || self.t == types.V_OBJECT || self.t == V_ARRAY_RAW || self.t == V_OBJECT_RAW {
return int(self.v >> _CAP_BITS)
} else {
panic("value does not have a capacity")
@ -205,7 +205,7 @@ func (self *Node) SetByIndex(index int, node Node) {
// Add appends the given node under array node
func (self *Node) Add(node Node) {
self.must(native.V_ARRAY, "an array")
self.must(types.V_ARRAY, "an array")
self.loadAllIndex()
l := self.Len()
c := self.Cap()
@ -240,26 +240,26 @@ func (self *Node) GetByPath(path ...interface{}) *Node {
// Get loads given key of an object node on demands
func (self *Node) Get(key string) *Node {
self.must(native.V_OBJECT, "an object")
self.must(types.V_OBJECT, "an object")
return self.loadKey(key)
}
// Index loads given index of an array node on demands
func (self *Node) Index(idx int) *Node {
self.must(native.V_ARRAY, "an array")
self.must(types.V_ARRAY, "an array")
return self.loadIndex(idx)
}
// Values returns iterator for array's children traversal
func (self *Node) Values() ListIterator {
self.must(native.V_ARRAY, "an array")
self.must(types.V_ARRAY, "an array")
self.loadAllIndex()
return ListIterator{Iterator{p: self}}
}
// Values returns iterator for object's children traversal
// Properties returns iterator for object's children traversal
func (self *Node) Properties() ObjectIterator {
self.must(native.V_OBJECT, "an object")
self.must(types.V_OBJECT, "an object")
self.loadAllKey()
return ObjectIterator{Iterator{p: self}}
}
@ -268,28 +268,28 @@ func (self *Node) Properties() ObjectIterator {
// Map loads all keys of an object node
func (self *Node) Map() map[string]interface{} {
self.must(native.V_OBJECT, "an object")
self.must(types.V_OBJECT, "an object")
self.loadAllKey()
return self.toGenericObject()
}
// MapUseNumber loads all keys of an object node, with numeric nodes casted to json.Number
func (self *Node) MapUseNumber() map[string]interface{} {
self.must(native.V_OBJECT, "an object")
self.must(types.V_OBJECT, "an object")
self.loadAllKey()
return self.toGenericObjectUseNumber()
}
// Array loads all indexes of an array node
func (self *Node) Array() []interface{} {
self.must(native.V_ARRAY, "an array")
self.must(types.V_ARRAY, "an array")
self.loadAllIndex()
return self.toGenericArray()
}
// Array loads all indexes of an array node, with numeric nodes casted to json.Number
// ArrayUseNumber loads all indexes of an array node, with numeric nodes casted to json.Number
func (self *Node) ArrayUseNumber() []interface{} {
self.must(native.V_ARRAY, "an array")
self.must(types.V_ARRAY, "an array")
self.loadAllIndex()
return self.toGenericArrayUseNumber()
}
@ -299,14 +299,14 @@ func (self *Node) ArrayUseNumber() []interface{} {
// all numberic nodes are casted to float64
func (self *Node) Interface() interface{} {
switch self.t {
case native.V_EOF : panic("invalid value")
case native.V_NULL : return nil
case native.V_TRUE : return true
case native.V_FALSE : return false
case native.V_ARRAY : return self.toGenericArray()
case native.V_OBJECT : return self.toGenericObject()
case native.V_STRING : return addr2str(self.p, self.v)
case V_NUMBER :
case types.V_EOF : panic("invalid value")
case types.V_NULL : return nil
case types.V_TRUE : return true
case types.V_FALSE : return false
case types.V_ARRAY : return self.toGenericArray()
case types.V_OBJECT : return self.toGenericObject()
case types.V_STRING : return addr2str(self.p, self.v)
case V_NUMBER :
return numberToFloat64(self)
case V_ARRAY_RAW:
self.loadAllIndex()
@ -317,7 +317,7 @@ func (self *Node) Interface() interface{} {
case V_RAW :
n := self.parseRaw()
return n.Interface()
default : panic("not gonna happen")
default : panic("not gonna happen")
}
}
@ -325,14 +325,14 @@ func (self *Node) Interface() interface{} {
// except numberic nodes are casted to json.Number
func (self *Node) InterfaceUseNumber() interface{} {
switch self.t {
case native.V_EOF : panic("invalid value")
case native.V_NULL : return nil
case native.V_TRUE : return true
case native.V_FALSE : return false
case native.V_ARRAY : return self.toGenericArrayUseNumber()
case native.V_OBJECT : return self.toGenericObjectUseNumber()
case native.V_STRING : return addr2str(self.p, self.v)
case V_NUMBER :
case types.V_EOF : panic("invalid value")
case types.V_NULL : return nil
case types.V_TRUE : return true
case types.V_FALSE : return false
case types.V_ARRAY : return self.toGenericArrayUseNumber()
case types.V_OBJECT : return self.toGenericObjectUseNumber()
case types.V_STRING : return addr2str(self.p, self.v)
case V_NUMBER :
return toNumber(self)
case V_ARRAY_RAW:
self.loadAllIndex()
@ -340,10 +340,10 @@ func (self *Node) InterfaceUseNumber() interface{} {
case V_OBJECT_RAW:
self.loadAllKey()
return self.toGenericObjectUseNumber()
case V_RAW :
case V_RAW :
n := self.parseRaw()
return n.InterfaceUseNumber()
default : panic("not gonna happen")
default : panic("not gonna happen")
}
}
@ -355,7 +355,7 @@ var (
)
func (self *Node) setCapAndLen(cap int, len int) {
if self.t == native.V_ARRAY || self.t == native.V_OBJECT || self.t == V_ARRAY_RAW || self.t == V_OBJECT_RAW {
if self.t == types.V_ARRAY || self.t == types.V_OBJECT || self.t == V_ARRAY_RAW || self.t == V_OBJECT_RAW {
self.v = int64(len&_LEN_MASK | cap<<_CAP_BITS)
} else {
panic("value does not have a length")
@ -370,7 +370,7 @@ func (self *Pair) unsafe_next() *Pair {
return (*Pair)(unsafe.Pointer(uintptr(unsafe.Pointer(self)) + _PAIR_SIZE))
}
func (self *Node) must(t native.ValueType, s string) {
func (self *Node) must(t types.ValueType, s string) {
if self.t == V_RAW {
*self = self.parseRaw()
}
@ -470,7 +470,7 @@ func (self *Node) loadAllIndex() {
if !self.IsRaw() {
return
}
var err native.ParsingError
var err types.ParsingError
stack := (*parseArrayStack)(self.p)
parser := &stack.parser
old := parser.noLazy
@ -486,7 +486,7 @@ func (self *Node) loadAllKey() {
if !self.IsRaw() {
return
}
var err native.ParsingError
var err types.ParsingError
stack := (*parseObjectStack)(self.p)
parser := &stack.parser
old := parser.noLazy
@ -523,7 +523,7 @@ func (self *Node) loadIndex(index int) *Node {
return nil
}
func (self *Node) loadNextNode() (*Node, native.ParsingError) {
func (self *Node) loadNextNode() (*Node, types.ParsingError) {
stack := (*parseArrayStack)(self.p)
ret := stack.v
parser := &stack.parser
@ -532,7 +532,7 @@ func (self *Node) loadNextNode() (*Node, native.ParsingError) {
/* check for EOF */
if parser.p = parser.lspace(sp); parser.p >= ns {
return nil, native.ERR_EOF
return nil, types.ERR_EOF
}
/* check for empty array */
@ -543,7 +543,7 @@ func (self *Node) loadNextNode() (*Node, native.ParsingError) {
}
var val Node
var err native.ParsingError
var err types.ParsingError
/* decode the value */
parser.noLazy = true
@ -558,7 +558,7 @@ func (self *Node) loadNextNode() (*Node, native.ParsingError) {
/* check for EOF */
if parser.p >= ns {
return &ret[len(ret)-1], native.ERR_EOF
return &ret[len(ret)-1], types.ERR_EOF
}
/* check for the next character */
@ -572,7 +572,7 @@ func (self *Node) loadNextNode() (*Node, native.ParsingError) {
self.setArray(ret)
return &ret[len(ret)-1], 0
default:
return &ret[len(ret)-1], native.ERR_INVALID_CHAR
return &ret[len(ret)-1], types.ERR_INVALID_CHAR
}
}
@ -596,7 +596,7 @@ func (self *Node) loadKey(key string) *Node {
return nil
}
func (self *Node) loadNextPair() (*Pair, native.ParsingError) {
func (self *Node) loadNextPair() (*Pair, types.ParsingError) {
stack := (*parseObjectStack)(self.p)
ret := stack.v
parser := &stack.parser
@ -605,7 +605,7 @@ func (self *Node) loadNextPair() (*Pair, native.ParsingError) {
/* check for EOF */
if parser.p = parser.lspace(sp); parser.p >= ns {
return nil, native.ERR_EOF
return nil, types.ERR_EOF
}
/* check for empty object */
@ -617,12 +617,12 @@ func (self *Node) loadNextPair() (*Pair, native.ParsingError) {
/* decode one pair */
var val Node
var njs native.JsonState
var err native.ParsingError
var njs types.JsonState
var err types.ParsingError
/* decode the key */
if njs = parser.decodeValue(); njs.Vt != native.V_STRING {
return nil, native.ERR_INVALID_CHAR
if njs = parser.decodeValue(); njs.Vt != types.V_STRING {
return nil, types.ERR_INVALID_CHAR
}
/* extract the key */
@ -654,7 +654,7 @@ func (self *Node) loadNextPair() (*Pair, native.ParsingError) {
/* check for EOF */
if parser.p >= ns {
return &ret[len(ret)-1], native.ERR_EOF
return &ret[len(ret)-1], types.ERR_EOF
}
/* check for the next character */
@ -668,7 +668,7 @@ func (self *Node) loadNextPair() (*Pair, native.ParsingError) {
self.setObject(ret)
return &ret[len(ret)-1], 0
default:
return &ret[len(ret)-1], native.ERR_INVALID_CHAR
return &ret[len(ret)-1], types.ERR_INVALID_CHAR
}
}
@ -752,12 +752,12 @@ func (self *Node) toGenericObjectUseNumber() map[string]interface{} {
/** Internal Factory Methods **/
var (
nullNode = Node{t: native.V_NULL}
trueNode = Node{t: native.V_TRUE}
falseNode = Node{t: native.V_FALSE}
nullNode = Node{t: types.V_NULL}
trueNode = Node{t: types.V_TRUE}
falseNode = Node{t: types.V_FALSE}
emptyArrayNode = Node{t: native.V_ARRAY}
emptyObjectNode = Node{t: native.V_OBJECT}
emptyArrayNode = Node{t: types.V_ARRAY}
emptyObjectNode = Node{t: types.V_OBJECT}
)
func newNumber(v string) Node {
@ -790,7 +790,7 @@ func numberToInt64(node *Node) int64 {
func newBytes(v []byte) Node {
return Node{
t: native.V_STRING,
t: types.V_STRING,
p: mem2ptr(v),
v: int64(len(v)),
}
@ -798,7 +798,7 @@ func newBytes(v []byte) Node {
func newString(v string) Node {
return Node{
t: native.V_STRING,
t: types.V_STRING,
p: str2ptr(v),
v: int64(len(v)),
}
@ -806,28 +806,28 @@ func newString(v string) Node {
func newArray(v []Node) Node {
return Node{
t: native.V_ARRAY,
t: types.V_ARRAY,
v: int64(len(v)&_LEN_MASK | cap(v)<<_CAP_BITS),
p: *(*unsafe.Pointer)(unsafe.Pointer(&v)),
}
}
func (self *Node) setArray(v []Node) {
self.t = native.V_ARRAY
self.t = types.V_ARRAY
self.setCapAndLen(cap(v), len(v))
self.p = *(*unsafe.Pointer)(unsafe.Pointer(&v))
}
func newObject(v []Pair) Node {
return Node{
t: native.V_OBJECT,
t: types.V_OBJECT,
v: int64(len(v)&_LEN_MASK | cap(v)<<_CAP_BITS),
p: *(*unsafe.Pointer)(unsafe.Pointer(&v)),
}
}
func (self *Node) setObject(v []Pair) {
self.t = native.V_OBJECT
self.t = types.V_OBJECT
self.setCapAndLen(cap(v), len(v))
self.p = *(*unsafe.Pointer)(unsafe.Pointer(&v))
}

View file

@ -21,6 +21,7 @@ import (
`unsafe`
`github.com/bytedance/sonic/internal/native`
`github.com/bytedance/sonic/internal/native/types`
`github.com/bytedance/sonic/internal/rt`
)
@ -34,24 +35,24 @@ type Parser struct {
var stackPool = sync.Pool{
New: func()interface{}{
return &native.StateMachine{}
return &types.StateMachine{}
},
}
/** Parser Private Methods **/
func (self *Parser) delim() native.ParsingError {
func (self *Parser) delim() types.ParsingError {
n := len(self.s)
p := self.lspace(self.p)
/* check for EOF */
if p >= n {
return native.ERR_EOF
return types.ERR_EOF
}
/* check for the delimtier */
if self.s[p] != ':' {
return native.ERR_INVALID_CHAR
return types.ERR_INVALID_CHAR
}
/* update the read pointer */
@ -59,18 +60,18 @@ func (self *Parser) delim() native.ParsingError {
return 0
}
func (self *Parser) object() native.ParsingError {
func (self *Parser) object() types.ParsingError {
n := len(self.s)
p := self.lspace(self.p)
/* check for EOF */
if p >= n {
return native.ERR_EOF
return types.ERR_EOF
}
/* check for the delimtier */
if self.s[p] != '{' {
return native.ERR_INVALID_CHAR
return types.ERR_INVALID_CHAR
}
/* update the read pointer */
@ -78,18 +79,18 @@ func (self *Parser) object() native.ParsingError {
return 0
}
func (self *Parser) array() native.ParsingError {
func (self *Parser) array() types.ParsingError {
n := len(self.s)
p := self.lspace(self.p)
/* check for EOF */
if p >= n {
return native.ERR_EOF
return types.ERR_EOF
}
/* check for the delimtier */
if self.s[p] != '[' {
return native.ERR_INVALID_CHAR
return types.ERR_INVALID_CHAR
}
/* update the read pointer */
@ -102,19 +103,19 @@ func (self *Parser) lspace(sp int) int {
return native.Lspace(sv.Ptr, sv.Len, sp)
}
func (self *Parser) decodeValue() (val native.JsonState) {
func (self *Parser) decodeValue() (val types.JsonState) {
sv := (*rt.GoString)(unsafe.Pointer(&self.s))
self.p = native.Value(sv.Ptr, sv.Len, self.p, &val)
return
}
func (self *Parser) decodeArray(ret []Node) (Node, native.ParsingError) {
func (self *Parser) decodeArray(ret []Node) (Node, types.ParsingError) {
sp := self.p
ns := len(self.s)
/* check for EOF */
if self.p = self.lspace(sp); self.p >= ns {
return Node{}, native.ERR_EOF
return Node{}, types.ERR_EOF
}
/* check for empty array */
@ -126,7 +127,7 @@ func (self *Parser) decodeArray(ret []Node) (Node, native.ParsingError) {
/* allocate array space and parse every element */
for {
var val Node
var err native.ParsingError
var err types.ParsingError
/* decode the value */
if val, err = self.Parse(); err != 0 {
@ -139,7 +140,7 @@ func (self *Parser) decodeArray(ret []Node) (Node, native.ParsingError) {
/* check for EOF */
if self.p >= ns {
return Node{}, native.ERR_EOF
return Node{}, types.ERR_EOF
}
/* check for the next character */
@ -150,18 +151,18 @@ func (self *Parser) decodeArray(ret []Node) (Node, native.ParsingError) {
if val.IsRaw() {
return newRawArray(self, ret), 0
}
return Node{}, native.ERR_INVALID_CHAR
return Node{}, types.ERR_INVALID_CHAR
}
}
}
func (self *Parser) decodeObject(ret []Pair) (Node, native.ParsingError) {
func (self *Parser) decodeObject(ret []Pair) (Node, types.ParsingError) {
sp := self.p
ns := len(self.s)
/* check for EOF */
if self.p = self.lspace(sp); self.p >= ns {
return Node{}, native.ERR_EOF
return Node{}, types.ERR_EOF
}
/* check for empty object */
@ -173,12 +174,12 @@ func (self *Parser) decodeObject(ret []Pair) (Node, native.ParsingError) {
/* decode each pair */
for {
var val Node
var njs native.JsonState
var err native.ParsingError
var njs types.JsonState
var err types.ParsingError
/* decode the key */
if njs = self.decodeValue(); njs.Vt != native.V_STRING {
return Node{}, native.ERR_INVALID_CHAR
if njs = self.decodeValue(); njs.Vt != types.V_STRING {
return Node{}, types.ERR_INVALID_CHAR
}
/* extract the key */
@ -208,7 +209,7 @@ func (self *Parser) decodeObject(ret []Pair) (Node, native.ParsingError) {
/* check for EOF */
if self.p >= ns {
return Node{}, native.ERR_EOF
return Node{}, types.ERR_EOF
}
/* check for the next character */
@ -219,12 +220,12 @@ func (self *Parser) decodeObject(ret []Pair) (Node, native.ParsingError) {
if val.IsRaw() {
return newRawObject(self, ret), 0
}
return Node{}, native.ERR_INVALID_CHAR
return Node{}, types.ERR_INVALID_CHAR
}
}
}
func (self *Parser) decodeString(iv int64, ep int) (Node, native.ParsingError) {
func (self *Parser) decodeString(iv int64, ep int) (Node, types.ParsingError) {
p := self.p - 1
s := self.s[iv:p]
@ -251,36 +252,36 @@ func (self *Parser) Pos() int {
return self.p
}
func (self *Parser) Parse() (Node, native.ParsingError) {
func (self *Parser) Parse() (Node, types.ParsingError) {
switch val := self.decodeValue(); val.Vt {
case native.V_EOF : return Node{}, native.ERR_EOF
case native.V_NULL : return nullNode, 0
case native.V_TRUE : return trueNode, 0
case native.V_FALSE : return falseNode, 0
case native.V_STRING : return self.decodeString(val.Iv, val.Ep)
case native.V_ARRAY:
case types.V_EOF : return Node{}, types.ERR_EOF
case types.V_NULL : return nullNode, 0
case types.V_TRUE : return trueNode, 0
case types.V_FALSE : return falseNode, 0
case types.V_STRING : return self.decodeString(val.Iv, val.Ep)
case types.V_ARRAY:
if self.noLazy {
return self.decodeArray(make([]Node, 0, _DEFAULT_NODE_CAP))
}
return newRawArray(self, make([]Node, 0, _DEFAULT_NODE_CAP)), 0
case native.V_OBJECT:
case types.V_OBJECT:
if self.noLazy {
return self.decodeObject(make([]Pair, 0, _DEFAULT_NODE_CAP))
}
return newRawObject(self, make([]Pair, 0, _DEFAULT_NODE_CAP)), 0
case native.V_DOUBLE : return newNumber(self.s[val.Ep:self.p]), 0
case native.V_INTEGER : return newNumber(self.s[val.Ep:self.p]), 0
default : return Node{}, native.ParsingError(-val.Vt)
case types.V_DOUBLE : return newNumber(self.s[val.Ep:self.p]), 0
case types.V_INTEGER : return newNumber(self.s[val.Ep:self.p]), 0
default : return Node{}, types.ParsingError(-val.Vt)
}
}
func (self *Parser) skip() (int, native.ParsingError) {
fsm := stackPool.Get().(*native.StateMachine)
func (self *Parser) skip() (int, types.ParsingError) {
fsm := stackPool.Get().(*types.StateMachine)
start := native.SkipOne(&self.s, &self.p, fsm)
stackPool.Put(fsm)
if start < 0 {
return self.p, native.ParsingError(-start)
return self.p, types.ParsingError(-start)
}
return start, 0
}
@ -288,7 +289,7 @@ func (self *Parser) skip() (int, native.ParsingError) {
/** Parser Factory **/
// Loads parse all json into interface{}
func Loads(src string) (int, interface{}, native.ParsingError) {
func Loads(src string) (int, interface{}, types.ParsingError) {
ps := &Parser{s: src}
np, err := ps.Parse()
@ -300,8 +301,8 @@ func Loads(src string) (int, interface{}, native.ParsingError) {
}
}
// Loads parse all json into interface{}, with numeric nodes casted to json.Number
func LoadsUseNumber(src string) (int, interface{}, native.ParsingError) {
// LoadsUseNumber parse all json into interface{}, with numeric nodes casted to json.Number
func LoadsUseNumber(src string) (int, interface{}, types.ParsingError) {
ps := &Parser{s: src}
np, err := ps.Parse()

View file

@ -19,7 +19,7 @@ package ast
import (
`fmt`
`github.com/bytedance/sonic/internal/native`
`github.com/bytedance/sonic/internal/native/types`
)
type Searcher struct {
@ -50,7 +50,7 @@ func (self *Parser) printNear(start int) string {
func (self *Searcher) GetByPath(path ...interface{}) (Node, error) {
self.parser.p = 0
var err native.ParsingError
var err types.ParsingError
for _, p := range path {
switch p.(type) {
case int:
@ -80,7 +80,7 @@ func (self *Searcher) GetByPath(path ...interface{}) (Node, error) {
return newRawNode(self.parser.s[start:self.parser.p]), nil
}
func (self *Parser) searchKey(match string) native.ParsingError {
func (self *Parser) searchKey(match string) types.ParsingError {
ns := len(self.s)
if err := self.object(); err != 0 {
return err
@ -88,23 +88,23 @@ func (self *Parser) searchKey(match string) native.ParsingError {
/* check for EOF */
if self.p = self.lspace(self.p); self.p >= ns {
return native.ERR_EOF
return types.ERR_EOF
}
/* check for empty object */
if self.s[self.p] == '}' {
self.p++
return native.ERR_EOF
return types.ERR_EOF
}
var njs native.JsonState
var err native.ParsingError
var njs types.JsonState
var err types.ParsingError
/* decode each pair */
for {
/* decode the key */
if njs = self.decodeValue(); njs.Vt != native.V_STRING {
return native.ERR_INVALID_CHAR
if njs = self.decodeValue(); njs.Vt != types.V_STRING {
return types.ERR_INVALID_CHAR
}
/* extract the key */
@ -135,7 +135,7 @@ func (self *Parser) searchKey(match string) native.ParsingError {
/* check for EOF */
self.p = self.lspace(self.p)
if self.p >= ns {
return native.ERR_EOF
return types.ERR_EOF
}
/* check for the next character */
@ -144,14 +144,14 @@ func (self *Parser) searchKey(match string) native.ParsingError {
self.p++
case '}':
self.p++
return native.ERR_EOF
return types.ERR_EOF
default:
return native.ERR_INVALID_CHAR
return types.ERR_INVALID_CHAR
}
}
}
func (self *Parser) searchIndex(idx int) native.ParsingError {
func (self *Parser) searchIndex(idx int) types.ParsingError {
ns := len(self.s)
if err := self.array(); err != 0 {
return err
@ -159,16 +159,16 @@ func (self *Parser) searchIndex(idx int) native.ParsingError {
/* check for EOF */
if self.p = self.lspace(self.p); self.p >= ns {
return native.ERR_EOF
return types.ERR_EOF
}
/* check for empty array */
if self.s[self.p] == ']' {
self.p++
return native.ERR_EOF
return types.ERR_EOF
}
var err native.ParsingError
var err types.ParsingError
/* allocate array space and parse every element */
for i := 0; i < idx; i++ {
@ -180,7 +180,7 @@ func (self *Parser) searchIndex(idx int) native.ParsingError {
/* check for EOF */
self.p = self.lspace(self.p)
if self.p >= ns {
return native.ERR_EOF
return types.ERR_EOF
}
/* check for the next character */
@ -189,9 +189,9 @@ func (self *Parser) searchIndex(idx int) native.ParsingError {
self.p++
case ']':
self.p++
return native.ERR_EOF
return types.ERR_EOF
default:
return native.ERR_INVALID_CHAR
return types.ERR_INVALID_CHAR
}
}

View file

@ -20,6 +20,7 @@ import (
`unsafe`
`github.com/bytedance/sonic/internal/native`
`github.com/bytedance/sonic/internal/native/types`
`github.com/bytedance/sonic/internal/rt`
)
@ -50,7 +51,7 @@ func addr2str(p unsafe.Pointer, n int64) (s string) {
return
}
func unquoteBytes(s string, m *[]byte) native.ParsingError {
func unquoteBytes(s string, m *[]byte) types.ParsingError {
pos := -1
slv := (*rt.GoSlice)(unsafe.Pointer(m))
str := (*rt.GoString)(unsafe.Pointer(&s))
@ -58,7 +59,7 @@ func unquoteBytes(s string, m *[]byte) native.ParsingError {
/* check for errors */
if ret < 0 {
return native.ParsingError(-ret)
return types.ParsingError(-ret)
}
/* update the length */
@ -66,7 +67,7 @@ func unquoteBytes(s string, m *[]byte) native.ParsingError {
return 0
}
func UnquoteString(s string) (ret string, err native.ParsingError) {
func UnquoteString(s string) (ret string, err types.ParsingError) {
mm := make([]byte, 0, len(s))
err = unquoteBytes(s, &mm)
ret = rt.Mem2Str(mm)

View file

@ -25,6 +25,7 @@ import (
`github.com/bytedance/sonic/internal/caching`
`github.com/bytedance/sonic/internal/jit`
`github.com/bytedance/sonic/internal/native`
`github.com/bytedance/sonic/internal/native/types`
`github.com/bytedance/sonic/internal/rt`
`github.com/twitchyliquid64/golang-asm/obj`
)
@ -424,7 +425,7 @@ func (self *_Assembler) base64_error() {
func (self *_Assembler) parsing_error() {
self.Link(_LB_eof_error) // _eof_error:
self.Emit("MOVQ" , _IL, _IC) // MOVQ IL, IC
self.Emit("MOVL" , jit.Imm(int64(native.ERR_EOF)), _EP) // MOVL ${native.ERR_EOF}, EP
self.Emit("MOVL" , jit.Imm(int64(types.ERR_EOF)), _EP) // MOVL ${types.ERR_EOF}, EP
self.Sjmp("JMP" , _LB_parsing_error) // JMP _parsing_error
self.Link(_LB_unquote_error) // _unquote_error:
self.Emit("SUBQ" , _VAR_sr, _SI) // SUBQ sr, SI
@ -457,7 +458,7 @@ func (self *_Assembler) parsing_error() {
self.Link(_LB_char_1_error) // _char_1_error:
self.Emit("ADDQ" , jit.Imm(1), _IC) // ADDQ $1, IC
self.Link(_LB_char_0_error) // _char_0_error:
self.Emit("MOVL" , jit.Imm(int64(native.ERR_INVALID_CHAR)), _EP) // MOVL ${native.ERR_INVALID_CHAR}, EP
self.Emit("MOVL" , jit.Imm(int64(types.ERR_INVALID_CHAR)), _EP) // MOVL ${types.ERR_INVALID_CHAR}, EP
self.Link(_LB_parsing_error) // _parsing_error:
self.Emit("MOVOU", _ARG_s, _X0) // MOVOU s, X0
self.Emit("MOVOU", _X0, jit.Ptr(_SP, 0)) // MOVOU X0, (SP)
@ -570,15 +571,15 @@ func init() {
}
func (self *_Assembler) range_single() {
self.Emit("VMOVSD" , _VAR_st_Dv, _X0) // VMOVSD st.Dv, X0
self.Emit("MOVSD" , _VAR_st_Dv, _X0) // MOVSD st.Dv, X0
self.Emit("MOVQ" , _V_max_f32, _AX) // MOVQ _max_f32, AX
self.Emit("MOVQ" , jit.Gitab(_I_float32), _ET) // MOVQ ${itab(float32)}, ET
self.Emit("MOVQ" , jit.Gtype(_T_float32), _EP) // MOVQ ${type(float32)}, EP
self.Emit("VUCOMISD", jit.Ptr(_AX, 0), _X0) // VUCOMISD (AX), X0
self.Emit("UCOMISD" , jit.Ptr(_AX, 0), _X0) // UCOMISD (AX), X0
self.Sjmp("JA" , _LB_range_error) // JA _range_error
self.Emit("MOVQ" , _V_min_f32, _AX) // MOVQ _min_f32, AX
self.Emit("VMOVSD" , jit.Ptr(_AX, 0), _X1) // VMOVSD (AX), X1
self.Emit("VUCOMISD", _X0, _X1) // VUCOMISD X0, X1
self.Emit("MOVSD" , jit.Ptr(_AX, 0), _X1) // MOVSD (AX), X1
self.Emit("UCOMISD" , _X0, _X1) // UCOMISD X0, X1
self.Sjmp("JA" , _LB_range_error) // JA _range_error
self.Emit("CVTSD2SS", _X0, _X0) // CVTSD2SS X0, X0
}
@ -634,7 +635,7 @@ func (self *_Assembler) unquote_once(p obj.Addr, n obj.Addr) {
self.Emit("XORL" , _R8, _R8) // XORL R8, R8
self.Emit("BTQ" , jit.Imm(_F_disable_urc), _ARG_fv) // BTQ ${_F_disable_urc}, fv
self.Emit("SETCC", _R8) // SETCC R8
self.Emit("SHLQ" , jit.Imm(native.B_UNICODE_REPLACE), _R8) // SHLQ ${native.B_UNICODE_REPLACE}, R8
self.Emit("SHLQ" , jit.Imm(types.B_UNICODE_REPLACE), _R8) // SHLQ ${types.B_UNICODE_REPLACE}, R8
self.call(_F_unquote) // CALL unquote
self.Emit("MOVQ" , n, _SI) // MOVQ ${n}, SI
self.Emit("ADDQ" , jit.Imm(1), _SI) // ADDQ $1, SI
@ -661,11 +662,11 @@ func (self *_Assembler) unquote_twice(p obj.Addr, n obj.Addr) {
self.Emit("MOVQ" , n, _SI) // MOVQ ${n}, SI
self.Emit("MOVQ" , _DX, p) // MOVQ DX, ${p}
self.Emit("LEAQ" , _VAR_sr, _CX) // LEAQ sr, CX
self.Emit("MOVL" , jit.Imm(native.F_DOUBLE_UNQUOTE), _R8) // MOVL ${native.F_DOUBLE_UNQUOTE}, R8
self.Emit("MOVL" , jit.Imm(types.F_DOUBLE_UNQUOTE), _R8) // MOVL ${types.F_DOUBLE_UNQUOTE}, R8
self.Emit("BTQ" , jit.Imm(_F_disable_urc), _ARG_fv) // BTQ ${_F_disable_urc}, AX
self.Emit("XORL" , _AX, _AX) // XORL AX, AX
self.Emit("SETCC", _AX) // SETCC AX
self.Emit("SHLQ" , jit.Imm(native.B_UNICODE_REPLACE), _AX) // SHLQ ${native.B_UNICODE_REPLACE}, AX
self.Emit("SHLQ" , jit.Imm(types.B_UNICODE_REPLACE), _AX) // SHLQ ${types.B_UNICODE_REPLACE}, AX
self.Emit("ORQ" , _AX, _R8) // ORQ AX, R8
self.call(_F_unquote) // CALL unquote
self.Emit("MOVQ" , n, _SI) // MOVQ ${n}, SI
@ -1013,15 +1014,15 @@ func (self *_Assembler) _asm_OP_u64(_ *_Instr) {
}
func (self *_Assembler) _asm_OP_f32(_ *_Instr) {
self.parse_number() // PARSE NUMBER
self.range_single() // RANGE float32
self.Emit("VMOVSS", _X0, jit.Ptr(_VP, 0)) // VMOVSS X0, (VP)
self.parse_number() // PARSE NUMBER
self.range_single() // RANGE float32
self.Emit("MOVSS", _X0, jit.Ptr(_VP, 0)) // MOVSS X0, (VP)
}
func (self *_Assembler) _asm_OP_f64(_ *_Instr) {
self.parse_number() // PARSE NUMBER
self.Emit("VMOVSD", _VAR_st_Dv, _X0) // VMOVSD st.Dv, X0
self.Emit("VMOVSD", _X0, jit.Ptr(_VP, 0)) // VMOVSD X0, (VP)
self.parse_number() // PARSE NUMBER
self.Emit("MOVSD", _VAR_st_Dv, _X0) // MOVSD st.Dv, X0
self.Emit("MOVSD", _X0, jit.Ptr(_VP, 0)) // MOVSD X0, (VP)
}
func (self *_Assembler) _asm_OP_unquote(_ *_Instr) {
@ -1041,13 +1042,13 @@ func (self *_Assembler) _asm_OP_nil_1(_ *_Instr) {
}
func (self *_Assembler) _asm_OP_nil_2(_ *_Instr) {
self.Emit("VPXOR", _X0, _X0, _X0) // VPXOR X0, X0, X0
self.Emit("PXOR" , _X0, _X0) // PXOR X0, X0
self.Emit("MOVOU", _X0, jit.Ptr(_VP, 0)) // MOVOU X0, (VP)
}
func (self *_Assembler) _asm_OP_nil_3(_ *_Instr) {
self.Emit("XORL" , _AX, _AX) // XORL AX, AX
self.Emit("VPXOR", _X0, _X0, _X0) // VPXOR X0, X0, X0
self.Emit("PXOR" , _X0, _X0) // PXOR X0, X0
self.Emit("MOVOU", _X0, jit.Ptr(_VP, 0)) // MOVOU X0, (VP)
self.Emit("MOVQ" , _AX, jit.Ptr(_VP, 16)) // MOVOU X0, 16(VP)
}
@ -1133,7 +1134,7 @@ func (self *_Assembler) _asm_OP_map_key_u64(p *_Instr) {
func (self *_Assembler) _asm_OP_map_key_f32(p *_Instr) {
self.parse_number() // PARSE NUMBER
self.range_single() // RANGE float32
self.Emit("VMOVSS", _X0, _VAR_st_Dv) // VMOVSS X0, st.Dv
self.Emit("MOVSS", _X0, _VAR_st_Dv) // MOVSS X0, st.Dv
self.mapassign_std(p.vt(), _VAR_st_Dv) // MAPASSIGN ${p.vt()}, mapassign, st.Dv
}
@ -1371,7 +1372,7 @@ func (self *_Assembler) _asm_OP_drop_2(_ *_Instr) {
self.Emit("SUBQ" , jit.Imm(16), _AX) // SUBQ $16, AX
self.Emit("MOVQ" , jit.Sib(_ST, _AX, 1, 8), _VP) // MOVQ 8(ST)(AX), VP
self.Emit("MOVQ" , _AX, jit.Ptr(_ST, 0)) // MOVQ AX, (ST)
self.Emit("VPXOR", _X0, _X0, _X0) // VPXOR X0, X0, X0
self.Emit("PXOR" , _X0, _X0) // PXOR X0, X0
self.Emit("MOVOU", _X0, jit.Sib(_ST, _AX, 1, 8)) // MOVOU X0, 8(ST)(AX)
}

View file

@ -25,7 +25,7 @@ import (
`github.com/bytedance/sonic/internal/caching`
`github.com/bytedance/sonic/internal/jit`
`github.com/bytedance/sonic/internal/native`
`github.com/bytedance/sonic/internal/native/types`
`github.com/bytedance/sonic/internal/rt`
`github.com/stretchr/testify/assert`
`github.com/stretchr/testify/require`
@ -182,26 +182,26 @@ func TestAssembler_OpCode(t *testing.T) {
key: "_OP_str/error_eof",
ins: []_Instr{newInsOp(_OP_str)},
src: `12345`,
err: SyntaxError{Src: `12345`, Pos: 5, Code: native.ERR_EOF},
err: SyntaxError{Src: `12345`, Pos: 5, Code: types.ERR_EOF},
val: new(string),
}, {
key: "_OP_str/error_invalid_escape",
ins: []_Instr{newInsOp(_OP_str)},
src: `12\g345"`,
err: SyntaxError{Src: `12\g345"`, Pos: 3, Code: native.ERR_INVALID_ESCAPE},
err: SyntaxError{Src: `12\g345"`, Pos: 3, Code: types.ERR_INVALID_ESCAPE},
val: new(string),
}, {
key: "_OP_str/error_invalid_unicode",
ins: []_Instr{newInsOp(_OP_str)},
src: `hello\ud800world"`,
opt: 1 << _F_disable_urc,
err: SyntaxError{Src: `hello\ud800world"`, Pos: 7, Code: native.ERR_INVALID_UNICODE},
err: SyntaxError{Src: `hello\ud800world"`, Pos: 7, Code: types.ERR_INVALID_UNICODE},
val: new(string),
}, {
key: "_OP_str/error_invalid_char",
ins: []_Instr{newInsOp(_OP_str)},
src: `12\u1ggg345"`,
err: SyntaxError{Src: `12\u1ggg345"`, Pos: 5, Code: native.ERR_INVALID_CHAR},
err: SyntaxError{Src: `12\u1ggg345"`, Pos: 5, Code: types.ERR_INVALID_CHAR},
val: new(string),
}, {
key: "_OP_bin",
@ -213,7 +213,7 @@ func TestAssembler_OpCode(t *testing.T) {
key: "_OP_bin/error_eof",
ins: []_Instr{newInsOp(_OP_bin)},
src: `aGVsbG8sIHdvcmxk`,
err: SyntaxError{Src: `aGVsbG8sIHdvcmxk`, Pos: 16, Code: native.ERR_EOF},
err: SyntaxError{Src: `aGVsbG8sIHdvcmxk`, Pos: 16, Code: types.ERR_EOF},
val: new([]byte),
}, {
key: "_OP_bin/error_corrupt_input",
@ -243,25 +243,25 @@ func TestAssembler_OpCode(t *testing.T) {
key: "_OP_bool/error_eof_1",
ins: []_Instr{newInsOp(_OP_bool)},
src: "tru",
err: SyntaxError{Src: `tru`, Pos: 3, Code: native.ERR_EOF},
err: SyntaxError{Src: `tru`, Pos: 3, Code: types.ERR_EOF},
val: new(bool),
}, {
key: "_OP_bool/error_eof_2",
ins: []_Instr{newInsOp(_OP_bool)},
src: "fals",
err: SyntaxError{Src: `fals`, Pos: 4, Code: native.ERR_EOF},
err: SyntaxError{Src: `fals`, Pos: 4, Code: types.ERR_EOF},
val: new(bool),
}, {
key: "_OP_bool/error_invalid_char_1",
ins: []_Instr{newInsOp(_OP_bool)},
src: "falxe",
err: SyntaxError{Src: `falxe`, Pos: 3, Code: native.ERR_INVALID_CHAR},
err: SyntaxError{Src: `falxe`, Pos: 3, Code: types.ERR_INVALID_CHAR},
val: new(bool),
}, {
key: "_OP_bool/error_invalid_char_2",
ins: []_Instr{newInsOp(_OP_bool)},
src: "falsx",
err: SyntaxError{Src: `falsx`, Pos: 4, Code: native.ERR_INVALID_CHAR},
err: SyntaxError{Src: `falsx`, Pos: 4, Code: types.ERR_INVALID_CHAR},
val: new(bool),
}, {
key: "_OP_num/positive",
@ -279,13 +279,13 @@ func TestAssembler_OpCode(t *testing.T) {
key: "_OP_num/error_eof",
ins: []_Instr{newInsOp(_OP_num)},
src: "-",
err: SyntaxError{Src: `-`, Pos: 1, Code: native.ERR_EOF},
err: SyntaxError{Src: `-`, Pos: 1, Code: types.ERR_EOF},
val: new(json.Number),
}, {
key: "_OP_num/error_invalid_char",
ins: []_Instr{newInsOp(_OP_num)},
src: "xxx",
err: SyntaxError{Src: `xxx`, Pos: 0, Code: native.ERR_INVALID_CHAR},
err: SyntaxError{Src: `xxx`, Pos: 0, Code: types.ERR_INVALID_CHAR},
val: new(json.Number),
}, {
key: "_OP_i8",
@ -303,7 +303,7 @@ func TestAssembler_OpCode(t *testing.T) {
key: "_OP_i8/error_wrong_type",
ins: []_Instr{newInsOp(_OP_i8)},
src: "12.34",
err: SyntaxError{Src: `12.34`, Pos: 2, Code: native.ERR_INVALID_NUMBER_FMT},
err: SyntaxError{Src: `12.34`, Pos: 2, Code: types.ERR_INVALID_NUMBER_FMT},
val: new(int8),
}, {
key: "_OP_u8",
@ -321,13 +321,13 @@ func TestAssembler_OpCode(t *testing.T) {
key: "_OP_u8/error_underflow",
ins: []_Instr{newInsOp(_OP_u8)},
src: "-123",
err: SyntaxError{Src: `-123`, Pos: 0, Code: native.ERR_INVALID_NUMBER_FMT},
err: SyntaxError{Src: `-123`, Pos: 0, Code: types.ERR_INVALID_NUMBER_FMT},
val: new(uint8),
}, {
key: "_OP_u8/error_wrong_type",
ins: []_Instr{newInsOp(_OP_u8)},
src: "12.34",
err: SyntaxError{Src: `12.34`, Pos: 2, Code: native.ERR_INVALID_NUMBER_FMT},
err: SyntaxError{Src: `12.34`, Pos: 2, Code: types.ERR_INVALID_NUMBER_FMT},
val: new(uint8),
}, {
key: "_OP_f32",
@ -369,7 +369,7 @@ func TestAssembler_OpCode(t *testing.T) {
key: "_OP_unquote/error_invalid_end",
ins: []_Instr{newInsOp(_OP_unquote)},
src: `\"te\\\"st"`,
err: SyntaxError{Src: `\"te\\\"st"`, Pos: 8, Code: native.ERR_INVALID_CHAR},
err: SyntaxError{Src: `\"te\\\"st"`, Pos: 8, Code: types.ERR_INVALID_CHAR},
val: new(string),
}, {
key: "_OP_nil_1",
@ -382,7 +382,7 @@ func TestAssembler_OpCode(t *testing.T) {
ins: []_Instr{newInsOp(_OP_nil_2)},
src: "",
exp: error(nil),
val: (func() *error { v := new(error); *v = native.ERR_EOF; return v })(),
val: (func() *error { v := new(error); *v = types.ERR_EOF; return v })(),
}, {
key: "_OP_nil_3",
ins: []_Instr{newInsOp(_OP_nil_3)},
@ -623,7 +623,7 @@ func TestAssembler_OpCode(t *testing.T) {
key: "_OP_lspace/error",
ins: []_Instr{newInsOp(_OP_lspace)},
src: "",
err: SyntaxError{Src: ``, Pos: 0, Code: native.ERR_EOF},
err: SyntaxError{Src: ``, Pos: 0, Code: types.ERR_EOF},
val: nil,
}, {
key: "_OP_match_char/correct",
@ -635,7 +635,7 @@ func TestAssembler_OpCode(t *testing.T) {
key: "_OP_match_char/error",
ins: []_Instr{newInsVb(_OP_match_char, 'b')},
src: "a",
err: SyntaxError{Src: `a`, Pos: 0, Code: native.ERR_INVALID_CHAR},
err: SyntaxError{Src: `a`, Pos: 0, Code: types.ERR_INVALID_CHAR},
val: nil,
}, {
key: "_OP_switch",

View file

@ -24,13 +24,13 @@ import (
`strconv`
`strings`
`github.com/bytedance/sonic/internal/native`
`github.com/bytedance/sonic/internal/native/types`
)
type SyntaxError struct {
Pos int
Src string
Code native.ParsingError
Code types.ParsingError
}
func (self SyntaxError) Error() string {
@ -86,7 +86,7 @@ func clamp_zero(v int) int {
}
}
func error_wrap(src string, pos int, code native.ParsingError) error {
func error_wrap(src string, pos int, code types.ParsingError) error {
return SyntaxError {
Pos : pos,
Src : src,
@ -111,6 +111,6 @@ func error_value(value string, vtype reflect.Type) error {
}
//go:nosplit
func throw_invalid_type(vt native.ValueType) {
func throw_invalid_type(vt types.ValueType) {
throw(fmt.Sprintf("invalid value type: %d", vt))
}

View file

@ -19,14 +19,14 @@ package decoder
import (
`testing`
`github.com/bytedance/sonic/internal/native`
`github.com/bytedance/sonic/internal/native/types`
)
func make_err(src string, pos int) SyntaxError {
return SyntaxError {
Src : src,
Pos : pos,
Code : native.ERR_INVALID_CHAR,
Code : types.ERR_INVALID_CHAR,
}
}

View file

@ -22,6 +22,7 @@ import (
`github.com/bytedance/sonic/internal/jit`
`github.com/bytedance/sonic/internal/native`
`github.com/bytedance/sonic/internal/native/types`
`github.com/bytedance/sonic/internal/rt`
`github.com/twitchyliquid64/golang-asm/obj`
)
@ -112,8 +113,8 @@ var (
)
var (
_V_max = jit.Imm(int64(native.V_MAX))
_V_eof = jit.Imm(int64(native.ERR_EOF))
_V_max = jit.Imm(int64(types.V_MAX))
_V_eof = jit.Imm(int64(types.ERR_EOF))
_F_value = jit.Imm(int64(native.S_value))
)
@ -293,7 +294,7 @@ func (self *_ValueDecoder) instrs() {
self.Emit("XORL" , _R8, _R8) // XORL R8, R8
self.Emit("BTQ" , jit.Imm(_F_disable_urc), _VP) // BTQ ${_F_disable_urc}, VP
self.Emit("SETCC", _R8) // SETCC R8
self.Emit("SHLQ" , jit.Imm(native.B_UNICODE_REPLACE), _R8) // SHLQ ${native.B_UNICODE_REPLACE}, R8
self.Emit("SHLQ" , jit.Imm(types.B_UNICODE_REPLACE), _R8) // SHLQ ${types.B_UNICODE_REPLACE}, R8
self.call(_F_unquote) // CALL unquote
self.Emit("TESTQ", _AX, _AX) // TESTQ AX, AX
self.Sjmp("JS" , _LB_esc_error) // JS _esc_error
@ -309,14 +310,14 @@ func (self *_ValueDecoder) instrs() {
/* V_DOUBLE */
self.Link(_SW_case_V_DOUBLE)
self.Emit("BTQ" , jit.Imm(_F_use_number), _VP) // BTQ ${_F_use_number}, VP
self.Sjmp("JC" , "_use_number") // JC _use_number
self.Emit("VMOVSD", _VAR_vv_Dv, _X0) // VMOVSD st.Dv, X0
self.Emit("VMOVSD", _X0, jit.Ptr(_SP, 0)) // VMOVSD X0, (SP)
self.Emit("BTQ" , jit.Imm(_F_use_number), _VP) // BTQ ${_F_use_number}, VP
self.Sjmp("JC" , "_use_number") // JC _use_number
self.Emit("MOVSD", _VAR_vv_Dv, _X0) // MOVSD st.Dv, X0
self.Emit("MOVSD", _X0, jit.Ptr(_SP, 0)) // MOVSD X0, (SP)
self.call_go(_F_convT64) // CALL_GO convT64
self.Emit("MOVQ" , _T_float64, _RT) // MOVQ ${type(float64)}, RT
self.Emit("MOVQ" , jit.Ptr(_SP, 8), _RV) // MOVQ 8(SP), RV
self.Sjmp("JMP" , _LB_done) // JMP _done
self.Emit("MOVQ" , _T_float64, _RT) // MOVQ ${type(float64)}, RT
self.Emit("MOVQ" , jit.Ptr(_SP, 8), _RV) // MOVQ 8(SP), RV
self.Sjmp("JMP" , _LB_done) // JMP _done
/* V_INTEGER */
self.Link(_SW_case_V_INTEGER)

View file

@ -39,15 +39,15 @@
#define ERR_INVALID_CHAR $-2
#define lspace(to) \
MOVQ PS, DI \
MOVQ PN, SI \
MOVQ PI, DX \
MOVQ github·combytedancesonicinternalnative·_subr__lspace(SB), AX \
CALL AX \
MOVQ AX, PI \
TESTQ AX, AX \
JNS to \
RET \
MOVQ PS, DI \
MOVQ PN, SI \
MOVQ PI, DX \
MOVQ github·combytedancesonicinternalnative·S_lspace(SB), AX \
CALL AX \
MOVQ AX, PI \
TESTQ AX, AX \
JNS to \
RET \
to:
#define match_eof(to) \
@ -337,7 +337,7 @@ TEXT decodeObjectKey(SB), NOSPLIT, $120 - 0
LEAQ VAR_in, DI
LEAQ VAR_in_PI, SI
LEAQ VAR_vv, DX
MOVQ github·combytedancesonicinternalnative·_subr__vstring(SB), AX
MOVQ github·combytedancesonicinternalnative·S_vstring(SB), AX
CALL AX
MOVQ VAR_in_PI, PI
@ -397,7 +397,7 @@ _unquote:
BTQ F_DISABLE_URC, FL
SETCC R8
SHLQ B_UNICODE_REPLACE, R8
MOVQ github·combytedancesonicinternalnative·_subr__unquote(SB), AX
MOVQ github·combytedancesonicinternalnative·S_unquote(SB), AX
CALL AX
TESTQ AX, AX
JS _escape_error

View file

@ -23,7 +23,7 @@ import (
`unsafe`
`github.com/bytedance/sonic/ast`
`github.com/bytedance/sonic/internal/native`
`github.com/bytedance/sonic/internal/native/types`
`github.com/bytedance/sonic/internal/rt`
`github.com/davecgh/go-spew/spew`
`github.com/stretchr/testify/require`
@ -32,7 +32,7 @@ import (
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func decodeInterface(s string, f uint64) (int, interface{}, native.ParsingError)
func decodeInterface(s string, f uint64) (int, interface{}, types.ParsingError)
//go:nosplit
//go:noescape
@ -54,7 +54,7 @@ func TestGeneric_DecodeInterface(t *testing.T) {
func TestGeneric_DecodeObjectKeyString(t *testing.T) {
r := decodeObjectKeyString(` "hello\u2333world"`, 4)
if v := (*rt.GoString)(unsafe.Pointer(&r)).Len; v < 0 {
require.NoError(t, native.ParsingError(-v))
require.NoError(t, types.ParsingError(-v))
}
spew.Dump(r)
}

View file

@ -21,7 +21,7 @@ import (
`unsafe`
`github.com/bytedance/sonic/internal/caching`
`github.com/bytedance/sonic/internal/native`
`github.com/bytedance/sonic/internal/native/types`
`github.com/bytedance/sonic/internal/rt`
)
@ -40,7 +40,7 @@ var (
type _Stack struct {
sp uintptr
sb [_MaxStack]unsafe.Pointer
mm native.StateMachine
mm types.StateMachine
}
type _Decoder func(

View file

@ -22,6 +22,7 @@ import (
`strconv`
`unsafe`
`github.com/bytedance/sonic/internal/cpu`
`github.com/bytedance/sonic/internal/jit`
`github.com/twitchyliquid64/golang-asm/obj`
`github.com/twitchyliquid64/golang-asm/obj/x86`
@ -115,10 +116,6 @@ var (
var (
_X0 = jit.Reg("X0")
_X1 = jit.Reg("X1")
)
var (
_Y0 = jit.Reg("Y0")
_Y1 = jit.Reg("Y1")
_Y2 = jit.Reg("Y2")
@ -411,16 +408,16 @@ func (self *_Assembler) save_state() {
}
func (self *_Assembler) drop_state(decr int64) {
self.Emit("MOVQ" , jit.Ptr(_ST, 0), _AX) // MOVQ (ST), AX
self.Emit("SUBQ" , jit.Imm(decr), _AX) // SUBQ $decr, AX
self.Emit("MOVQ" , _AX, jit.Ptr(_ST, 0)) // MOVQ AX, (ST)
self.Emit("MOVQ" , jit.Sib(_ST, _AX, 1, 8), _SP_x) // MOVQ 8(ST)(AX), SP.x
self.Emit("MOVQ" , jit.Sib(_ST, _AX, 1, 16), _SP_f) // MOVQ 16(ST)(AX), SP.f
self.Emit("MOVQ" , jit.Sib(_ST, _AX, 1, 24), _SP_p) // MOVQ 24(ST)(AX), SP.p
self.Emit("MOVQ" , jit.Sib(_ST, _AX, 1, 32), _SP_q) // MOVQ 32(ST)(AX), SP.q
self.Emit("VPXOR" , _Y0, _Y0, _Y0) // VPXOR Y0, Y0, Y0
self.Emit("VMOVDQU", _Y0, jit.Sib(_ST, _AX, 1, 8)) // VMOVDQU Y0, 8(ST)(AX)
self.Emit("VZEROUPPER") // VZEROUPPER
self.Emit("MOVQ" , jit.Ptr(_ST, 0), _AX) // MOVQ (ST), AX
self.Emit("SUBQ" , jit.Imm(decr), _AX) // SUBQ $decr, AX
self.Emit("MOVQ" , _AX, jit.Ptr(_ST, 0)) // MOVQ AX, (ST)
self.Emit("MOVQ" , jit.Sib(_ST, _AX, 1, 8), _SP_x) // MOVQ 8(ST)(AX), SP.x
self.Emit("MOVQ" , jit.Sib(_ST, _AX, 1, 16), _SP_f) // MOVQ 16(ST)(AX), SP.f
self.Emit("MOVQ" , jit.Sib(_ST, _AX, 1, 24), _SP_p) // MOVQ 24(ST)(AX), SP.p
self.Emit("MOVQ" , jit.Sib(_ST, _AX, 1, 32), _SP_q) // MOVQ 32(ST)(AX), SP.q
self.Emit("PXOR" , _X0, _X0) // PXOR X0, X0
self.Emit("MOVOU", _X0, jit.Sib(_ST, _AX, 1, 8)) // MOVOU X0, 8(ST)(AX)
self.Emit("MOVOU", _X0, jit.Sib(_ST, _AX, 1, 24)) // MOVOU X0, 24(ST)(AX)
}
/** Buffer Helpers **/
@ -654,6 +651,106 @@ func (self *_Assembler) encode_string(fn obj.Addr, doubleQuote bool) {
self.close_quote(doubleQuote) // QCLOSE $doubleQuote
}
/** Zero Value Check Routine **/
func (self *_Assembler) check_zero(nb int, dest int) {
i := int64(0)
e := int64(nb)
/* special case: zero-sized value, always empty */
if e == 0 {
return
}
/* default instructions for AVX2 */
vclear := func(v obj.Addr) { self.Emit("VPXOR" , v, v, v) }
vset1a := func(a, b obj.Addr) { self.Emit("VPCMPEQB", a, a, b) }
vandpb := func(b, a, r obj.Addr) { self.Emit("VPAND" , b, a, r) }
vcmpeq := func(b, a, r obj.Addr) { self.Emit("VPCMPEQB", b, a, r) }
/* fall-back instructions for AVX */
if !cpu.HasAVX2 {
vclear = func(v obj.Addr) { self.Emit("VXORPS", v, v, v) }
vset1a = func(a, b obj.Addr) { self.Emit("VCMPPS", a, a, b, jit.Imm(0x0f)) }
vandpb = func(b, a, r obj.Addr) { self.Emit("VANDPS", b, a, r) }
vcmpeq = func(b, a, r obj.Addr) { self.Emit("VCMPPS", b, a, r, jit.Imm(0x00)) }
}
/* if n is less than 32 byte, only scalar code will be used;
* otherwise AVX is used, so clear Y0, and set Y1 to all 1s */
if e >= 32 {
vclear(_Y0) // CLEAR Y0
vset1a(_Y0, _Y1) // SET1A Y0, Y1
}
/* 128-byte tests */
for i <= e - 128 {
vcmpeq(jit.Ptr(_SP_p, i + 0), _Y0, _Y2) // CMPEQ i+0(SP.p), Y0, Y2
vcmpeq(jit.Ptr(_SP_p, i + 32), _Y0, _Y3) // CMPEQ i+32(SP.p), Y0, Y3
vcmpeq(jit.Ptr(_SP_p, i + 64), _Y0, _Y4) // CMPEQ i+64(SP.p), Y0, Y4
vcmpeq(jit.Ptr(_SP_p, i + 96), _Y0, _Y5) // CMPEQ i+96(SP.p), Y0, Y5
vandpb(_Y3, _Y2, _Y2) // ANDPB Y3, Y2, Y2
vandpb(_Y5, _Y4, _Y3) // ANDPB Y5, Y4, Y3
vandpb(_Y2, _Y3, _Y3) // ANDPB Y2, Y3, Y3
self.Emit("VPTEST", _Y1, _Y3) // VPTEST Y1, Y3
self.Sjmp("JNC" , "_not_zero_z_{n}") // JNC _not_zero_z_{n}
i += 128
}
/* 32-byte tests */
for i <= e - 32 {
vcmpeq(jit.Ptr(_SP_p, i), _Y0, _Y2) // CMPEQ i(SP.p), Y0, Y2
self.Emit("VPTEST", _Y1, _Y2) // VPTEST Y1, Y2
self.Sjmp("JNC" , "_not_zero_z_{n}") // JNC _not_zero_z_{n}
i += 32
}
/* VZEROUPPER to avoid AVX-SSE transition penalty */
if e >= 32 {
self.Emit("VZEROUPPER")
}
/* 8-byte tests */
for i <= e - 8 {
self.Emit("CMPQ", jit.Ptr(_SP_p, i), jit.Imm(0)) // CMPQ i(SP.p), $0
self.Sjmp("JNE" , "_not_zero_{n}") // JNE _not_zero_{n}
i += 8
}
/* 4 byte test */
if i <= e - 4 {
self.Emit("CMPL", jit.Ptr(_SP_p, i), jit.Imm(0)) // CMPL i(SP.p), $0
self.Sjmp("JNE" , "_not_zero_{n}") // JNE _not_zero_{n}
i += 4
}
/* 2 byte test */
if i <= e - 2 {
self.Emit("CMPW", jit.Ptr(_SP_p, i), jit.Imm(0)) // CMPW i(SP.p), $0
self.Sjmp("JNE" , "_not_zero_{n}") // JNE _not_zero_{n}
i += 2
}
/* the last byte */
if i < e {
self.Emit("CMPB", jit.Ptr(_SP_p, i), jit.Imm(0)) // CMPB i(SP.p), $0
self.Sjmp("JNE" , "_not_zero_{n}") // JNE _not_zero_{n}
}
/* value is not zero */
if e < 32 {
self.Xjmp("JMP", dest)
self.Link("_not_zero_{n}")
return
}
/* VZEROUPPER to avoid AVX-SSE transition penalty */
self.Xjmp("JMP", dest)
self.Link("_not_zero_z_{n}")
self.Emit("VZEROUPPER")
self.Link("_not_zero_{n}")
}
/** OpCode Assembler Functions **/
var (
@ -671,7 +768,7 @@ var (
var (
_F_memmove = jit.Func(memmove)
_F_isZeroSafe = jit.Func(isZeroSafe)
_F_isZeroTyped = jit.Func(isZeroTyped)
_F_mapiternext = jit.Func(mapiternext)
_F_mapiterinit = jit.Func(mapiterinit)
_F_error_number = jit.Func(error_number)
@ -960,103 +1057,15 @@ func (self *_Assembler) _asm_OP_is_zero_map(p *_Instr) {
}
func (self *_Assembler) _asm_OP_is_zero_mem(p *_Instr) {
i := int64(0)
e := int64(p.vlen())
/* increse the offset, and decide what jumps to use */
incr_jump := func(np string, op string, d int64, avx2 bool) {
if i += d; avx2 && e >= 32 {
self.Sjmp(np, "not_zero_z_{n}")
} else if i < e || e >= 32 {
self.Sjmp(np, "not_zero_{n}")
} else {
self.Xjmp(op, p.vi())
}
}
/* if n is less than 32 byte, only SSE2 will be used;
* otherwise AVX2 is used, so clear Y0, and set Y1 to all 0xff */
if e < 32 {
self.Emit("VPXOR", _X0, _X0, _X0) // VPXOR X0, X0, X0
} else {
self.Emit("VPXOR" , _Y0, _Y0, _Y0) // VPXOR Y0, Y0, Y0
self.Emit("VPCMPEQB", _Y1, _Y1, _Y1) // VPCMPEQB Y1, Y1, Y1
}
/* 128-byte tests */
for i <= e - 128 {
self.Emit("VPCMPEQB", jit.Ptr(_SP_p, i + 0), _Y0, _Y2) // VPCMPEQB i+0(SP.p), Y0, Y2
self.Emit("VPCMPEQB", jit.Ptr(_SP_p, i + 32), _Y0, _Y3) // VPCMPEQB i+32(SP.p), Y0, Y3
self.Emit("VPCMPEQB", jit.Ptr(_SP_p, i + 64), _Y0, _Y4) // VPCMPEQB i+64(SP.p), Y0, Y4
self.Emit("VPCMPEQB", jit.Ptr(_SP_p, i + 96), _Y0, _Y5) // VPCMPEQB i+96(SP.p), Y0, Y5
self.Emit("VPAND" , _Y2, _Y3, _Y2) // VPAND Y2, Y3, Y2
self.Emit("VPAND" , _Y4, _Y5, _Y3) // VPAND Y4, Y5, Y3
self.Emit("VPXOR" , _Y3, _Y1, _Y3) // VPXOR Y3, Y1, Y3
self.Emit("VPTEST" , _Y2, _Y3) // VPTEST Y2, Y3
incr_jump("JNC" , "JC", 128, true) // JNC not_zero_z_{n}
}
/* 32-byte tests */
for i <= e - 32 {
self.Emit("VPCMPEQB", jit.Ptr(_SP_p, i), _Y0, _Y2) // VPCMPEQB i(SP.p), Y0, Y2
self.Emit("VPTEST" , _Y2, _Y1) // VPTEST Y2, Y1
incr_jump("JNC" , "JC", 32, true) // JNC not_zero_z_{n}
}
/* VZEROUPPER to avoid AVX-SSE transition penalty */
if e >= 32 {
self.Emit("VZEROUPPER")
}
/* 16 bytes test */
if i <= e - 16 {
self.Emit("PCMPEQB" , jit.Ptr(_SP_p, i), _X0, _X1) // PCMPEQB i(SP.p), X0, X1
self.Emit("PMOVMSKB", _X1, _AX) // PMOVMSKB X1, AX
self.Emit("CMPQ" , jit.Imm(-1), _AX) // CMPQ $-1, AX
incr_jump("JNE" , "JE", 16, false) // JNE not_zero_{n}
}
/* 8-byte tests */
if i <= e - 8 {
self.Emit("CMPQ", jit.Ptr(_SP_p, i), jit.Imm(0)) // CMPQ i(SP.p), $0
incr_jump("JNE" , "JE", 8, false) // JNE not_zero_{n}
}
/* 4 byte test */
if i <= e - 4 {
self.Emit("CMPL", jit.Ptr(_SP_p, i), jit.Imm(0)) // CMPL i(SP.p), $0
incr_jump("JNE" , "JE", 4, false) // JNE not_zero_{n}
}
/* 2 byte test */
if i <= e - 2 {
self.Emit("CMPW", jit.Ptr(_SP_p, i), jit.Imm(0)) // CMPW i(SP.p), $0
incr_jump("JNE" , "JE", 2, false) // JNE not_zero_{n}
}
/* the last byte */
if i < e {
self.Emit("CMPB", jit.Ptr(_SP_p, i), jit.Imm(0)) // CMPB i(SP.p), $0
incr_jump("JNE" , "JE", 1, false) // JNE not_zero_{n}
}
/* VZEROUPPER to avoid AVX-SSE transition penalty */
if e >= 32 {
self.Xjmp("JMP", p.vi())
self.Link("not_zero_z_{n}")
self.Emit("VZEROUPPER")
}
/* value is not zero */
self.Link("not_zero_{n}")
self.NOP()
self.check_zero(p.vlen(), p.vi())
}
func (self *_Assembler) _asm_OP_is_zero_safe(p *_Instr) {
self.check_zero(p.vlen(), p.vi()) // CHECKZ $p.vlen(), p.vi()
self.Emit("MOVQ", jit.Type(p.vt()), _AX) // MOVQ $p.vt(), AX
self.Emit("MOVQ", _SP_p, jit.Ptr(_SP, 0)) // MOVQ SP.p, (SP)
self.Emit("MOVQ", _AX, jit.Ptr(_SP, 8)) // MOVQ AX, 8(SP)
self.call_go(_F_isZeroSafe) // CALL_GO isZeroSafe
self.call_go(_F_isZeroTyped) // CALL_GO isZeroTyped
self.Emit("CMPQ", jit.Ptr(_SP, 16), jit.Imm(0)) // CMPQ 16(SP), $0
self.Xjmp("JNE" , p.vi()) // JNE p.vi()
}

View file

@ -176,12 +176,8 @@ func encodeTextMarshaler(buf *[]byte, val encoding.TextMarshaler) error {
}
}
func isZeroMem(p unsafe.Pointer, nb int) bool {
return native.Lzero(p, nb) == 0
}
func isZeroSafe(p unsafe.Pointer, vt *rt.GoType) bool {
if isZeroMem(p, vt.Size()) {
if native.Lzero(p, vt.Size()) == 0 {
return true
} else {
return isZeroTyped(p, vt)

3
go.mod
View file

@ -3,9 +3,10 @@ module github.com/bytedance/sonic
go 1.15
require (
github.com/chenzhuoyu/base64x v0.0.0-20210528150155-e775e1ff0f56
github.com/chenzhuoyu/base64x v0.0.0-20210528162528-3c6c11c43ee5
github.com/davecgh/go-spew v1.1.1
github.com/json-iterator/go v1.1.10
github.com/klauspost/cpuid/v2 v2.0.6
github.com/stretchr/testify v1.7.0
github.com/tidwall/gjson v1.8.0
github.com/twitchyliquid64/golang-asm v0.15.1

6
go.sum
View file

@ -1,11 +1,13 @@
github.com/chenzhuoyu/base64x v0.0.0-20210528150155-e775e1ff0f56 h1:dwu5dS6rUvkgozhG4LYv4PPs8wu7T9L6D7A2Y1nwHwo=
github.com/chenzhuoyu/base64x v0.0.0-20210528150155-e775e1ff0f56/go.mod h1:NfDzX8KeqVNX62apij1OkqoeDdq1VR3g0TRZo99kkBA=
github.com/chenzhuoyu/base64x v0.0.0-20210528162528-3c6c11c43ee5 h1:7AStn2tanqGY99xzW+Ve1p6YYqnRr1m/yswJ4h0BhcY=
github.com/chenzhuoyu/base64x v0.0.0-20210528162528-3c6c11c43ee5/go.mod h1:NfDzX8KeqVNX62apij1OkqoeDdq1VR3g0TRZo99kkBA=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68=
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/klauspost/cpuid/v2 v2.0.6 h1:dQ5ueTiftKxp0gyjKSx5+8BtPWkyQbd95m8Gys/RarI=
github.com/klauspost/cpuid/v2 v2.0.6/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg=

38
internal/cpu/features.go Normal file
View file

@ -0,0 +1,38 @@
/*
* 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)
)
func init() {
switch v := os.Getenv("SONIC_MODE"); v {
case "" : break
case "auto" : break
case "noavx2" : HasAVX2 = false
default : panic(fmt.Sprintf("invalid mode: '%s', should be one of 'auto', 'noavx2'", v))
}
}

View file

@ -182,7 +182,9 @@ func (self *BaseAssembler) assignOperands(p *obj.Prog, args []obj.Addr) {
case 0 :
case 1 : p.To = args[0]
case 2 : p.To, p.From = args[1], args[0]
default : p.To, p.From, p.RestArgs = args[1], args[0], args[2:]
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")
}
}

View file

@ -0,0 +1,34 @@
/*
* 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 (
`testing`
`github.com/davecgh/go-spew/spew`
`github.com/twitchyliquid64/golang-asm/obj`
`github.com/twitchyliquid64/golang-asm/obj/x86`
)
func TestBackend(t *testing.T) {
e := newBackend("amd64")
p := e.New()
p.As = x86.AVPTEST
(*BaseAssembler)(nil).assignOperands(p, []obj.Addr{Reg("Y2"), Reg("Y1")})
e.Append(p)
spew.Dump(e.Assemble())
}

View file

@ -0,0 +1,66 @@
// 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 (
`math`
`strconv`
`testing`
`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, "1e30" , string(buf[:__f64toa(&buf[0], 1e30)]))
assert.Equal(t, "1.234e33" , string(buf[:__f64toa(&buf[0], 1234e30)]))
assert.Equal(t, "1.234e308" , string(buf[:__f64toa(&buf[0], 1234e305)]))
assert.Equal(t, "1.234e-317" , string(buf[:__f64toa(&buf[0], 1234e-320)]))
assert.Equal(t, "1.7976931348623157e308" , 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, "-1e30" , string(buf[:__f64toa(&buf[0], -1e30)]))
assert.Equal(t, "-1.234e33" , string(buf[:__f64toa(&buf[0], -1234e30)]))
assert.Equal(t, "-1.234e308" , 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 BenchmarkFastFloat_Encode(b *testing.B) {
val := -2.2250738585072014e-308
benchmarks := []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[:], val, 'g', -1, 64) }},
}, {
name: "FastFloat",
test: func(b *testing.B) { var buf [64]byte; for i := 0; i < b.N; i++ { __f64toa(&buf[0], val) }},
}}
for _, bm := range benchmarks {
b.Run(bm.name, bm.test)
}
}

View file

@ -0,0 +1,135 @@
// Code generated by Makefile, DO NOT EDIT.
/*
* Copyright 2021 ByteDance Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package avx
import (
`strconv`
`testing`
`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[:], 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[:], -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)
}
}
func BenchmarkFastInt_UintToString(b *testing.B) {
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[:], uint64(i), 10) }},
}, {
name: "FastInt",
test: func(b *testing.B) { var buf [32]byte; for i := 0; i < b.N; i++ { __u64toa(&buf[0], uint64(i)) }},
}}
for _, bm := range benchmarks {
b.Run(bm.name, bm.test)
}
}

View file

@ -0,0 +1,100 @@
// 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 __lzero(p unsafe.Pointer, n int) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __lquote(buf *string, off int) (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 __value(s unsafe.Pointer, n int, p int, v *types.JsonState) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __vstring(s *string, p *int, v *types.JsonState)
//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) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __skip_array(s *string, p *int, m *types.StateMachine) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __skip_object(s *string, p *int, m *types.StateMachine) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __unquote(s unsafe.Pointer, nb int, dp unsafe.Pointer, ep *int, flags uint64) (ret int)

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,426 @@
// 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 (
`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)
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_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_Vstring(t *testing.T) {
var v types.JsonState
i := 0
s := `test"test\n2"`
__vstring(&s, &i, &v)
assert.Equal(t, 5, i)
assert.Equal(t, -1, v.Ep)
assert.Equal(t, int64(0), v.Iv)
__vstring(&s, &i, &v)
assert.Equal(t, 13, i)
assert.Equal(t, 9, v.Ep)
assert.Equal(t, int64(5), 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)
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{})
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{})
assert.Equal(t, 1, p)
assert.Equal(t, 0, q)
q = __skip_one(&s, &p, &types.StateMachine{})
assert.Equal(t, 5, p)
assert.Equal(t, 2, q)
q = __skip_one(&s, &p, &types.StateMachine{})
assert.Equal(t, 8, p)
assert.Equal(t, 6, q)
q = __skip_one(&s, &p, &types.StateMachine{})
assert.Equal(t, 21, p)
assert.Equal(t, 9, q)
q = __skip_one(&s, &p, &types.StateMachine{})
assert.Equal(t, 26, p)
assert.Equal(t, 22, q)
q = __skip_one(&s, &p, &types.StateMachine{})
assert.Equal(t, 32, p)
assert.Equal(t, 27, q)
q = __skip_one(&s, &p, &types.StateMachine{})
assert.Equal(t, 37, p)
assert.Equal(t, 33, q)
q = __skip_one(&s, &p, &types.StateMachine{})
assert.Equal(t, 40, p)
assert.Equal(t, 38, q)
q = __skip_one(&s, &p, &types.StateMachine{})
assert.Equal(t, 43, p)
assert.Equal(t, 41, q)
}
func TestNative_SkipArray(t *testing.T) {
p := 0
s := `null, true, false, 1, 2.0, -3, {"asdf": "wqer"}],`
__skip_array(&s, &p, &types.StateMachine{})
assert.Equal(t, p, 48)
}
func TestNative_SkipObject(t *testing.T) {
p := 0
s := `"asdf": "wqer"},`
__skip_object(&s, &p, &types.StateMachine{})
assert.Equal(t, p, 15)
}

View file

@ -0,0 +1,45 @@
// 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_i64toa = _subr__i64toa
S_lquote = _subr__lquote
S_u64toa = _subr__u64toa
)
var (
S_lspace = _subr__lspace
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_array = _subr__skip_array
S_skip_object = _subr__skip_object
)

View file

@ -1,7 +1,7 @@
// +build !noasm !appengine
// Code generated by asm2asm, DO NOT EDIT.
package native
package avx
import (
`unsafe`
@ -14,21 +14,21 @@ func ___asm2asm_compiled_code__DO_NOT_CALL_THIS_SYMBOL___()
var (
_func__base = ___asm2asm_compiled_code__DO_NOT_CALL_THIS_SYMBOL___
_subr__f64toa = **(**uintptr)(unsafe.Pointer(&_func__base)) + 2953
_subr__i64toa = **(**uintptr)(unsafe.Pointer(&_func__base)) + 6042
_subr__lquote = **(**uintptr)(unsafe.Pointer(&_func__base)) + 384
_subr__lspace = **(**uintptr)(unsafe.Pointer(&_func__base)) + 1266
_subr__f64toa = **(**uintptr)(unsafe.Pointer(&_func__base)) + 2480
_subr__i64toa = **(**uintptr)(unsafe.Pointer(&_func__base)) + 5544
_subr__lquote = **(**uintptr)(unsafe.Pointer(&_func__base)) + 295
_subr__lspace = **(**uintptr)(unsafe.Pointer(&_func__base)) + 937
_subr__lzero = **(**uintptr)(unsafe.Pointer(&_func__base)) + 0
_subr__skip_array = **(**uintptr)(unsafe.Pointer(&_func__base)) + 14398
_subr__skip_object = **(**uintptr)(unsafe.Pointer(&_func__base)) + 14433
_subr__skip_one = **(**uintptr)(unsafe.Pointer(&_func__base)) + 12845
_subr__u64toa = **(**uintptr)(unsafe.Pointer(&_func__base)) + 6135
_subr__unquote = **(**uintptr)(unsafe.Pointer(&_func__base)) + 7356
_subr__value = **(**uintptr)(unsafe.Pointer(&_func__base)) + 9076
_subr__vnumber = **(**uintptr)(unsafe.Pointer(&_func__base)) + 11325
_subr__vsigned = **(**uintptr)(unsafe.Pointer(&_func__base)) + 12295
_subr__vstring = **(**uintptr)(unsafe.Pointer(&_func__base)) + 10096
_subr__vunsigned = **(**uintptr)(unsafe.Pointer(&_func__base)) + 12572
_subr__skip_array = **(**uintptr)(unsafe.Pointer(&_func__base)) + 13958
_subr__skip_object = **(**uintptr)(unsafe.Pointer(&_func__base)) + 13993
_subr__skip_one = **(**uintptr)(unsafe.Pointer(&_func__base)) + 12328
_subr__u64toa = **(**uintptr)(unsafe.Pointer(&_func__base)) + 5637
_subr__unquote = **(**uintptr)(unsafe.Pointer(&_func__base)) + 6825
_subr__value = **(**uintptr)(unsafe.Pointer(&_func__base)) + 8460
_subr__vnumber = **(**uintptr)(unsafe.Pointer(&_func__base)) + 10806
_subr__vsigned = **(**uintptr)(unsafe.Pointer(&_func__base)) + 11778
_subr__vstring = **(**uintptr)(unsafe.Pointer(&_func__base)) + 9464
_subr__vunsigned = **(**uintptr)(unsafe.Pointer(&_func__base)) + 12055
)
var (

View file

@ -0,0 +1,66 @@
// 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 (
`math`
`strconv`
`testing`
`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, "1e30" , string(buf[:__f64toa(&buf[0], 1e30)]))
assert.Equal(t, "1.234e33" , string(buf[:__f64toa(&buf[0], 1234e30)]))
assert.Equal(t, "1.234e308" , string(buf[:__f64toa(&buf[0], 1234e305)]))
assert.Equal(t, "1.234e-317" , string(buf[:__f64toa(&buf[0], 1234e-320)]))
assert.Equal(t, "1.7976931348623157e308" , 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, "-1e30" , string(buf[:__f64toa(&buf[0], -1e30)]))
assert.Equal(t, "-1.234e33" , string(buf[:__f64toa(&buf[0], -1234e30)]))
assert.Equal(t, "-1.234e308" , 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 BenchmarkFastFloat_Encode(b *testing.B) {
val := -2.2250738585072014e-308
benchmarks := []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[:], val, 'g', -1, 64) }},
}, {
name: "FastFloat",
test: func(b *testing.B) { var buf [64]byte; for i := 0; i < b.N; i++ { __f64toa(&buf[0], val) }},
}}
for _, bm := range benchmarks {
b.Run(bm.name, bm.test)
}
}

View file

@ -0,0 +1,135 @@
// Code generated by Makefile, DO NOT EDIT.
/*
* Copyright 2021 ByteDance Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package avx2
import (
`strconv`
`testing`
`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[:], 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[:], -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)
}
}
func BenchmarkFastInt_UintToString(b *testing.B) {
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[:], uint64(i), 10) }},
}, {
name: "FastInt",
test: func(b *testing.B) { var buf [32]byte; for i := 0; i < b.N; i++ { __u64toa(&buf[0], uint64(i)) }},
}}
for _, bm := range benchmarks {
b.Run(bm.name, bm.test)
}
}

View file

@ -0,0 +1,100 @@
// 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 __lzero(p unsafe.Pointer, n int) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __lquote(buf *string, off int) (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 __value(s unsafe.Pointer, n int, p int, v *types.JsonState) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __vstring(s *string, p *int, v *types.JsonState)
//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) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __skip_array(s *string, p *int, m *types.StateMachine) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __skip_object(s *string, p *int, m *types.StateMachine) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __unquote(s unsafe.Pointer, nb int, dp unsafe.Pointer, ep *int, flags uint64) (ret int)

View file

@ -0,0 +1,426 @@
// 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 (
`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)
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_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_Vstring(t *testing.T) {
var v types.JsonState
i := 0
s := `test"test\n2"`
__vstring(&s, &i, &v)
assert.Equal(t, 5, i)
assert.Equal(t, -1, v.Ep)
assert.Equal(t, int64(0), v.Iv)
__vstring(&s, &i, &v)
assert.Equal(t, 13, i)
assert.Equal(t, 9, v.Ep)
assert.Equal(t, int64(5), 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)
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{})
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{})
assert.Equal(t, 1, p)
assert.Equal(t, 0, q)
q = __skip_one(&s, &p, &types.StateMachine{})
assert.Equal(t, 5, p)
assert.Equal(t, 2, q)
q = __skip_one(&s, &p, &types.StateMachine{})
assert.Equal(t, 8, p)
assert.Equal(t, 6, q)
q = __skip_one(&s, &p, &types.StateMachine{})
assert.Equal(t, 21, p)
assert.Equal(t, 9, q)
q = __skip_one(&s, &p, &types.StateMachine{})
assert.Equal(t, 26, p)
assert.Equal(t, 22, q)
q = __skip_one(&s, &p, &types.StateMachine{})
assert.Equal(t, 32, p)
assert.Equal(t, 27, q)
q = __skip_one(&s, &p, &types.StateMachine{})
assert.Equal(t, 37, p)
assert.Equal(t, 33, q)
q = __skip_one(&s, &p, &types.StateMachine{})
assert.Equal(t, 40, p)
assert.Equal(t, 38, q)
q = __skip_one(&s, &p, &types.StateMachine{})
assert.Equal(t, 43, p)
assert.Equal(t, 41, q)
}
func TestNative_SkipArray(t *testing.T) {
p := 0
s := `null, true, false, 1, 2.0, -3, {"asdf": "wqer"}],`
__skip_array(&s, &p, &types.StateMachine{})
assert.Equal(t, p, 48)
}
func TestNative_SkipObject(t *testing.T) {
p := 0
s := `"asdf": "wqer"},`
__skip_object(&s, &p, &types.StateMachine{})
assert.Equal(t, p, 15)
}

View file

@ -0,0 +1,45 @@
// 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_i64toa = _subr__i64toa
S_lquote = _subr__lquote
S_u64toa = _subr__u64toa
)
var (
S_lspace = _subr__lspace
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_array = _subr__skip_array
S_skip_object = _subr__skip_object
)

View file

@ -0,0 +1,50 @@
// +build !noasm !appengine
// Code generated by asm2asm, DO NOT EDIT.
package avx2
import (
`unsafe`
)
//go:nosplit
//go:noescape
//goland:noinspection ALL
func ___asm2asm_compiled_code__DO_NOT_CALL_THIS_SYMBOL___()
var (
_func__base = ___asm2asm_compiled_code__DO_NOT_CALL_THIS_SYMBOL___
_subr__f64toa = **(**uintptr)(unsafe.Pointer(&_func__base)) + 3038
_subr__i64toa = **(**uintptr)(unsafe.Pointer(&_func__base)) + 6102
_subr__lquote = **(**uintptr)(unsafe.Pointer(&_func__base)) + 376
_subr__lspace = **(**uintptr)(unsafe.Pointer(&_func__base)) + 1268
_subr__lzero = **(**uintptr)(unsafe.Pointer(&_func__base)) + 0
_subr__skip_array = **(**uintptr)(unsafe.Pointer(&_func__base)) + 14619
_subr__skip_object = **(**uintptr)(unsafe.Pointer(&_func__base)) + 14654
_subr__skip_one = **(**uintptr)(unsafe.Pointer(&_func__base)) + 13066
_subr__u64toa = **(**uintptr)(unsafe.Pointer(&_func__base)) + 6195
_subr__unquote = **(**uintptr)(unsafe.Pointer(&_func__base)) + 7419
_subr__value = **(**uintptr)(unsafe.Pointer(&_func__base)) + 9196
_subr__vnumber = **(**uintptr)(unsafe.Pointer(&_func__base)) + 11544
_subr__vsigned = **(**uintptr)(unsafe.Pointer(&_func__base)) + 12516
_subr__vstring = **(**uintptr)(unsafe.Pointer(&_func__base)) + 10216
_subr__vunsigned = **(**uintptr)(unsafe.Pointer(&_func__base)) + 12793
)
var (
_ = _subr__f64toa
_ = _subr__i64toa
_ = _subr__lquote
_ = _subr__lspace
_ = _subr__lzero
_ = _subr__skip_array
_ = _subr__skip_object
_ = _subr__skip_one
_ = _subr__u64toa
_ = _subr__unquote
_ = _subr__value
_ = _subr__vnumber
_ = _subr__vsigned
_ = _subr__vstring
_ = _subr__vunsigned
)

View file

@ -0,0 +1,123 @@
/*
* 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/types`
)
var (
S_f64toa uintptr
S_i64toa uintptr
S_u64toa uintptr
S_lquote uintptr
S_lspace 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_array uintptr
S_skip_object uintptr
)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func Lzero(p unsafe.Pointer, n int) int
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func Lquote(buf *string, off int) int
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func Lspace(sp unsafe.Pointer, nb int, off int) int
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func Value(s unsafe.Pointer, n int, p int, v *types.JsonState) int
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func SkipOne(s *string, p *int, m *types.StateMachine) int
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func Unquote(s unsafe.Pointer, nb int, dp unsafe.Pointer, ep *int, flags uint64) int
func useAVX() {
S_f64toa = avx.S_f64toa
S_i64toa = avx.S_i64toa
S_u64toa = avx.S_u64toa
S_lquote = avx.S_lquote
S_lspace = avx.S_lspace
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_array = avx.S_skip_array
S_skip_object = avx.S_skip_object
}
func useAVX2() {
S_f64toa = avx2.S_f64toa
S_i64toa = avx2.S_i64toa
S_u64toa = avx2.S_u64toa
S_lquote = avx2.S_lquote
S_lspace = avx2.S_lspace
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_array = avx2.S_skip_array
S_skip_object = avx2.S_skip_object
}
func init() {
if cpu.HasAVX2 {
useAVX2()
} else if cpu.HasAVX {
useAVX()
} else {
panic("Unsupported CPU, maybe it's too old to run Sonic.")
}
}

View file

@ -0,0 +1,55 @@
//
// 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 ·Lzero(SB), NOSPLIT, $0 - 24
CMPB github·combytedancesonicinternalcpu·HasAVX2(SB), $0
JE 2(PC)
JMP github·combytedancesonicinternalnativeavx2·__lzero(SB)
JMP github·combytedancesonicinternalnativeavx·__lzero(SB)
TEXT ·Lquote(SB), NOSPLIT, $0 - 24
CMPB github·combytedancesonicinternalcpu·HasAVX2(SB), $0
JE 2(PC)
JMP github·combytedancesonicinternalnativeavx2·__lquote(SB)
JMP github·combytedancesonicinternalnativeavx·__lquote(SB)
TEXT ·Lspace(SB), NOSPLIT, $0 - 32
CMPB github·combytedancesonicinternalcpu·HasAVX2(SB), $0
JE 2(PC)
JMP github·combytedancesonicinternalnativeavx2·__lspace(SB)
JMP github·combytedancesonicinternalnativeavx·__lspace(SB)
TEXT ·Value(SB), NOSPLIT, $0 - 40
CMPB github·combytedancesonicinternalcpu·HasAVX2(SB), $0
JE 2(PC)
JMP github·combytedancesonicinternalnativeavx2·__value(SB)
JMP github·combytedancesonicinternalnativeavx·__value(SB)
TEXT ·SkipOne(SB), NOSPLIT, $0 - 32
CMPB github·combytedancesonicinternalcpu·HasAVX2(SB), $0
JE 2(PC)
JMP github·combytedancesonicinternalnativeavx2·__skip_one(SB)
JMP github·combytedancesonicinternalnativeavx·__skip_one(SB)
TEXT ·Unquote(SB), NOSPLIT, $0 - 48
CMPB github·combytedancesonicinternalcpu·HasAVX2(SB), $0
JE 2(PC)
JMP github·combytedancesonicinternalnativeavx2·__unquote(SB)
JMP github·combytedancesonicinternalnativeavx·__unquote(SB)

View file

@ -14,7 +14,7 @@
* limitations under the License.
*/
package native
package {{PACKAGE}}
import (
`math`

View file

@ -14,7 +14,7 @@
* limitations under the License.
*/
package native
package {{PACKAGE}}
import (
`strconv`

View file

@ -14,10 +14,12 @@
* limitations under the License.
*/
package native
package {{PACKAGE}}
import (
`unsafe`
`github.com/bytedance/sonic/internal/native/types`
)
//go:nosplit
@ -53,42 +55,42 @@ func __lspace(sp unsafe.Pointer, nb int, off int) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __value(s unsafe.Pointer, n int, p int, v *JsonState) (ret int)
func __value(s unsafe.Pointer, n int, p int, v *types.JsonState) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __vstring(s *string, p *int, v *JsonState)
func __vstring(s *string, p *int, v *types.JsonState)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __vnumber(s *string, p *int, v *JsonState)
func __vnumber(s *string, p *int, v *types.JsonState)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __vsigned(s *string, p *int, v *JsonState)
func __vsigned(s *string, p *int, v *types.JsonState)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __vunsigned(s *string, p *int, v *JsonState)
func __vunsigned(s *string, p *int, v *types.JsonState)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __skip_one(s *string, p *int, m *StateMachine) (ret int)
func __skip_one(s *string, p *int, m *types.StateMachine) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __skip_array(s *string, p *int, m *StateMachine) (ret int)
func __skip_array(s *string, p *int, m *types.StateMachine) (ret int)
//go:nosplit
//go:noescape
//goland:noinspection GoUnusedParameter
func __skip_object(s *string, p *int, m *StateMachine) (ret int)
func __skip_object(s *string, p *int, m *types.StateMachine) (ret int)
//go:nosplit
//go:noescape

View file

@ -14,7 +14,7 @@
* limitations under the License.
*/
package native
package {{PACKAGE}}
import (
`encoding/hex`
@ -23,6 +23,7 @@ import (
`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`
@ -30,12 +31,12 @@ import (
)
func TestNative_Value(t *testing.T) {
var v JsonState
var v types.JsonState
s := ` -12345`
p := (*rt.GoString)(unsafe.Pointer(&s))
x := __value(p.Ptr, p.Len, 0, &v)
assert.Equal(t, 9, x)
assert.Equal(t, V_INTEGER, v.Vt)
assert.Equal(t, types.V_INTEGER, v.Vt)
assert.Equal(t, int64(-12345), v.Iv)
assert.Equal(t, 3, v.Ep)
}
@ -48,7 +49,7 @@ func TestNative_Unquote(t *testing.T) {
sp := (*rt.GoString)(unsafe.Pointer(&s))
rv := __unquote(sp.Ptr, sp.Len, dp.Ptr, &ep, 0)
if rv < 0 {
require.NoError(t, ParsingError(-rv))
require.NoError(t, types.ParsingError(-rv))
}
dp.Len = rv
assert.Equal(t, -1, ep)
@ -62,7 +63,7 @@ func TestNative_UnquoteError(t *testing.T) {
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(ERR_EOF), rv)
assert.Equal(t, -int(types.ERR_EOF), rv)
assert.Equal(t, 5, ep)
s = `asdf\gqwer`
d = make([]byte, 0, len(s))
@ -70,7 +71,7 @@ func TestNative_UnquoteError(t *testing.T) {
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(ERR_INVALID_ESCAPE), rv)
assert.Equal(t, -int(types.ERR_INVALID_ESCAPE), rv)
assert.Equal(t, 5, ep)
s = `asdf\u1gggqwer`
d = make([]byte, 0, len(s))
@ -78,7 +79,7 @@ func TestNative_UnquoteError(t *testing.T) {
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(ERR_INVALID_CHAR), rv)
assert.Equal(t, -int(types.ERR_INVALID_CHAR), rv)
assert.Equal(t, 7, ep)
s = `asdf\ud800qwer`
d = make([]byte, 0, len(s))
@ -86,15 +87,15 @@ func TestNative_UnquoteError(t *testing.T) {
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(ERR_INVALID_UNICODE), rv)
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, F_DOUBLE_UNQUOTE)
assert.Equal(t, -int(ERR_INVALID_UNICODE), rv)
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))
@ -102,15 +103,15 @@ func TestNative_UnquoteError(t *testing.T) {
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(ERR_INVALID_UNICODE), rv)
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, F_DOUBLE_UNQUOTE)
assert.Equal(t, -int(ERR_INVALID_UNICODE), rv)
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)
}
@ -120,9 +121,9 @@ func TestNative_DoubleUnquote(t *testing.T) {
ep := -1
dp := (*rt.GoSlice)(unsafe.Pointer(&d))
sp := (*rt.GoString)(unsafe.Pointer(&s))
rv := __unquote(sp.Ptr, sp.Len, dp.Ptr, &ep, F_DOUBLE_UNQUOTE)
rv := __unquote(sp.Ptr, sp.Len, dp.Ptr, &ep, types.F_DOUBLE_UNQUOTE)
if rv < 0 {
require.NoError(t, ParsingError(-rv))
require.NoError(t, types.ParsingError(-rv))
}
dp.Len = rv
assert.Equal(t, -1, ep)
@ -135,9 +136,9 @@ func TestNative_UnquoteUnicodeReplacement(t *testing.T) {
ep := -1
dp := (*rt.GoSlice)(unsafe.Pointer(&d))
sp := (*rt.GoString)(unsafe.Pointer(&s))
rv := __unquote(sp.Ptr, sp.Len, dp.Ptr, &ep, F_UNICODE_REPLACE)
rv := __unquote(sp.Ptr, sp.Len, dp.Ptr, &ep, types.F_UNICODE_REPLACE)
if rv < 0 {
require.NoError(t, ParsingError(-rv))
require.NoError(t, types.ParsingError(-rv))
}
dp.Len = rv
assert.Equal(t, -1, ep)
@ -147,9 +148,9 @@ func TestNative_UnquoteUnicodeReplacement(t *testing.T) {
ep = -1
dp = (*rt.GoSlice)(unsafe.Pointer(&d))
sp = (*rt.GoString)(unsafe.Pointer(&s))
rv = __unquote(sp.Ptr, sp.Len, dp.Ptr, &ep, F_UNICODE_REPLACE)
rv = __unquote(sp.Ptr, sp.Len, dp.Ptr, &ep, types.F_UNICODE_REPLACE)
if rv < 0 {
require.NoError(t, ParsingError(-rv))
require.NoError(t, types.ParsingError(-rv))
}
dp.Len = rv
assert.Equal(t, -1, ep)
@ -157,7 +158,7 @@ func TestNative_UnquoteUnicodeReplacement(t *testing.T) {
}
func TestNative_Vstring(t *testing.T) {
var v JsonState
var v types.JsonState
i := 0
s := `test"test\n2"`
__vstring(&s, &i, &v)
@ -179,231 +180,231 @@ func TestNative_VstringHangUpOnRandomData(t *testing.T) {
assert.Nil(t, e)
p := 1
s := rt.Mem2Str(v)
var js JsonState
var js types.JsonState
__vstring(&s, &p, &js)
fmt.Printf("js: %s\n", spew.Sdump(js))
}
func TestNative_Vnumber(t *testing.T) {
var v JsonState
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, V_INTEGER, v.Vt)
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, V_DOUBLE, v.Vt)
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, V_DOUBLE, v.Vt)
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, V_DOUBLE, v.Vt)
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, V_DOUBLE, v.Vt)
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, V_DOUBLE, v.Vt)
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, V_DOUBLE, v.Vt)
assert.Equal(t, types.V_DOUBLE, v.Vt)
}
func TestNative_Vsigned(t *testing.T) {
var v JsonState
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, V_INTEGER, v.Vt)
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, V_INTEGER, v.Vt)
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, V_INTEGER, v.Vt)
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, V_INTEGER, v.Vt)
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, ValueType(-int(ERR_INTEGER_OVERFLOW)), v.Vt)
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, ValueType(-int(ERR_INTEGER_OVERFLOW)), v.Vt)
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, ValueType(-int(ERR_INVALID_NUMBER_FMT)), v.Vt)
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, ValueType(-int(ERR_INVALID_NUMBER_FMT)), v.Vt)
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, ValueType(-int(ERR_INVALID_NUMBER_FMT)), v.Vt)
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, ValueType(-int(ERR_INVALID_NUMBER_FMT)), v.Vt)
assert.Equal(t, types.ValueType(-int(types.ERR_INVALID_NUMBER_FMT)), v.Vt)
}
func TestNative_Vunsigned(t *testing.T) {
var v JsonState
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, V_INTEGER, v.Vt)
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, V_INTEGER, v.Vt)
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, ValueType(-int(ERR_INTEGER_OVERFLOW)), v.Vt)
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, ValueType(-int(ERR_INVALID_NUMBER_FMT)), v.Vt)
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, ValueType(-int(ERR_INVALID_NUMBER_FMT)), v.Vt)
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, ValueType(-int(ERR_INVALID_NUMBER_FMT)), v.Vt)
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, ValueType(-int(ERR_INVALID_NUMBER_FMT)), v.Vt)
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, ValueType(-int(ERR_INVALID_NUMBER_FMT)), v.Vt)
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, ValueType(-int(ERR_INVALID_NUMBER_FMT)), v.Vt)
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, ValueType(-int(ERR_INVALID_NUMBER_FMT)), v.Vt)
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, &StateMachine{})
q := __skip_one(&s, &p, &types.StateMachine{})
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, &StateMachine{})
q = __skip_one(&s, &p, &types.StateMachine{})
assert.Equal(t, 1, p)
assert.Equal(t, 0, q)
q = __skip_one(&s, &p, &StateMachine{})
q = __skip_one(&s, &p, &types.StateMachine{})
assert.Equal(t, 5, p)
assert.Equal(t, 2, q)
q = __skip_one(&s, &p, &StateMachine{})
q = __skip_one(&s, &p, &types.StateMachine{})
assert.Equal(t, 8, p)
assert.Equal(t, 6, q)
q = __skip_one(&s, &p, &StateMachine{})
q = __skip_one(&s, &p, &types.StateMachine{})
assert.Equal(t, 21, p)
assert.Equal(t, 9, q)
q = __skip_one(&s, &p, &StateMachine{})
q = __skip_one(&s, &p, &types.StateMachine{})
assert.Equal(t, 26, p)
assert.Equal(t, 22, q)
q = __skip_one(&s, &p, &StateMachine{})
q = __skip_one(&s, &p, &types.StateMachine{})
assert.Equal(t, 32, p)
assert.Equal(t, 27, q)
q = __skip_one(&s, &p, &StateMachine{})
q = __skip_one(&s, &p, &types.StateMachine{})
assert.Equal(t, 37, p)
assert.Equal(t, 33, q)
q = __skip_one(&s, &p, &StateMachine{})
q = __skip_one(&s, &p, &types.StateMachine{})
assert.Equal(t, 40, p)
assert.Equal(t, 38, q)
q = __skip_one(&s, &p, &StateMachine{})
q = __skip_one(&s, &p, &types.StateMachine{})
assert.Equal(t, 43, p)
assert.Equal(t, 41, q)
}
@ -411,13 +412,13 @@ func TestNative_SkipOne(t *testing.T) {
func TestNative_SkipArray(t *testing.T) {
p := 0
s := `null, true, false, 1, 2.0, -3, {"asdf": "wqer"}],`
__skip_array(&s, &p, &StateMachine{})
__skip_array(&s, &p, &types.StateMachine{})
assert.Equal(t, p, 48)
}
func TestNative_SkipObject(t *testing.T) {
p := 0
s := `"asdf": "wqer"},`
__skip_object(&s, &p, &StateMachine{})
__skip_object(&s, &p, &types.StateMachine{})
assert.Equal(t, p, 15)
}

View file

@ -0,0 +1,43 @@
/*
* 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_i64toa = _subr__i64toa
S_lquote = _subr__lquote
S_u64toa = _subr__u64toa
)
var (
S_lspace = _subr__lspace
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_array = _subr__skip_array
S_skip_object = _subr__skip_object
)

View file

@ -14,11 +14,10 @@
* limitations under the License.
*/
package native
package types
import (
`fmt`
`unsafe`
)
type ValueType int
@ -96,53 +95,3 @@ type StateMachine struct {
Sp int
Vt [MAX_RECURSE]int
}
var (
S_f64toa = _subr__f64toa
S_i64toa = _subr__i64toa
S_lquote = _subr__lquote
S_u64toa = _subr__u64toa
)
var (
S_lspace = _subr__lspace
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_array = _subr__skip_array
S_skip_object = _subr__skip_object
)
func Lzero(p unsafe.Pointer, n int) int {
return __lzero(p, n)
}
func Lquote(buf *string, off int) int {
return __lquote(buf, off)
}
func Lspace(sp unsafe.Pointer, nb int, off int) int {
return __lspace(sp, nb, off)
}
func Value(s unsafe.Pointer, n int, p int, v *JsonState) int {
return __value(s, n, p, v)
}
func SkipOne(s *string, p *int, m *StateMachine) int {
return __skip_one(s, p, m)
}
func Unquote(s unsafe.Pointer, nb int, dp unsafe.Pointer, ep *int, flags uint64) int {
return __unquote(s, nb, dp, ep, flags)
}

View file

@ -16,43 +16,39 @@
#include "native.h"
#if USE_SSE
#define loop_decl() \
size_t v; \
size_t n = 0; \
const char * p = s; \
#define loop_m128(func, ...) { \
if (nb >= 16) { \
if ((v = func(_mm_loadu_si128(as_m128c(p)), ## __VA_ARGS__)) < 16) { \
#define loop_simd(size, load, func, ...) { \
while (nb >= size) { \
if ((v = func(load((const void *)(p)), ## __VA_ARGS__)) < size) { \
return n + v; \
} else { \
n += v; \
p += 16; \
nb -= 16; \
p += size; \
nb -= size; \
} \
} \
}
#define loop_m256(func, ...) { \
while (nb >= 32) { \
if ((v = func(_mm256_loadu_si256(as_m256c(p)), ## __VA_ARGS__)) < 32) { \
return n + v; \
} else { \
n += v; \
p += 32; \
nb -= 32; \
} \
} \
}
#if !USE_AVX2
#define loop_zero()
#define loop_m256(func, ...)
#else
#define loop_zero() _mm256_zeroupper();
#define loop_m256(func, ...) loop_simd(32, _mm256_loadu_si256, func, ## __VA_ARGS__)
#endif
#define loop_last(func, ...) { \
return func(_mm_loadu_si128(as_m128c(p + nb - 16)), ## __VA_ARGS__) + n + nb - 16; \
}
#define loop_m128(func, ...) loop_simd(16, _mm_loadu_si128, func, ## __VA_ARGS__)
#define loop_last(func, ...) return func(_mm_loadu_si128(as_m128c(p + nb - 16)), ## __VA_ARGS__) + n + nb - 16;
#define loop_simd(func, ...) { \
#define loop_bulk(func, ...) { \
loop_decl() \
loop_m256(func ## _avx2, ## __VA_ARGS__) \
_mm256_zeroupper(); \
loop_zero(); \
loop_m128(func ## _sse2, ## __VA_ARGS__) \
loop_last(func ## _sse2, ## __VA_ARGS__) \
}
@ -95,6 +91,7 @@ static inline size_t lspace_sse2(__m128i v0) {
return v9;
}
#if USE_AVX2
static inline size_t lspace_avx2(__m256i v0) {
__m256i v1 = _mm256_cmpeq_epi8 (v0, _mm256_set1_epi8(' '));
__m256i v2 = _mm256_cmpeq_epi8 (v0, _mm256_set1_epi8('\t'));
@ -107,6 +104,7 @@ static inline size_t lspace_avx2(__m256i v0) {
uint64_t v9 = __builtin_ctzll (~(uint64_t)(v8));
return v9;
}
#endif
static inline size_t lquote_sse2(__m128i v0) {
__m128i v1 = _mm_cmpgt_epi8 (v0, _mm_set1_epi8(-1));
@ -121,6 +119,7 @@ static inline size_t lquote_sse2(__m128i v0) {
return v9;
}
#if USE_AVX2
static inline size_t lquote_avx2(__m256i v0) {
__m256i v1 = _mm256_cmpgt_epi8 (v0, _mm256_set1_epi8(-1));
__m256i v2 = _mm256_cmpgt_epi8 (v0, _mm256_set1_epi8(31));
@ -133,6 +132,7 @@ static inline size_t lquote_avx2(__m256i v0) {
uint64_t v9 = __builtin_ctzll ((uint64_t)v8 | 0xffffffff00000000);
return v9;
}
#endif
static inline size_t strchr2_sse2(__m128i v0, uint64_t c0, uint64_t c1) {
__m128i v1 = _mm_cmpeq_epi8 (v0, _mm_set1_epi8((char)c0));
@ -143,6 +143,7 @@ static inline size_t strchr2_sse2(__m128i v0, uint64_t c0, uint64_t c1) {
return v5;
}
#if USE_AVX2
static inline size_t strchr2_avx2(__m256i v0, uint64_t c0, uint64_t c1) {
__m256i v1 = _mm256_cmpeq_epi8 (v0, _mm256_set1_epi8((char)c0));
__m256i v2 = _mm256_cmpeq_epi8 (v0, _mm256_set1_epi8((char)c1));
@ -151,127 +152,59 @@ static inline size_t strchr2_avx2(__m256i v0, uint64_t c0, uint64_t c1) {
uint64_t v5 = __builtin_ctzll ((uint64_t)v4 | 0xffffffff00000000);
return v5;
}
#endif
#define do_simd(func, ...) { \
if (nb == 0) { \
return 0; \
} if (nb < 16) { \
loop_duff(func, ## __VA_ARGS__) \
} else { \
loop_bulk(func, ## __VA_ARGS__) \
} \
}
#endif
#define is_quote(c) ((c) == '"' || (c) == '\\' || ((c) >= 0 && (c) <= 31))
#define is_space(c) ((c) == ' ' || (c) == '\t' || (c) == '\n' || (c) == '\r')
static inline size_t lspace_p(const char *s, size_t nb) {
if (nb == 0) {
return 0;
} else if (nb < 16) {
loop_duff(lspace)
} else {
loop_simd(lspace)
}
#if USE_SSE
do_simd(lspace)
#else
size_t i = 0;
while (i < nb && !is_space(s[i])) i++;
return i;
#endif
}
static inline size_t lquote_p(const char *s, size_t nb) {
if (nb == 0) {
return 0;
} else if (nb < 16) {
loop_duff(lquote)
} else {
loop_simd(lquote)
}
#if USE_SSE
do_simd(lquote)
#else
size_t i = 0;
while (i < nb && !is_quote(s[i])) i++;
return i;
#endif
}
static inline size_t strchr1_p(const char *p, size_t nb, uint64_t ch) {
__m256i a;
__m256i b;
__m256i c;
__m256i d;
__m256i u;
__m256i v;
__m256i w;
int32_t r;
#if USE_SSE
int64_t r;
uint32_t t;
/* prepare the vector */
__m256i x = _mm256_set1_epi8(ch);
ssize_t n = nb;
uintptr_t m = (uintptr_t)p;
const char * q = p;
/* check for pointer alignment */
if (m & 31) {
v = _mm256_load_si256 ((const void *)(m & -32));
v = _mm256_cmpeq_epi8 (v, x);
r = _mm256_movemask_epi8 (v);
/* check for match in the first characters */
if ((r = r >> (t = m & 31)) != 0) {
if ((r = _mm_tzcnt_64(r)) < n) {
return r;
} else {
return -1;
}
}
/* make the pointer aligned */
p += 32 - t;
n -= 32 - t;
}
/* attempt to compare 128-bytes at a time */
while (n >= 128) {
a = _mm256_cmpeq_epi8 (_mm256_load_si256((const void *)(p + 0)), x);
b = _mm256_cmpeq_epi8 (_mm256_load_si256((const void *)(p + 32)), x);
c = _mm256_cmpeq_epi8 (_mm256_load_si256((const void *)(p + 64)), x);
d = _mm256_cmpeq_epi8 (_mm256_load_si256((const void *)(p + 96)), x);
u = _mm256_or_si256 (a, b);
v = _mm256_or_si256 (c, d);
w = _mm256_or_si256 (u, v);
/* check if anything matches */
if (_mm256_testz_si256(w, w)) {
p += 128;
n -= 128;
continue;
}
/* match something in the 128-byte region */
if ((r = _mm256_movemask_epi8(a)) != 0) {
return p - q + _mm_tzcnt_64(r);
} else if ((r = _mm256_movemask_epi8(b)) != 0) {
return p - q + _mm_tzcnt_64(r) + 32;
} else if ((r = _mm256_movemask_epi8(c)) != 0) {
return p - q + _mm_tzcnt_64(r) + 64;
} else {
return p - q + _mm_tzcnt_64(_mm256_movemask_epi8(d)) + 96;
}
}
/* check every 32 bytes, at most 4 times */
for (int i = 0; i < 4 && n >= 0; i++) {
v = _mm256_cmpeq_epi8 (_mm256_load_si256((const void *)p), x);
r = _mm256_movemask_epi8 (v);
/* found something */
if (r != 0) {
if ((r = _mm_tzcnt_64(r)) >= n) {
return -1;
} else {
return p - q + r;
}
}
/* otherwise advance to next block */
p += 32;
n -= 32;
}
/* not found */
return nb;
}
static inline size_t strchr2_p(const char *s, size_t nb, uint64_t c0, uint64_t c1) {
if (nb == 0) {
return 0;
} else if (nb < 16) {
loop_duff(strchr2, c0, c1)
} else {
loop_simd(strchr2, c0, c1)
}
}
size_t lzero(const char *p, size_t n) {
#if USE_AVX2
#define ALIGN_VAL 31
#define _mm_or _mm256_or_si256
#define _mm_load _mm256_load_si256
#define _mm_cmpeq(a, b) _mm256_cmpeq_epi8(a, b)
#define _mm_testz(v) _mm256_testz_si256(v, v)
#define _mm_movemask(v) _mm256_movemask_epi8(v)
__m256i a;
__m256i b;
__m256i c;
@ -279,47 +212,219 @@ size_t lzero(const char *p, size_t n) {
__m256i u;
__m256i v;
__m256i w;
__m256i x = _mm256_set1_epi8(ch);
#else
#define ALIGN_VAL 15
#define _mm_or _mm_or_si128
#define _mm_load _mm_load_si128
#define _mm_cmpeq(a, b) _mm_cmpeq_epi8(a, b)
#define _mm_testz(v) (_mm_movemask_epi8(v) == 0)
#define _mm_movemask(v) _mm_movemask_epi8(v)
__m128i a;
__m128i b;
__m128i c;
__m128i d;
__m128i u;
__m128i v;
__m128i w;
__m128i x = _mm_set1_epi8(ch);
#endif
/* zero vector */
size_t r = 0;
#define BLOCK_SIZE (ALIGN_VAL + 1)
#define BLOCK_MASK (1ull << BLOCK_SIZE)
#define BLOCK_LARGE (BLOCK_SIZE * 4)
/* check for pointer alignment */
if (m & ALIGN_VAL) {
v = _mm_load ((const void *)(m & -BLOCK_SIZE));
v = _mm_cmpeq (v, x);
r = _mm_movemask (v);
/* check for match in the first characters */
if ((r >>= (t = m & ALIGN_VAL)) != 0) {
if ((r = __builtin_ctzll(r | BLOCK_MASK)) < n) {
return r;
} else {
return -1;
}
}
/* make the pointer aligned */
p += BLOCK_SIZE - t;
n -= BLOCK_SIZE - t;
}
/* attempt to compare 4 blocks at a time */
while (n >= BLOCK_LARGE) {
a = _mm_load ((const void *)(p + BLOCK_SIZE * 0));
b = _mm_load ((const void *)(p + BLOCK_SIZE * 1));
c = _mm_load ((const void *)(p + BLOCK_SIZE * 2));
d = _mm_load ((const void *)(p + BLOCK_SIZE * 3));
a = _mm_cmpeq (a, x);
b = _mm_cmpeq (b, x);
c = _mm_cmpeq (c, x);
d = _mm_cmpeq (d, x);
u = _mm_or (a, b);
v = _mm_or (c, d);
w = _mm_or (u, v);
/* check if anything matches */
if (_mm_testz(w)) {
p += BLOCK_LARGE;
n -= BLOCK_LARGE;
continue;
}
/* match something in the 4-blocks region */
if ((r = _mm_movemask(a)) != 0) {
return p - q + __builtin_ctzll(r | BLOCK_MASK);
} else if ((r = _mm_movemask(b)) != 0) {
return p - q + __builtin_ctzll(r | BLOCK_MASK) + BLOCK_SIZE;
} else if ((r = _mm_movemask(c)) != 0) {
return p - q + __builtin_ctzll(r | BLOCK_MASK) + BLOCK_SIZE * 2;
} else {
return p - q + __builtin_ctzll(_mm_movemask(d) | BLOCK_MASK) + BLOCK_SIZE * 3;
}
}
/* check every block, at most 4 times */
for (int i = 0; i < 4 && n >= 0; i++) {
v = _mm_load ((const void *)p);
v = _mm_cmpeq (v, x);
r = _mm_movemask (v);
/* found something */
if (r != 0) {
if ((r = __builtin_ctzll(r | BLOCK_MASK)) >= n) {
return -1;
} else {
return p - q + r;
}
}
/* otherwise advance to next block */
p += BLOCK_SIZE;
n -= BLOCK_SIZE;
}
#undef _mm_load
#undef _mm_bitor
#undef _mm_cmpeq
#undef _mm_testz
#undef _mm_movemask
#undef ALIGN_VAL
#undef BLOCK_SIZE
#undef BLOCK_LARGE
#else
for (size_t i = 0; i < nb; i++) {
if (p[i] == ch) {
return i;
}
}
#endif
/* not found */
return nb;
}
static inline size_t strchr2_p(const char *s, size_t nb, uint64_t c0, uint64_t c1) {
#if USE_SSE
do_simd(strchr2, c0, c1)
#else
size_t i = 0;
while (i < nb && s[i] != c0 && s[i] != c1) i++;
return i;
#endif
}
size_t lzero(const char *p, size_t n) {
#if USE_SSE
#if USE_AVX
__m256i a;
__m256i b;
__m256i c;
__m256i d;
__m256i u;
__m256i v;
__m256i w;
__m256i y = _mm256_set1_epi8(0xff);
__m256i z = _mm256_setzero_si256();
#define BLOCK_SIZE 32
#else
__m128i a;
__m128i b;
__m128i c;
__m128i d;
__m128i u;
__m128i v;
__m128i w;
__m128i z = _mm_setzero_si128();
#define BLOCK_SIZE 16
#endif
/* 128 bytes loop */
while (n >= 128) {
a = _mm256_cmpeq_epi8 (_mm256_loadu_si256(as_m256c(p + 0)), z);
b = _mm256_cmpeq_epi8 (_mm256_loadu_si256(as_m256c(p + 32)), z);
c = _mm256_cmpeq_epi8 (_mm256_loadu_si256(as_m256c(p + 64)), z);
d = _mm256_cmpeq_epi8 (_mm256_loadu_si256(as_m256c(p + 96)), z);
u = _mm256_and_si256 (a, b);
v = _mm256_and_si256 (c, d);
w = _mm256_xor_si256 (v, y);
#if USE_AVX2
#define _mm_load _mm256_load_si256
#define _mm_and(a, b) _mm256_and_si256(a, b)
#define _mm_cmpeq(a, b) _mm256_cmpeq_epi8(a, b)
#define _mm_testinz(v) (!_mm256_testc_si256(v, y))
#elif USE_AVX
#define _mm_load _mm256_load_si256
#define _mm_and(a, b) _mm256_and_ps((__m256)a, (__m256)b)
#define _mm_cmpeq(a, b) _mm256_cmp_ps(a, b, _CMP_EQ_OQ)
#define _mm_testinz(v) (!_mm256_testc_si256(v, y))
#else
#define _mm_load _mm_load_si128
#define _mm_and(a, b) _mm_and_si128(a, b)
#define _mm_cmpeq(a, b) _mm_cmpeq_epi8(a, b)
#define _mm_testinz(v) (_mm_movemask_epi8(v) != 0xffff)
#endif
/* multi-block loop */
while (n >= BLOCK_SIZE * 4) {
a = _mm_load ((const void *)(p + BLOCK_SIZE * 0));
b = _mm_load ((const void *)(p + BLOCK_SIZE * 1));
c = _mm_load ((const void *)(p + BLOCK_SIZE * 2));
d = _mm_load ((const void *)(p + BLOCK_SIZE * 3));
a = _mm_cmpeq (a, z);
b = _mm_cmpeq (b, z);
c = _mm_cmpeq (c, z);
d = _mm_cmpeq (d, z);
u = _mm_and (a, b);
v = _mm_and (c, d);
w = _mm_and (u, v);
/* test for zeros */
if (!_mm256_testc_si256(u, w)) {
if (_mm_testinz(w)) {
return 1;
}
/* move to next block */
p += 128;
n -= 128;
p += BLOCK_SIZE * 4;
n -= BLOCK_SIZE * 4;
}
/* 32 bytes loop */
while (n >= 32) {
a = _mm256_loadu_si256 (as_m256c(p));
b = _mm256_cmpeq_epi8 (a, z);
/* single block loop */
while (n >= BLOCK_SIZE) {
a = _mm_load ((const void *)(p));
b = _mm_cmpeq (a, z);
/* test for zeros */
if (!_mm256_testc_si256(b, y)) {
if (_mm_testinz(b)) {
return 1;
}
/* move to next block */
p += 32;
n -= 32;
p += BLOCK_SIZE;
n -= BLOCK_SIZE;
}
#undef _mm_load
#undef _mm_cmpeq
#undef _mm_bitand
#undef _mm_testinz
#undef BLOCK_SIZE
#endif
/* 8 bytes loop */
while (n >= 8) {
if (*(uint64_t *)p) {

View file

@ -16,6 +16,8 @@
#include "native.h"
#if USE_SSE
static const char Digits[200] = {
'0', '0', '0', '1', '0', '2', '0', '3', '0', '4', '0', '5', '0', '6', '0', '7', '0', '8', '0', '9',
'1', '0', '1', '1', '1', '2', '1', '3', '1', '4', '1', '5', '1', '6', '1', '7', '1', '8', '1', '9',
@ -221,6 +223,8 @@ static inline int u64toa_xlarge_sse2(char *out, uint64_t val) {
return n + 16;
}
#endif
int i64toa(char *out, int64_t val) {
if (likely(val >= 0)) {
return u64toa(out, (uint64_t)val);
@ -230,6 +234,8 @@ int i64toa(char *out, int64_t val) {
}
}
#if USE_SSE
int u64toa(char *out, uint64_t val) {
if (likely(val < 10000)) {
return u32toa_small(out, (uint32_t)val);
@ -241,3 +247,29 @@ int u64toa(char *out, uint64_t val) {
return u64toa_xlarge_sse2(out, val);
}
}
#else
int u64toa(char *out, uint64_t val) {
char c;
long n = 0;
uint64_t v = val;
/* convert each digit */
while (val) {
out[n++] = v % 10 + '0';
v /= 10;
}
/* reverse the output */
for (long i = 0; i < n / 2; i++) {
c = out[i];
out[i] = out[n - i - 1];
out[n - i - 1] = c;
}
/* all done */
return n;
}
#endif

View file

@ -28,55 +28,60 @@ static const char _UnquoteTab[256] = {
['\\'] = '\\',
};
#define memcchr_p32_avx2() \
while (n >= 32) { \
u = _mm256_loadu_si256 ((const void *)s); \
v = _mm256_cmpeq_epi8 (u, b); \
_mm256_storeu_si256 ((void *)p, u); \
\
/* check for matches */ \
if ((r = _mm256_movemask_epi8(v)) != 0) { \
return s - q + _mm_tzcnt_64(r); \
} \
\
/* move to the next 32 bytes */ \
s += 32; \
p += 32; \
n -= 32; \
} \
#define memcchr_p32_sse2() \
if (n >= 16) { \
x = _mm_loadu_si128 ((const void *)s); \
y = _mm_cmpeq_epi8 (x, a); \
_mm_storeu_si128 ((void *)p, x); \
\
/* check for matches */ \
if ((r = _mm_movemask_epi8(y)) != 0) { \
return s - q + _mm_tzcnt_64(r); \
} \
\
/* move to the next 16 bytes */ \
s += 16; \
p += 16; \
n -= 16; \
}
static inline ssize_t memcchr_p32(const char *s, ssize_t nb, char *p) {
int32_t r;
__m128i x;
__m128i y;
__m256i u;
__m256i v;
__m128i a = _mm_set1_epi8('\\');
__m256i b = _mm256_set1_epi8('\\');
int64_t r;
ssize_t n = nb;
const char * q = s;
/* scan & copy with SIMD */
memcchr_p32_avx2();
#if USE_AVX2
__m256i u;
__m256i v;
__m256i b = _mm256_set1_epi8('\\');
/* process every 32 bytes */
while (n >= 32) {
u = _mm256_loadu_si256 ((const void *)s);
v = _mm256_cmpeq_epi8 (u, b);
_mm256_storeu_si256 ((void *)p, u);
/* check for matches */
if ((r = _mm256_movemask_epi8(v)) != 0) {
return s - q + __builtin_ctzll(r | (1ull << 32));
}
/* move to the next 32 bytes */
s += 32;
p += 32;
n -= 32;
}
#endif
#if USE_AVX2
_mm256_zeroupper();
memcchr_p32_sse2();
#endif
#if USE_SSE
__m128i x;
__m128i y;
__m128i a = _mm_set1_epi8('\\');
/* process every 16 bytes */
while (n >= 16) {
x = _mm_loadu_si128 ((const void *)s);
y = _mm_cmpeq_epi8 (x, a);
_mm_storeu_si128 ((void *)p, x);
/* check for matches */
if ((r = _mm_movemask_epi8(y)) != 0) {
return s - q + __builtin_ctzll(r | (1 << 16));
}
/* move to the next 16 bytes */
s += 16;
p += 16;
n -= 16;
}
#endif
/* remaining bytes, do with scalar code */
while (n--) {
@ -91,9 +96,6 @@ static inline ssize_t memcchr_p32(const char *s, ssize_t nb, char *p) {
return -1;
}
#undef memcchr_p32_avx2
#undef memcchr_p32_sse2
#define ALL_01h (~0ul / 255)
#define ALL_7fh (ALL_01h * 127)
#define ALL_80h (ALL_01h * 128)

@ -1 +1 @@
Subproject commit 75fa4e6f2ee3ee4049724fe2a3806fbf119d0667
Subproject commit 38a813682862252de3d1a016c90755467bff0ee9