mirror of
https://github.com/ii64/sonic.git
synced 2026-06-21 00:46:43 +08:00
opt: skip number in json.Number parsing (#209)
* opt: skip number in json.Number parsing * fix: generic use skip_number * test: add json.Number decoding benchmarks Co-authored-by: liuqiang <liuqiang.06@bytedance.com> Co-authored-by: duanyi.aster <duanyi.aster@bytedance.com>
This commit is contained in:
parent
fe2497d01e
commit
57989f38ba
22 changed files with 1570 additions and 1153 deletions
|
|
@ -581,15 +581,6 @@ func (self *_Assembler) check_err() {
|
||||||
self.Sjmp("JS" , _LB_parsing_error_v) // JNE _parsing_error_v
|
self.Sjmp("JS" , _LB_parsing_error_v) // JNE _parsing_error_v
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *_Assembler) check_err_num() {
|
|
||||||
self.Emit("MOVQ" , _VAR_st_Vt, _AX) // MOVQ st.Vt, AX
|
|
||||||
self.Emit("TESTQ", _AX, _AX) // CMPQ AX, ${native.V_STRING}
|
|
||||||
self.Sjmp("JNS" , "check_err_end_{n}")
|
|
||||||
self.Emit("CMPQ" , _AX, jit.Imm(-int64(types.ERR_FLOAT_INFINITY)))
|
|
||||||
self.Sjmp("JNE" , _LB_parsing_error_v)
|
|
||||||
self.Link("check_err_end_{n}")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *_Assembler) check_eof(d int64) {
|
func (self *_Assembler) check_eof(d int64) {
|
||||||
if d == 1 {
|
if d == 1 {
|
||||||
self.Emit("CMPQ", _IC, _IL) // CMPQ IC, IL
|
self.Emit("CMPQ", _IC, _IL) // CMPQ IC, IL
|
||||||
|
|
@ -942,6 +933,7 @@ func (self *_Assembler) mapassign_utext(t reflect.Type, addressable bool) {
|
||||||
|
|
||||||
var (
|
var (
|
||||||
_F_skip_one = jit.Imm(int64(native.S_skip_one))
|
_F_skip_one = jit.Imm(int64(native.S_skip_one))
|
||||||
|
_F_skip_number = jit.Imm(int64(native.S_skip_number))
|
||||||
)
|
)
|
||||||
|
|
||||||
func (self *_Assembler) unmarshal_json(t reflect.Type, deref bool) {
|
func (self *_Assembler) unmarshal_json(t reflect.Type, deref bool) {
|
||||||
|
|
@ -1176,13 +1168,21 @@ func (self *_Assembler) _asm_OP_bool(_ *_Instr) {
|
||||||
func (self *_Assembler) _asm_OP_num(_ *_Instr) {
|
func (self *_Assembler) _asm_OP_num(_ *_Instr) {
|
||||||
self.Emit("MOVQ", jit.Imm(0), _VAR_fl)
|
self.Emit("MOVQ", jit.Imm(0), _VAR_fl)
|
||||||
self.Emit("CMPB", jit.Sib(_IP, _IC, 1, 0), jit.Imm('"'))
|
self.Emit("CMPB", jit.Sib(_IP, _IC, 1, 0), jit.Imm('"'))
|
||||||
self.Sjmp("JNE", "_parse_number_{n}")
|
self.Sjmp("JNE", "_skip_number_{n}")
|
||||||
self.Emit("MOVQ", jit.Imm(1), _VAR_fl)
|
self.Emit("MOVQ", jit.Imm(1), _VAR_fl)
|
||||||
self.Emit("ADDQ", jit.Imm(1), _IC)
|
self.Emit("ADDQ", jit.Imm(1), _IC)
|
||||||
self.Link("_parse_number_{n}")
|
self.Link("_skip_number_{n}")
|
||||||
self.call_vf(_F_vnumber) // call vnumber
|
|
||||||
self.check_err_num()
|
/* call skip_number */
|
||||||
self.slice_from(_VAR_st_Ep, 0) // SLICE st.Ep, $0
|
self.Emit("LEAQ", _ARG_s, _DI) // LEAQ s<>+0(FP), DI
|
||||||
|
self.Emit("MOVQ", _IC, _ARG_ic) // MOVQ IC, ic<>+16(FP)
|
||||||
|
self.Emit("LEAQ", _ARG_ic, _SI) // LEAQ ic<>+16(FP), SI
|
||||||
|
self.call(_F_skip_number) // CALL _F_skip_number
|
||||||
|
self.Emit("MOVQ", _ARG_ic, _IC) // MOVQ ic<>+16(FP), IC
|
||||||
|
self.Emit("TESTQ", _AX, _AX) // TESTQ AX, AX
|
||||||
|
self.Sjmp("JS" , _LB_parsing_error_v) // JS _parse_error_v
|
||||||
|
|
||||||
|
self.slice_from_r(_AX, 0)
|
||||||
self.Emit("BTQ", jit.Imm(_F_copy_string), _ARG_fv)
|
self.Emit("BTQ", jit.Imm(_F_copy_string), _ARG_fv)
|
||||||
self.Sjmp("JNC", "_num_write_{n}")
|
self.Sjmp("JNC", "_num_write_{n}")
|
||||||
self.Byte(0x4c, 0x8d, 0x0d) // LEAQ (PC), R9
|
self.Byte(0x4c, 0x8d, 0x0d) // LEAQ (PC), R9
|
||||||
|
|
|
||||||
|
|
@ -591,15 +591,6 @@ func (self *_Assembler) check_err() {
|
||||||
self.Sjmp("JS" , _LB_parsing_error_v) // JNE _parsing_error_v
|
self.Sjmp("JS" , _LB_parsing_error_v) // JNE _parsing_error_v
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *_Assembler) check_err_num() {
|
|
||||||
self.Emit("MOVQ" , _VAR_st_Vt, _AX) // MOVQ st.Vt, AX
|
|
||||||
self.Emit("TESTQ", _AX, _AX) // CMPQ AX, ${native.V_STRING}
|
|
||||||
self.Sjmp("JNS" , "check_err_end_{n}")
|
|
||||||
self.Emit("CMPQ" , _AX, jit.Imm(-int64(types.ERR_FLOAT_INFINITY)))
|
|
||||||
self.Sjmp("JNE" , _LB_parsing_error_v)
|
|
||||||
self.Link("check_err_end_{n}")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *_Assembler) check_eof(d int64) {
|
func (self *_Assembler) check_eof(d int64) {
|
||||||
if d == 1 {
|
if d == 1 {
|
||||||
self.Emit("CMPQ", _IC, _IL) // CMPQ IC, IL
|
self.Emit("CMPQ", _IC, _IL) // CMPQ IC, IL
|
||||||
|
|
@ -943,6 +934,7 @@ func (self *_Assembler) mapassign_utext(t reflect.Type, addressable bool) {
|
||||||
|
|
||||||
var (
|
var (
|
||||||
_F_skip_one = jit.Imm(int64(native.S_skip_one))
|
_F_skip_one = jit.Imm(int64(native.S_skip_one))
|
||||||
|
_F_skip_number = jit.Imm(int64(native.S_skip_number))
|
||||||
)
|
)
|
||||||
|
|
||||||
func (self *_Assembler) unmarshal_json(t reflect.Type, deref bool) {
|
func (self *_Assembler) unmarshal_json(t reflect.Type, deref bool) {
|
||||||
|
|
@ -1173,13 +1165,21 @@ func (self *_Assembler) _asm_OP_bool(_ *_Instr) {
|
||||||
func (self *_Assembler) _asm_OP_num(_ *_Instr) {
|
func (self *_Assembler) _asm_OP_num(_ *_Instr) {
|
||||||
self.Emit("MOVQ", jit.Imm(0), _VAR_fl)
|
self.Emit("MOVQ", jit.Imm(0), _VAR_fl)
|
||||||
self.Emit("CMPB", jit.Sib(_IP, _IC, 1, 0), jit.Imm('"'))
|
self.Emit("CMPB", jit.Sib(_IP, _IC, 1, 0), jit.Imm('"'))
|
||||||
self.Sjmp("JNE", "_parse_number_{n}")
|
self.Sjmp("JNE", "_skip_number_{n}")
|
||||||
self.Emit("MOVQ", jit.Imm(1), _VAR_fl)
|
self.Emit("MOVQ", jit.Imm(1), _VAR_fl)
|
||||||
self.Emit("ADDQ", jit.Imm(1), _IC)
|
self.Emit("ADDQ", jit.Imm(1), _IC)
|
||||||
self.Link("_parse_number_{n}")
|
self.Link("_skip_number_{n}")
|
||||||
self.call_vf(_F_vnumber)
|
|
||||||
self.check_err_num()
|
/* call skip_number */
|
||||||
self.slice_from(_VAR_st_Ep, 0) // SLICE st.Ep, $0
|
self.Emit("LEAQ", _ARG_s, _DI) // LEAQ s<>+0(FP), DI
|
||||||
|
self.Emit("MOVQ", _IC, _ARG_ic) // MOVQ IC, ic<>+16(FP)
|
||||||
|
self.Emit("LEAQ", _ARG_ic, _SI) // LEAQ ic<>+16(FP), SI
|
||||||
|
self.callc(_F_skip_number) // CALL _F_skip_number
|
||||||
|
self.Emit("MOVQ", _ARG_ic, _IC) // MOVQ ic<>+16(FP), IC
|
||||||
|
self.Emit("TESTQ", _AX, _AX) // TESTQ AX, AX
|
||||||
|
self.Sjmp("JS" , _LB_parsing_error_v) // JS _parse_error_v
|
||||||
|
|
||||||
|
self.slice_from_r(_AX, 0)
|
||||||
self.Emit("BTQ", jit.Imm(_F_copy_string), _ARG_fv)
|
self.Emit("BTQ", jit.Imm(_F_copy_string), _ARG_fv)
|
||||||
self.Sjmp("JNC", "_num_write_{n}")
|
self.Sjmp("JNC", "_num_write_{n}")
|
||||||
self.Byte(0x4c, 0x8d, 0x0d) // LEAQ (PC), R9
|
self.Byte(0x4c, 0x8d, 0x0d) // LEAQ (PC), R9
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,8 @@ const (
|
||||||
_F_disable_urc
|
_F_disable_urc
|
||||||
_F_disable_unknown
|
_F_disable_unknown
|
||||||
_F_copy_string
|
_F_copy_string
|
||||||
|
|
||||||
|
_F_allow_control = 31
|
||||||
)
|
)
|
||||||
|
|
||||||
// Decoder is the decoder context object
|
// Decoder is the decoder context object
|
||||||
|
|
|
||||||
|
|
@ -266,21 +266,16 @@ func (self *_ValueDecoder) compile() {
|
||||||
self.Emit("MOVQ", _IL, _SI) // MOVQ IL, SI
|
self.Emit("MOVQ", _IL, _SI) // MOVQ IL, SI
|
||||||
self.Emit("MOVQ", _IC, _DX) // MOVQ IC, DX
|
self.Emit("MOVQ", _IC, _DX) // MOVQ IC, DX
|
||||||
self.Emit("LEAQ", _VAR_ss, _CX) // LEAQ ss, CX
|
self.Emit("LEAQ", _VAR_ss, _CX) // LEAQ ss, CX
|
||||||
self.Emit("MOVL", jit.Imm(1), _R8) // MOVL $1, R8
|
self.Emit("MOVQ", _VAR_df, _R8) // MOVQ $df, R8
|
||||||
|
self.Emit("BTSQ", jit.Imm(_F_allow_control), _R8) // ANDQ $1<<_F_allow_control, R8
|
||||||
self.call(_F_value) // CALL value
|
self.call(_F_value) // CALL value
|
||||||
self.Emit("MOVQ", _AX, _IC) // MOVQ AX, IC
|
self.Emit("MOVQ", _AX, _IC) // MOVQ AX, IC
|
||||||
|
|
||||||
/* check for errors */
|
/* check for errors */
|
||||||
self.Emit("MOVQ" , _VAR_ss_Vt, _AX) // MOVQ ss.Vt, AX
|
self.Emit("MOVQ" , _VAR_ss_Vt, _AX) // MOVQ ss.Vt, AX
|
||||||
self.Emit("TESTQ", _AX, _AX) // TESTQ AX, AX
|
self.Emit("TESTQ", _AX, _AX) // TESTQ AX, AX
|
||||||
|
self.Sjmp("JS" , "_parsing_error")
|
||||||
self.Sjmp("JZ" , "_invalid_vtype") // JZ _invalid_vtype
|
self.Sjmp("JZ" , "_invalid_vtype") // JZ _invalid_vtype
|
||||||
self.Sjmp("JNS" , "_not_sign") // JNS
|
|
||||||
self.Emit("CMPQ" , _AX, jit.Imm(-int64(types.ERR_FLOAT_INFINITY)))
|
|
||||||
self.Sjmp("JNE" , "_parsing_error")
|
|
||||||
self.Emit("BTQ" , jit.Imm(_F_use_number), _VAR_df) // BTQ _F_use_number, df
|
|
||||||
self.Sjmp("JNC" , "_parsing_error")
|
|
||||||
self.Emit("MOVQ" , jit.Imm(int64(types.V_DOUBLE)), _AX)
|
|
||||||
self.Link("_not_sign")
|
|
||||||
self.Emit("CMPQ" , _AX, _V_max) // CMPQ AX, _V_max
|
self.Emit("CMPQ" , _AX, _V_max) // CMPQ AX, _V_max
|
||||||
self.Sjmp("JA" , "_invalid_vtype") // JA _invalid_vtype
|
self.Sjmp("JA" , "_invalid_vtype") // JA _invalid_vtype
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -281,21 +281,16 @@ func (self *_ValueDecoder) compile() {
|
||||||
self.Emit("MOVQ", _IL, _SI) // MOVQ IL, SI
|
self.Emit("MOVQ", _IL, _SI) // MOVQ IL, SI
|
||||||
self.Emit("MOVQ", _IC, _DX) // MOVQ IC, DX
|
self.Emit("MOVQ", _IC, _DX) // MOVQ IC, DX
|
||||||
self.Emit("LEAQ", _VAR_ss, _CX) // LEAQ ss, CX
|
self.Emit("LEAQ", _VAR_ss, _CX) // LEAQ ss, CX
|
||||||
self.Emit("MOVL", jit.Imm(1), _R8) // MOVL $1, R8
|
self.Emit("MOVQ", _VAR_df, _R8) // MOVQ $df, R8
|
||||||
|
self.Emit("BTSQ", jit.Imm(_F_allow_control), _R8) // ANDQ $1<<_F_allow_control, R8
|
||||||
self.callc(_F_value) // CALL value
|
self.callc(_F_value) // CALL value
|
||||||
self.Emit("MOVQ", _AX, _IC) // MOVQ AX, IC
|
self.Emit("MOVQ", _AX, _IC) // MOVQ AX, IC
|
||||||
|
|
||||||
/* check for errors */
|
/* check for errors */
|
||||||
self.Emit("MOVQ" , _VAR_ss_Vt, _AX) // MOVQ ss.Vt, AX
|
self.Emit("MOVQ" , _VAR_ss_Vt, _AX) // MOVQ ss.Vt, AX
|
||||||
self.Emit("TESTQ", _AX, _AX) // TESTQ AX, AX
|
self.Emit("TESTQ", _AX, _AX) // TESTQ AX, AX
|
||||||
|
self.Sjmp("JS" , "_parsing_error")
|
||||||
self.Sjmp("JZ" , "_invalid_vtype") // JZ _invalid_vtype
|
self.Sjmp("JZ" , "_invalid_vtype") // JZ _invalid_vtype
|
||||||
self.Sjmp("JNS" , "_not_sign") // JNS
|
|
||||||
self.Emit("CMPQ" , _AX, jit.Imm(-int64(types.ERR_FLOAT_INFINITY)))
|
|
||||||
self.Sjmp("JNE" , "_parsing_error")
|
|
||||||
self.Emit("BTQ" , jit.Imm(_F_use_number), _VAR_df) // BTQ _F_use_number, df
|
|
||||||
self.Sjmp("JNC" , "_parsing_error")
|
|
||||||
self.Emit("MOVQ" , jit.Imm(int64(types.V_DOUBLE)), _AX)
|
|
||||||
self.Link("_not_sign")
|
|
||||||
self.Emit("CMPQ" , _AX, _V_max) // CMPQ AX, _V_max
|
self.Emit("CMPQ" , _AX, _V_max) // CMPQ AX, _V_max
|
||||||
self.Sjmp("JA" , "_invalid_vtype") // JA _invalid_vtype
|
self.Sjmp("JA" , "_invalid_vtype") // JA _invalid_vtype
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -104,6 +104,11 @@ func __skip_array(s *string, p *int, m *types.StateMachine) (ret int)
|
||||||
//goland:noinspection GoUnusedParameter
|
//goland:noinspection GoUnusedParameter
|
||||||
func __skip_object(s *string, p *int, m *types.StateMachine) (ret int)
|
func __skip_object(s *string, p *int, m *types.StateMachine) (ret int)
|
||||||
|
|
||||||
|
//go:nosplit
|
||||||
|
//go:noescape
|
||||||
|
//goland:noinspection GoUnusedParameter
|
||||||
|
func __skip_number(s *string, p *int) (ret int)
|
||||||
|
|
||||||
//go:nosplit
|
//go:nosplit
|
||||||
//go:noescape
|
//go:noescape
|
||||||
//goland:noinspection GoUnusedParameter
|
//goland:noinspection GoUnusedParameter
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -565,3 +565,11 @@ func TestNative_SkipObject(t *testing.T) {
|
||||||
__skip_object(&s, &p, &types.StateMachine{})
|
__skip_object(&s, &p, &types.StateMachine{})
|
||||||
assert.Equal(t, p, 15)
|
assert.Equal(t, p, 15)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestNative_SkipNumber(t *testing.T) {
|
||||||
|
p := 0
|
||||||
|
s := `-1.23e+12`
|
||||||
|
q := __skip_number(&s, &p)
|
||||||
|
assert.Equal(t, 9, p)
|
||||||
|
assert.Equal(t, 0, q)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,4 +42,5 @@ var (
|
||||||
S_skip_one = _subr__skip_one
|
S_skip_one = _subr__skip_one
|
||||||
S_skip_array = _subr__skip_array
|
S_skip_array = _subr__skip_array
|
||||||
S_skip_object = _subr__skip_object
|
S_skip_object = _subr__skip_object
|
||||||
|
S_skip_number = _subr__skip_number
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -15,17 +15,18 @@ var (
|
||||||
_subr__lspace = __native_entry__() + 301
|
_subr__lspace = __native_entry__() + 301
|
||||||
_subr__lzero = __native_entry__() + 13
|
_subr__lzero = __native_entry__() + 13
|
||||||
_subr__quote = __native_entry__() + 4955
|
_subr__quote = __native_entry__() + 4955
|
||||||
_subr__skip_array = __native_entry__() + 17370
|
_subr__skip_array = __native_entry__() + 17551
|
||||||
_subr__skip_object = __native_entry__() + 17407
|
_subr__skip_number = __native_entry__() + 20669
|
||||||
_subr__skip_one = __native_entry__() + 15518
|
_subr__skip_object = __native_entry__() + 17588
|
||||||
|
_subr__skip_one = __native_entry__() + 15699
|
||||||
_subr__u64toa = __native_entry__() + 3735
|
_subr__u64toa = __native_entry__() + 3735
|
||||||
_subr__unquote = __native_entry__() + 6005
|
_subr__unquote = __native_entry__() + 6005
|
||||||
_subr__validate_one = __native_entry__() + 20488
|
_subr__validate_one = __native_entry__() + 20786
|
||||||
_subr__value = __native_entry__() + 10880
|
_subr__value = __native_entry__() + 10880
|
||||||
_subr__vnumber = __native_entry__() + 13676
|
_subr__vnumber = __native_entry__() + 13857
|
||||||
_subr__vsigned = __native_entry__() + 14990
|
_subr__vsigned = __native_entry__() + 15171
|
||||||
_subr__vstring = __native_entry__() + 12641
|
_subr__vstring = __native_entry__() + 12822
|
||||||
_subr__vunsigned = __native_entry__() + 15249
|
_subr__vunsigned = __native_entry__() + 15430
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
@ -36,12 +37,13 @@ const (
|
||||||
_stack__lzero = 8
|
_stack__lzero = 8
|
||||||
_stack__quote = 80
|
_stack__quote = 80
|
||||||
_stack__skip_array = 160
|
_stack__skip_array = 160
|
||||||
|
_stack__skip_number = 96
|
||||||
_stack__skip_object = 160
|
_stack__skip_object = 160
|
||||||
_stack__skip_one = 160
|
_stack__skip_one = 160
|
||||||
_stack__u64toa = 8
|
_stack__u64toa = 8
|
||||||
_stack__unquote = 88
|
_stack__unquote = 88
|
||||||
_stack__validate_one = 160
|
_stack__validate_one = 160
|
||||||
_stack__value = 400
|
_stack__value = 416
|
||||||
_stack__vnumber = 312
|
_stack__vnumber = 312
|
||||||
_stack__vsigned = 16
|
_stack__vsigned = 16
|
||||||
_stack__vstring = 128
|
_stack__vstring = 128
|
||||||
|
|
@ -56,6 +58,7 @@ var (
|
||||||
_ = _subr__lzero
|
_ = _subr__lzero
|
||||||
_ = _subr__quote
|
_ = _subr__quote
|
||||||
_ = _subr__skip_array
|
_ = _subr__skip_array
|
||||||
|
_ = _subr__skip_number
|
||||||
_ = _subr__skip_object
|
_ = _subr__skip_object
|
||||||
_ = _subr__skip_one
|
_ = _subr__skip_one
|
||||||
_ = _subr__u64toa
|
_ = _subr__u64toa
|
||||||
|
|
@ -76,6 +79,7 @@ const (
|
||||||
_ = _stack__lzero
|
_ = _stack__lzero
|
||||||
_ = _stack__quote
|
_ = _stack__quote
|
||||||
_ = _stack__skip_array
|
_ = _stack__skip_array
|
||||||
|
_ = _stack__skip_number
|
||||||
_ = _stack__skip_object
|
_ = _stack__skip_object
|
||||||
_ = _stack__skip_one
|
_ = _stack__skip_one
|
||||||
_ = _stack__u64toa
|
_ = _stack__u64toa
|
||||||
|
|
|
||||||
|
|
@ -104,6 +104,11 @@ func __skip_array(s *string, p *int, m *types.StateMachine) (ret int)
|
||||||
//goland:noinspection GoUnusedParameter
|
//goland:noinspection GoUnusedParameter
|
||||||
func __skip_object(s *string, p *int, m *types.StateMachine) (ret int)
|
func __skip_object(s *string, p *int, m *types.StateMachine) (ret int)
|
||||||
|
|
||||||
|
//go:nosplit
|
||||||
|
//go:noescape
|
||||||
|
//goland:noinspection GoUnusedParameter
|
||||||
|
func __skip_number(s *string, p *int) (ret int)
|
||||||
|
|
||||||
//go:nosplit
|
//go:nosplit
|
||||||
//go:noescape
|
//go:noescape
|
||||||
//goland:noinspection GoUnusedParameter
|
//goland:noinspection GoUnusedParameter
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -565,3 +565,11 @@ func TestNative_SkipObject(t *testing.T) {
|
||||||
__skip_object(&s, &p, &types.StateMachine{})
|
__skip_object(&s, &p, &types.StateMachine{})
|
||||||
assert.Equal(t, p, 15)
|
assert.Equal(t, p, 15)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestNative_SkipNumber(t *testing.T) {
|
||||||
|
p := 0
|
||||||
|
s := `-1.23e+12`
|
||||||
|
q := __skip_number(&s, &p)
|
||||||
|
assert.Equal(t, 9, p)
|
||||||
|
assert.Equal(t, 0, q)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,4 +42,5 @@ var (
|
||||||
S_skip_one = _subr__skip_one
|
S_skip_one = _subr__skip_one
|
||||||
S_skip_array = _subr__skip_array
|
S_skip_array = _subr__skip_array
|
||||||
S_skip_object = _subr__skip_object
|
S_skip_object = _subr__skip_object
|
||||||
|
S_skip_number = _subr__skip_number
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -15,17 +15,18 @@ var (
|
||||||
_subr__lspace = __native_entry__() + 429
|
_subr__lspace = __native_entry__() + 429
|
||||||
_subr__lzero = __native_entry__() + 13
|
_subr__lzero = __native_entry__() + 13
|
||||||
_subr__quote = __native_entry__() + 5328
|
_subr__quote = __native_entry__() + 5328
|
||||||
_subr__skip_array = __native_entry__() + 21375
|
_subr__skip_array = __native_entry__() + 21558
|
||||||
_subr__skip_object = __native_entry__() + 21412
|
_subr__skip_number = __native_entry__() + 25206
|
||||||
_subr__skip_one = __native_entry__() + 18275
|
_subr__skip_object = __native_entry__() + 21595
|
||||||
|
_subr__skip_one = __native_entry__() + 18458
|
||||||
_subr__u64toa = __native_entry__() + 4008
|
_subr__u64toa = __native_entry__() + 4008
|
||||||
_subr__unquote = __native_entry__() + 7080
|
_subr__unquote = __native_entry__() + 7080
|
||||||
_subr__validate_one = __native_entry__() + 25023
|
_subr__validate_one = __native_entry__() + 25323
|
||||||
_subr__value = __native_entry__() + 13781
|
_subr__value = __native_entry__() + 13781
|
||||||
_subr__vnumber = __native_entry__() + 16433
|
_subr__vnumber = __native_entry__() + 16616
|
||||||
_subr__vsigned = __native_entry__() + 17747
|
_subr__vsigned = __native_entry__() + 17930
|
||||||
_subr__vstring = __native_entry__() + 15556
|
_subr__vstring = __native_entry__() + 15739
|
||||||
_subr__vunsigned = __native_entry__() + 18006
|
_subr__vunsigned = __native_entry__() + 18189
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
@ -36,12 +37,13 @@ const (
|
||||||
_stack__lzero = 8
|
_stack__lzero = 8
|
||||||
_stack__quote = 64
|
_stack__quote = 64
|
||||||
_stack__skip_array = 136
|
_stack__skip_array = 136
|
||||||
|
_stack__skip_number = 96
|
||||||
_stack__skip_object = 136
|
_stack__skip_object = 136
|
||||||
_stack__skip_one = 136
|
_stack__skip_one = 136
|
||||||
_stack__u64toa = 8
|
_stack__u64toa = 8
|
||||||
_stack__unquote = 72
|
_stack__unquote = 72
|
||||||
_stack__validate_one = 136
|
_stack__validate_one = 136
|
||||||
_stack__value = 392
|
_stack__value = 408
|
||||||
_stack__vnumber = 312
|
_stack__vnumber = 312
|
||||||
_stack__vsigned = 16
|
_stack__vsigned = 16
|
||||||
_stack__vstring = 112
|
_stack__vstring = 112
|
||||||
|
|
@ -56,6 +58,7 @@ var (
|
||||||
_ = _subr__lzero
|
_ = _subr__lzero
|
||||||
_ = _subr__quote
|
_ = _subr__quote
|
||||||
_ = _subr__skip_array
|
_ = _subr__skip_array
|
||||||
|
_ = _subr__skip_number
|
||||||
_ = _subr__skip_object
|
_ = _subr__skip_object
|
||||||
_ = _subr__skip_one
|
_ = _subr__skip_one
|
||||||
_ = _subr__u64toa
|
_ = _subr__u64toa
|
||||||
|
|
@ -76,6 +79,7 @@ const (
|
||||||
_ = _stack__lzero
|
_ = _stack__lzero
|
||||||
_ = _stack__quote
|
_ = _stack__quote
|
||||||
_ = _stack__skip_array
|
_ = _stack__skip_array
|
||||||
|
_ = _stack__skip_number
|
||||||
_ = _stack__skip_object
|
_ = _stack__skip_object
|
||||||
_ = _stack__skip_one
|
_ = _stack__skip_one
|
||||||
_ = _stack__u64toa
|
_ = _stack__u64toa
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,7 @@ var (
|
||||||
S_skip_one uintptr
|
S_skip_one uintptr
|
||||||
S_skip_array uintptr
|
S_skip_array uintptr
|
||||||
S_skip_object uintptr
|
S_skip_object uintptr
|
||||||
|
S_skip_number uintptr
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:nosplit
|
//go:nosplit
|
||||||
|
|
@ -113,6 +114,7 @@ func useAVX() {
|
||||||
S_skip_one = avx.S_skip_one
|
S_skip_one = avx.S_skip_one
|
||||||
S_skip_array = avx.S_skip_array
|
S_skip_array = avx.S_skip_array
|
||||||
S_skip_object = avx.S_skip_object
|
S_skip_object = avx.S_skip_object
|
||||||
|
S_skip_number = avx.S_skip_number
|
||||||
}
|
}
|
||||||
|
|
||||||
func useAVX2() {
|
func useAVX2() {
|
||||||
|
|
@ -130,6 +132,7 @@ func useAVX2() {
|
||||||
S_skip_one = avx2.S_skip_one
|
S_skip_one = avx2.S_skip_one
|
||||||
S_skip_array = avx2.S_skip_array
|
S_skip_array = avx2.S_skip_array
|
||||||
S_skip_object = avx2.S_skip_object
|
S_skip_object = avx2.S_skip_object
|
||||||
|
S_skip_number = avx2.S_skip_number
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|
|
||||||
|
|
@ -102,6 +102,11 @@ func __skip_array(s *string, p *int, m *types.StateMachine) (ret int)
|
||||||
//goland:noinspection GoUnusedParameter
|
//goland:noinspection GoUnusedParameter
|
||||||
func __skip_object(s *string, p *int, m *types.StateMachine) (ret int)
|
func __skip_object(s *string, p *int, m *types.StateMachine) (ret int)
|
||||||
|
|
||||||
|
//go:nosplit
|
||||||
|
//go:noescape
|
||||||
|
//goland:noinspection GoUnusedParameter
|
||||||
|
func __skip_number(s *string, p *int) (ret int)
|
||||||
|
|
||||||
//go:nosplit
|
//go:nosplit
|
||||||
//go:noescape
|
//go:noescape
|
||||||
//goland:noinspection GoUnusedParameter
|
//goland:noinspection GoUnusedParameter
|
||||||
|
|
|
||||||
|
|
@ -563,3 +563,11 @@ func TestNative_SkipObject(t *testing.T) {
|
||||||
__skip_object(&s, &p, &types.StateMachine{})
|
__skip_object(&s, &p, &types.StateMachine{})
|
||||||
assert.Equal(t, p, 15)
|
assert.Equal(t, p, 15)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestNative_SkipNumber(t *testing.T) {
|
||||||
|
p := 0
|
||||||
|
s := `-1.23e+12`
|
||||||
|
q := __skip_number(&s, &p)
|
||||||
|
assert.Equal(t, 9, p)
|
||||||
|
assert.Equal(t, 0, q)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,4 +40,5 @@ var (
|
||||||
S_skip_one = _subr__skip_one
|
S_skip_one = _subr__skip_one
|
||||||
S_skip_array = _subr__skip_array
|
S_skip_array = _subr__skip_array
|
||||||
S_skip_object = _subr__skip_object
|
S_skip_object = _subr__skip_object
|
||||||
|
S_skip_number = _subr__skip_number
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ import (
|
||||||
var issue_19x_idata = "\"" + strings.Repeat("9", 1000) + "\""
|
var issue_19x_idata = "\"" + strings.Repeat("9", 1000) + "\""
|
||||||
var issue_19x_fdata = "\"" + strings.Repeat("9", 100) + "." + strings.Repeat("9", 1000) + "\""
|
var issue_19x_fdata = "\"" + strings.Repeat("9", 100) + "." + strings.Repeat("9", 1000) + "\""
|
||||||
var issue_19x_ndata = strings.Repeat("9", 1000)
|
var issue_19x_ndata = strings.Repeat("9", 1000)
|
||||||
|
var issue_19x_invalid = strings.Repeat("9", 100) + "abc99"
|
||||||
|
|
||||||
func TestDecodeLongStringToJsonNumber(t *testing.T) {
|
func TestDecodeLongStringToJsonNumber(t *testing.T) {
|
||||||
var objs, obje json.Number
|
var objs, obje json.Number
|
||||||
|
|
@ -45,6 +46,13 @@ func TestDecodeLongStringToJsonNumber(t *testing.T) {
|
||||||
require.Equal(t, erre, errs)
|
require.Equal(t, erre, errs)
|
||||||
require.Equal(t, fobje, fobjs)
|
require.Equal(t, fobje, fobjs)
|
||||||
|
|
||||||
|
var objs2, obje2 json.Number
|
||||||
|
errs = sonic.UnmarshalString(issue_19x_invalid, &objs2)
|
||||||
|
erre = json.Unmarshal([]byte(issue_19x_invalid), &obje2)
|
||||||
|
require.NotNil(t, erre)
|
||||||
|
require.NotNil(t, errs)
|
||||||
|
|
||||||
|
|
||||||
var iobjs, iobje interface{}
|
var iobjs, iobje interface{}
|
||||||
dc := decoder.NewDecoder(issue_19x_ndata)
|
dc := decoder.NewDecoder(issue_19x_ndata)
|
||||||
dc.UseNumber()
|
dc.UseNumber()
|
||||||
|
|
@ -54,4 +62,37 @@ func TestDecodeLongStringToJsonNumber(t *testing.T) {
|
||||||
erre = r.Decode(&iobje)
|
erre = r.Decode(&iobje)
|
||||||
require.Equal(t, erre, errs)
|
require.Equal(t, erre, errs)
|
||||||
require.Equal(t, iobje, iobjs)
|
require.Equal(t, iobje, iobjs)
|
||||||
|
|
||||||
|
var iobjs2, iobje2 interface{}
|
||||||
|
dc = decoder.NewDecoder(issue_19x_invalid)
|
||||||
|
dc.UseNumber()
|
||||||
|
errs = dc.Decode(&iobjs2)
|
||||||
|
r = json.NewDecoder(bytes.NewBufferString(issue_19x_invalid))
|
||||||
|
r.UseNumber()
|
||||||
|
erre = r.Decode(&iobje2)
|
||||||
|
require.Equal(t, erre, errs)
|
||||||
|
require.Equal(t, iobje2, iobjs2)
|
||||||
|
// spew.Dump(iobje2)
|
||||||
|
}
|
||||||
|
|
||||||
|
var jsonNumberBig = "\"" + strings.Repeat("9", 10) + "." + strings.Repeat("9", 100) + "\""
|
||||||
|
|
||||||
|
func BenchmarkDecodeJsonNumber_Sonic(b *testing.B) {
|
||||||
|
b.SetBytes(int64(len(jsonNumberBig)))
|
||||||
|
b.ResetTimer()
|
||||||
|
for i:=0; i<b.N; i++ {
|
||||||
|
var obj json.Number
|
||||||
|
_ = sonic.UnmarshalString(jsonNumberBig, &obj)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkDecodeUseNumber_Sonic(b *testing.B) {
|
||||||
|
b.SetBytes(int64(len(jsonNumberBig)))
|
||||||
|
b.ResetTimer()
|
||||||
|
for i:=0; i<b.N; i++ {
|
||||||
|
var obj interface{}
|
||||||
|
dc := decoder.NewDecoder(jsonNumberBig)
|
||||||
|
dc.UseNumber()
|
||||||
|
_ = dc.Decode(&obj)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -108,7 +108,7 @@ ssize_t quote(const char *sp, ssize_t nb, char *dp, ssize_t *dn, uint64_t flags)
|
||||||
ssize_t unquote(const char *sp, ssize_t nb, char *dp, ssize_t *ep, uint64_t flags);
|
ssize_t unquote(const char *sp, ssize_t nb, char *dp, ssize_t *ep, uint64_t flags);
|
||||||
ssize_t html_escape(const char *sp, ssize_t nb, char *dp, ssize_t *dn);
|
ssize_t html_escape(const char *sp, ssize_t nb, char *dp, ssize_t *dn);
|
||||||
|
|
||||||
long value(const char *s, size_t n, long p, JsonState *ret, int allow_control);
|
long value(const char *s, size_t n, long p, JsonState *ret, uint64_t flags);
|
||||||
void vstring(const GoString *src, long *p, JsonState *ret);
|
void vstring(const GoString *src, long *p, JsonState *ret);
|
||||||
void vnumber(const GoString *src, long *p, JsonState *ret);
|
void vnumber(const GoString *src, long *p, JsonState *ret);
|
||||||
void vsigned(const GoString *src, long *p, JsonState *ret);
|
void vsigned(const GoString *src, long *p, JsonState *ret);
|
||||||
|
|
@ -121,6 +121,7 @@ long skip_object(const GoString *src, long *p, StateMachine *m);
|
||||||
long skip_string(const GoString *src, long *p);
|
long skip_string(const GoString *src, long *p);
|
||||||
long skip_negative(const GoString *src, long *p);
|
long skip_negative(const GoString *src, long *p);
|
||||||
long skip_positive(const GoString *src, long *p);
|
long skip_positive(const GoString *src, long *p);
|
||||||
|
long skip_number(const GoString *src, long *p);
|
||||||
|
|
||||||
bool atof_eisel_lemire64(uint64_t mant, int exp10, int sgn, double *val);
|
bool atof_eisel_lemire64(uint64_t mant, int exp10, int sgn, double *val);
|
||||||
double atof_native(const char *sp, ssize_t nb, char* dbuf, ssize_t cap);
|
double atof_native(const char *sp, ssize_t nb, char* dbuf, ssize_t cap);
|
||||||
|
|
|
||||||
|
|
@ -51,8 +51,20 @@ static inline char isspace(char ch) {
|
||||||
return ch == ' ' || ch == '\r' || ch == '\n' | ch == '\t';
|
return ch == ' ' || ch == '\r' || ch == '\n' | ch == '\t';
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void vdigits(const GoString *src, long *p, JsonState *ret) {
|
const int MASK_USE_NUMBER = 1<<1;
|
||||||
|
|
||||||
|
static inline void vdigits(const GoString *src, long *p, JsonState *ret, uint64_t flag) {
|
||||||
--*p;
|
--*p;
|
||||||
|
if (flag & MASK_USE_NUMBER) {
|
||||||
|
long i = skip_number(src, p);
|
||||||
|
if (i < 0) {
|
||||||
|
ret->vt = i;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ret->vt = V_DOUBLE;
|
||||||
|
ret->ep = i;
|
||||||
|
return;
|
||||||
|
}
|
||||||
vnumber(src, p, ret);
|
vnumber(src, p, ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -572,9 +584,12 @@ static inline ssize_t advance_validate_string(const GoString *src, long p, int64
|
||||||
|
|
||||||
/** Value Scanning Routines **/
|
/** Value Scanning Routines **/
|
||||||
|
|
||||||
long value(const char *s, size_t n, long p, JsonState *ret, int allow_control) {
|
const uint64_t MASK_ALLOW_CONTROL = 1ul<<31;
|
||||||
|
|
||||||
|
long value(const char *s, size_t n, long p, JsonState *ret, uint64_t flags) {
|
||||||
long q = p;
|
long q = p;
|
||||||
GoString m = {.buf = s, .len = n};
|
GoString m = {.buf = s, .len = n};
|
||||||
|
bool allow_control = (flags&MASK_ALLOW_CONTROL) != 0;
|
||||||
|
|
||||||
/* parse the next identifier, q is UNSAFE, may cause out-of-bounds accessing */
|
/* parse the next identifier, q is UNSAFE, may cause out-of-bounds accessing */
|
||||||
switch (advance_ns(&m, &q)) {
|
switch (advance_ns(&m, &q)) {
|
||||||
|
|
@ -588,7 +603,7 @@ long value(const char *s, size_t n, long p, JsonState *ret, int allow_control) {
|
||||||
case '6' : /* fallthrough */
|
case '6' : /* fallthrough */
|
||||||
case '7' : /* fallthrough */
|
case '7' : /* fallthrough */
|
||||||
case '8' : /* fallthrough */
|
case '8' : /* fallthrough */
|
||||||
case '9' : vdigits(&m, &q, ret) ; return q;
|
case '9' : vdigits(&m, &q, ret, flags) ; return q;
|
||||||
case '"' : vstring(&m, &q, ret) ; return q;
|
case '"' : vstring(&m, &q, ret) ; return q;
|
||||||
case 'n' : ret->vt = advance_dword(&m, &q, 1, V_NULL, VS_NULL) ; return q;
|
case 'n' : ret->vt = advance_dword(&m, &q, 1, V_NULL, VS_NULL) ; return q;
|
||||||
case 't' : ret->vt = advance_dword(&m, &q, 1, V_TRUE, VS_TRUE) ; return q;
|
case 't' : ret->vt = advance_dword(&m, &q, 1, V_TRUE, VS_TRUE) ; return q;
|
||||||
|
|
@ -1135,7 +1150,7 @@ static inline long fsm_exec(StateMachine *self, const GoString *src, long *p, in
|
||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline long skip_number(const char *sp, size_t nb) {
|
static inline long do_skip_number(const char *sp, size_t nb) {
|
||||||
long di = -1;
|
long di = -1;
|
||||||
long ei = -1;
|
long ei = -1;
|
||||||
long si = -1;
|
long si = -1;
|
||||||
|
|
@ -1380,7 +1395,7 @@ long validate_string(const GoString *src, long *p) {
|
||||||
|
|
||||||
long skip_negative(const GoString *src, long *p) {
|
long skip_negative(const GoString *src, long *p) {
|
||||||
long i = *p;
|
long i = *p;
|
||||||
long r = skip_number(src->buf + i, src->len - i);
|
long r = do_skip_number(src->buf + i, src->len - i);
|
||||||
|
|
||||||
/* check for errors */
|
/* check for errors */
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
|
|
@ -1395,7 +1410,7 @@ long skip_negative(const GoString *src, long *p) {
|
||||||
|
|
||||||
long skip_positive(const GoString *src, long *p) {
|
long skip_positive(const GoString *src, long *p) {
|
||||||
long i = *p - 1;
|
long i = *p - 1;
|
||||||
long r = skip_number(src->buf + i, src->len - i);
|
long r = do_skip_number(src->buf + i, src->len - i);
|
||||||
|
|
||||||
/* check for errors */
|
/* check for errors */
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
|
|
@ -1408,6 +1423,35 @@ long skip_positive(const GoString *src, long *p) {
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
long skip_number(const GoString *src, long *p) {
|
||||||
|
const char* ss = src->buf;
|
||||||
|
const char* sp = src->buf + *p;
|
||||||
|
size_t nb = src->len;
|
||||||
|
long i = *p;
|
||||||
|
long r;
|
||||||
|
bool neg = *sp == '-';
|
||||||
|
|
||||||
|
sp += neg;
|
||||||
|
nb -= neg;
|
||||||
|
if (unlikely(nb <= 0)) {
|
||||||
|
*p = sp - ss;
|
||||||
|
return -ERR_EOF;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unlikely(i < nb && (*sp > '9' || *sp < '0'))) {
|
||||||
|
*p = sp - ss;
|
||||||
|
return -ERR_INVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = do_skip_number(sp, nb);
|
||||||
|
if (unlikely(r < 0)) {
|
||||||
|
*p = sp - (r + 1) - ss;
|
||||||
|
return -ERR_INVAL;
|
||||||
|
}
|
||||||
|
*p = sp + r - ss;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
long validate_one(const GoString *src, long *p, StateMachine *m) {
|
long validate_one(const GoString *src, long *p, StateMachine *m) {
|
||||||
fsm_init(m, FSM_VAL);
|
fsm_init(m, FSM_VAL);
|
||||||
return fsm_exec(m, src, p, VALID_FULL);
|
return fsm_exec(m, src, p, VALID_FULL);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue