//go:build go1.17 && !go1.21 // +build go1.17,!go1.21 /* * Copyright 2021 ByteDance Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package decoder import ( `encoding/json` `fmt` `reflect` `strconv` `github.com/bytedance/sonic/internal/jit` `github.com/bytedance/sonic/internal/native` `github.com/bytedance/sonic/internal/native/types` `github.com/twitchyliquid64/golang-asm/obj` `github.com/twitchyliquid64/golang-asm/obj/x86` ) /** Crucial Registers: * * ST(R13) && 0(SP) : ro, decoder stack * DF(AX) : ro, decoder flags * EP(BX) : wo, error pointer * IP(R10) : ro, input pointer * IL(R12) : ro, input length * IC(R11) : rw, input cursor * VP(R15) : ro, value pointer (to an interface{}) */ const ( _VD_args = 8 // 8 bytes for passing arguments to this functions _VD_fargs = 64 // 64 bytes for passing arguments to other Go functions _VD_saves = 48 // 48 bytes for saving the registers before CALL instructions _VD_locals = 96 // 96 bytes for local variables ) const ( _VD_offs = _VD_fargs + _VD_saves + _VD_locals _VD_size = _VD_offs + 8 // 8 bytes for the parent frame pointer ) var ( _VAR_ss = _VAR_ss_Vt _VAR_df = jit.Ptr(_SP, _VD_fargs + _VD_saves) ) var ( _VAR_ss_Vt = jit.Ptr(_SP, _VD_fargs + _VD_saves + 8) _VAR_ss_Dv = jit.Ptr(_SP, _VD_fargs + _VD_saves + 16) _VAR_ss_Iv = jit.Ptr(_SP, _VD_fargs + _VD_saves + 24) _VAR_ss_Ep = jit.Ptr(_SP, _VD_fargs + _VD_saves + 32) _VAR_ss_Db = jit.Ptr(_SP, _VD_fargs + _VD_saves + 40) _VAR_ss_Dc = jit.Ptr(_SP, _VD_fargs + _VD_saves + 48) ) var ( _VAR_R9 = jit.Ptr(_SP, _VD_fargs + _VD_saves + 56) ) type _ValueDecoder struct { jit.BaseAssembler } var ( _VAR_cs_LR = jit.Ptr(_SP, _VD_fargs + _VD_saves + 64) _VAR_cs_p = jit.Ptr(_SP, _VD_fargs + _VD_saves + 72) _VAR_cs_n = jit.Ptr(_SP, _VD_fargs + _VD_saves + 80) _VAR_cs_d = jit.Ptr(_SP, _VD_fargs + _VD_saves + 88) ) func (self *_ValueDecoder) build() uintptr { self.Init(self.compile) return *(*uintptr)(self.Load("decode_value", _VD_size, _VD_args, argPtrs_generic, localPtrs_generic)) } /** Function Calling Helpers **/ func (self *_ValueDecoder) save(r ...obj.Addr) { for i, v := range r { if i > _VD_saves / 8 - 1 { panic("too many registers to save") } else { self.Emit("MOVQ", v, jit.Ptr(_SP, _VD_fargs + int64(i) * 8)) } } } func (self *_ValueDecoder) load(r ...obj.Addr) { for i, v := range r { if i > _VD_saves / 8 - 1 { panic("too many registers to load") } else { self.Emit("MOVQ", jit.Ptr(_SP, _VD_fargs + int64(i) * 8), v) } } } func (self *_ValueDecoder) call(fn obj.Addr) { self.Emit("MOVQ", fn, _R9) // MOVQ ${fn}, AX self.Rjmp("CALL", _R9) // CALL AX } func (self *_ValueDecoder) call_go(fn obj.Addr) { self.save(_REG_go...) // SAVE $REG_go self.call(fn) // CALL ${fn} self.load(_REG_go...) // LOAD $REG_go } func (self *_ValueDecoder) callc(fn obj.Addr) { self.Emit("XCHGQ", _IP, _BP) self.call(fn) self.Emit("XCHGQ", _IP, _BP) } func (self *_ValueDecoder) call_c(fn obj.Addr) { self.Emit("XCHGQ", _IC, _BX) self.callc(fn) self.Emit("XCHGQ", _IC, _BX) } /** Decoder Assembler **/ const ( _S_val = iota + 1 _S_arr _S_arr_0 _S_obj _S_obj_0 _S_obj_delim _S_obj_sep ) const ( _S_omask_key = (1 << _S_obj_0) | (1 << _S_obj_sep) _S_omask_end = (1 << _S_obj_0) | (1 << _S_obj) _S_vmask = (1 << _S_val) | (1 << _S_arr_0) ) const ( _A_init_len = 1 _A_init_cap = 16 ) const ( _ST_Sp = 0 _ST_Vt = _PtrBytes _ST_Vp = _PtrBytes * (types.MAX_RECURSE + 1) ) var ( _V_true = jit.Imm(int64(pbool(true))) _V_false = jit.Imm(int64(pbool(false))) _F_value = jit.Imm(int64(native.S_value)) ) var ( _V_max = jit.Imm(int64(types.V_MAX)) _E_eof = jit.Imm(int64(types.ERR_EOF)) _E_invalid = jit.Imm(int64(types.ERR_INVALID_CHAR)) _E_recurse = jit.Imm(int64(types.ERR_RECURSE_EXCEED_MAX)) ) var ( _F_convTslice = jit.Func(convTslice) _F_convTstring = jit.Func(convTstring) _F_invalid_vtype = jit.Func(invalid_vtype) ) var ( _T_map = jit.Type(reflect.TypeOf((map[string]interface{})(nil))) _T_bool = jit.Type(reflect.TypeOf(false)) _T_int64 = jit.Type(reflect.TypeOf(int64(0))) _T_eface = jit.Type(reflect.TypeOf((*interface{})(nil)).Elem()) _T_slice = jit.Type(reflect.TypeOf(([]interface{})(nil))) _T_string = jit.Type(reflect.TypeOf("")) _T_number = jit.Type(reflect.TypeOf(json.Number(""))) _T_float64 = jit.Type(reflect.TypeOf(float64(0))) ) var _R_tab = map[int]string { '[': "_decode_V_ARRAY", '{': "_decode_V_OBJECT", ':': "_decode_V_KEY_SEP", ',': "_decode_V_ELEM_SEP", ']': "_decode_V_ARRAY_END", '}': "_decode_V_OBJECT_END", } func (self *_ValueDecoder) compile() { self.Emit("SUBQ", jit.Imm(_VD_size), _SP) // SUBQ $_VD_size, SP self.Emit("MOVQ", _BP, jit.Ptr(_SP, _VD_offs)) // MOVQ BP, _VD_offs(SP) self.Emit("LEAQ", jit.Ptr(_SP, _VD_offs), _BP) // LEAQ _VD_offs(SP), BP /* initialize the state machine */ self.Emit("XORL", _CX, _CX) // XORL CX, CX self.Emit("MOVQ", _DF, _VAR_df) // MOVQ DF, df /* initialize digital buffer first */ self.Emit("MOVQ", jit.Imm(_MaxDigitNums), _VAR_ss_Dc) // MOVQ $_MaxDigitNums, ss.Dcap self.Emit("LEAQ", jit.Ptr(_ST, _DbufOffset), _AX) // LEAQ _DbufOffset(ST), AX self.Emit("MOVQ", _AX, _VAR_ss_Db) // MOVQ AX, ss.Dbuf /* add ST offset */ self.Emit("ADDQ", jit.Imm(_FsmOffset), _ST) // ADDQ _FsmOffset, _ST self.Emit("MOVQ", _CX, jit.Ptr(_ST, _ST_Sp)) // MOVQ CX, ST.Sp self.WriteRecNotAX(0, _VP, jit.Ptr(_ST, _ST_Vp), false) // MOVQ VP, ST.Vp[0] self.Emit("MOVQ", jit.Imm(_S_val), jit.Ptr(_ST, _ST_Vt)) // MOVQ _S_val, ST.Vt[0] self.Sjmp("JMP" , "_next") // JMP _next /* set the value from previous round */ self.Link("_set_value") // _set_value: self.Emit("MOVL" , jit.Imm(_S_vmask), _DX) // MOVL _S_vmask, DX self.Emit("MOVQ" , jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX self.Emit("MOVQ" , jit.Sib(_ST, _CX, 8, _ST_Vt), _AX) // MOVQ ST.Vt[CX], AX self.Emit("BTQ" , _AX, _DX) // BTQ AX, DX self.Sjmp("JNC" , "_vtype_error") // JNC _vtype_error self.Emit("XORL" , _SI, _SI) // XORL SI, SI self.Emit("SUBQ" , jit.Imm(1), jit.Ptr(_ST, _ST_Sp)) // SUBQ $1, ST.Sp self.Emit("XCHGQ", jit.Sib(_ST, _CX, 8, _ST_Vp), _SI) // XCHGQ ST.Vp[CX], SI self.Emit("MOVQ" , _R8, jit.Ptr(_SI, 0)) // MOVQ R8, (SI) self.WriteRecNotAX(1, _R9, jit.Ptr(_SI, 8), false) // MOVQ R9, 8(SI) /* check for value stack */ self.Link("_next") // _next: self.Emit("MOVQ" , jit.Ptr(_ST, _ST_Sp), _AX) // MOVQ ST.Sp, AX self.Emit("TESTQ", _AX, _AX) // TESTQ AX, AX self.Sjmp("JS" , "_return") // JS _return /* fast path: test up to 4 characters manually */ self.Emit("CMPQ" , _IC, _IL) // CMPQ IC, IL self.Sjmp("JAE" , "_decode_V_EOF") // JAE _decode_V_EOF self.Emit("MOVBQZX", jit.Sib(_IP, _IC, 1, 0), _AX) // MOVBQZX (IP)(IC), AX self.Emit("MOVQ" , jit.Imm(_BM_space), _DX) // MOVQ _BM_space, DX self.Emit("CMPQ" , _AX, jit.Imm(' ')) // CMPQ AX, $' ' self.Sjmp("JA" , "_decode_fast") // JA _decode_fast self.Emit("BTQ" , _AX, _DX) // BTQ _AX, _DX self.Sjmp("JNC" , "_decode_fast") // JNC _decode_fast self.Emit("ADDQ" , jit.Imm(1), _IC) // ADDQ $1, IC /* at least 1 to 3 spaces */ for i := 0; i < 3; i++ { self.Emit("CMPQ" , _IC, _IL) // CMPQ IC, IL self.Sjmp("JAE" , "_decode_V_EOF") // JAE _decode_V_EOF self.Emit("MOVBQZX", jit.Sib(_IP, _IC, 1, 0), _AX) // MOVBQZX (IP)(IC), AX self.Emit("CMPQ" , _AX, jit.Imm(' ')) // CMPQ AX, $' ' self.Sjmp("JA" , "_decode_fast") // JA _decode_fast self.Emit("BTQ" , _AX, _DX) // BTQ _AX, _DX self.Sjmp("JNC" , "_decode_fast") // JNC _decode_fast self.Emit("ADDQ" , jit.Imm(1), _IC) // ADDQ $1, IC } /* at least 4 spaces */ self.Emit("CMPQ" , _IC, _IL) // CMPQ IC, IL self.Sjmp("JAE" , "_decode_V_EOF") // JAE _decode_V_EOF self.Emit("MOVBQZX", jit.Sib(_IP, _IC, 1, 0), _AX) // MOVBQZX (IP)(IC), AX /* fast path: use lookup table to select decoder */ self.Link("_decode_fast") // _decode_fast: self.Byte(0x48, 0x8d, 0x3d) // LEAQ ?(PC), DI self.Sref("_decode_tab", 4) // .... &_decode_tab self.Emit("MOVLQSX", jit.Sib(_DI, _AX, 4, 0), _AX) // MOVLQSX (DI)(AX*4), AX self.Emit("TESTQ" , _AX, _AX) // TESTQ AX, AX self.Sjmp("JZ" , "_decode_native") // JZ _decode_native self.Emit("ADDQ" , jit.Imm(1), _IC) // ADDQ $1, IC self.Emit("ADDQ" , _DI, _AX) // ADDQ DI, AX self.Rjmp("JMP" , _AX) // JMP AX /* decode with native decoder */ self.Link("_decode_native") // _decode_native: self.Emit("MOVQ", _IP, _DI) // MOVQ IP, DI self.Emit("MOVQ", _IL, _SI) // MOVQ IL, SI self.Emit("MOVQ", _IC, _DX) // MOVQ IC, DX self.Emit("LEAQ", _VAR_ss, _CX) // LEAQ ss, CX self.Emit("MOVQ", _VAR_df, _R8) // MOVQ $df, R8 self.Emit("BTSQ", jit.Imm(_F_allow_control), _R8) // ANDQ $1<<_F_allow_control, R8 self.callc(_F_value) // CALL value self.Emit("MOVQ", _AX, _IC) // MOVQ AX, IC /* check for errors */ self.Emit("MOVQ" , _VAR_ss_Vt, _AX) // MOVQ ss.Vt, AX self.Emit("TESTQ", _AX, _AX) // TESTQ AX, AX self.Sjmp("JS" , "_parsing_error") self.Sjmp("JZ" , "_invalid_vtype") // JZ _invalid_vtype self.Emit("CMPQ" , _AX, _V_max) // CMPQ AX, _V_max self.Sjmp("JA" , "_invalid_vtype") // JA _invalid_vtype /* jump table selector */ self.Byte(0x48, 0x8d, 0x3d) // LEAQ ?(PC), DI self.Sref("_switch_table", 4) // .... &_switch_table self.Emit("MOVLQSX", jit.Sib(_DI, _AX, 4, -4), _AX) // MOVLQSX -4(DI)(AX*4), AX self.Emit("ADDQ" , _DI, _AX) // ADDQ DI, AX self.Rjmp("JMP" , _AX) // JMP AX /** V_EOF **/ self.Link("_decode_V_EOF") // _decode_V_EOF: self.Emit("MOVL", _E_eof, _EP) // MOVL _E_eof, EP self.Sjmp("JMP" , "_error") // JMP _error /** V_NULL **/ self.Link("_decode_V_NULL") // _decode_V_NULL: self.Emit("XORL", _R8, _R8) // XORL R8, R8 self.Emit("XORL", _R9, _R9) // XORL R9, R9 self.Emit("LEAQ", jit.Ptr(_IC, -4), _DI) // LEAQ -4(IC), DI self.Sjmp("JMP" , "_set_value") // JMP _set_value /** V_TRUE **/ self.Link("_decode_V_TRUE") // _decode_V_TRUE: self.Emit("MOVQ", _T_bool, _R8) // MOVQ _T_bool, R8 // TODO: maybe modified by users? self.Emit("MOVQ", _V_true, _R9) // MOVQ _V_true, R9 self.Emit("LEAQ", jit.Ptr(_IC, -4), _DI) // LEAQ -4(IC), DI self.Sjmp("JMP" , "_set_value") // JMP _set_value /** V_FALSE **/ self.Link("_decode_V_FALSE") // _decode_V_FALSE: self.Emit("MOVQ", _T_bool, _R8) // MOVQ _T_bool, R8 self.Emit("MOVQ", _V_false, _R9) // MOVQ _V_false, R9 self.Emit("LEAQ", jit.Ptr(_IC, -5), _DI) // LEAQ -5(IC), DI self.Sjmp("JMP" , "_set_value") // JMP _set_value /** V_ARRAY **/ self.Link("_decode_V_ARRAY") // _decode_V_ARRAY self.Emit("MOVL", jit.Imm(_S_vmask), _DX) // MOVL _S_vmask, DX self.Emit("MOVQ", jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX self.Emit("MOVQ", jit.Sib(_ST, _CX, 8, _ST_Vt), _AX) // MOVQ ST.Vt[CX], AX self.Emit("BTQ" , _AX, _DX) // BTQ AX, DX self.Sjmp("JNC" , "_invalid_char") // JNC _invalid_char /* create a new array */ self.Emit("MOVQ", _T_eface, _AX) // MOVQ _T_eface, AX self.Emit("MOVQ", jit.Imm(_A_init_len), _BX) // MOVQ _A_init_len, BX self.Emit("MOVQ", jit.Imm(_A_init_cap), _CX) // MOVQ _A_init_cap, CX self.call_go(_F_makeslice) // CALL_GO runtime.makeslice /* pack into an interface */ self.Emit("MOVQ", jit.Imm(_A_init_len), _BX) // MOVQ _A_init_len, BX self.Emit("MOVQ", jit.Imm(_A_init_cap), _CX) // MOVQ _A_init_cap, CX self.call_go(_F_convTslice) // CALL_GO runtime.convTslice self.Emit("MOVQ", _AX, _R8) // MOVQ AX, R8 /* replace current state with an array */ self.Emit("MOVQ", jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX self.Emit("MOVQ", jit.Sib(_ST, _CX, 8, _ST_Vp), _SI) // MOVQ ST.Vp[CX], SI self.Emit("MOVQ", jit.Imm(_S_arr), jit.Sib(_ST, _CX, 8, _ST_Vt)) // MOVQ _S_arr, ST.Vt[CX] self.Emit("MOVQ", _T_slice, _AX) // MOVQ _T_slice, AX self.Emit("MOVQ", _AX, jit.Ptr(_SI, 0)) // MOVQ AX, (SI) self.WriteRecNotAX(2, _R8, jit.Ptr(_SI, 8), false) // MOVQ R8, 8(SI) /* add a new slot for the first element */ self.Emit("ADDQ", jit.Imm(1), _CX) // ADDQ $1, CX self.Emit("CMPQ", _CX, jit.Imm(types.MAX_RECURSE)) // CMPQ CX, ${types.MAX_RECURSE} self.Sjmp("JAE" , "_stack_overflow") // JA _stack_overflow self.Emit("MOVQ", jit.Ptr(_R8, 0), _AX) // MOVQ (R8), AX self.Emit("MOVQ", _CX, jit.Ptr(_ST, _ST_Sp)) // MOVQ CX, ST.Sp self.WritePtrAX(3, jit.Sib(_ST, _CX, 8, _ST_Vp), false) // MOVQ AX, ST.Vp[CX] self.Emit("MOVQ", jit.Imm(_S_arr_0), jit.Sib(_ST, _CX, 8, _ST_Vt)) // MOVQ _S_arr_0, ST.Vt[CX] self.Sjmp("JMP" , "_next") // JMP _next /** V_OBJECT **/ self.Link("_decode_V_OBJECT") // _decode_V_OBJECT: self.Emit("MOVL", jit.Imm(_S_vmask), _DX) // MOVL _S_vmask, DX self.Emit("MOVQ", jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX self.Emit("MOVQ", jit.Sib(_ST, _CX, 8, _ST_Vt), _AX) // MOVQ ST.Vt[CX], AX self.Emit("BTQ" , _AX, _DX) // BTQ AX, DX self.Sjmp("JNC" , "_invalid_char") // JNC _invalid_char self.call_go(_F_makemap_small) // CALL_GO runtime.makemap_small self.Emit("MOVQ", jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX self.Emit("MOVQ", jit.Imm(_S_obj_0), jit.Sib(_ST, _CX, 8, _ST_Vt)) // MOVQ _S_obj_0, ST.Vt[CX] self.Emit("MOVQ", jit.Sib(_ST, _CX, 8, _ST_Vp), _SI) // MOVQ ST.Vp[CX], SI self.Emit("MOVQ", _T_map, _DX) // MOVQ _T_map, DX self.Emit("MOVQ", _DX, jit.Ptr(_SI, 0)) // MOVQ DX, (SI) self.WritePtrAX(4, jit.Ptr(_SI, 8), false) // MOVQ AX, 8(SI) self.Sjmp("JMP" , "_next") // JMP _next /** V_STRING **/ self.Link("_decode_V_STRING") // _decode_V_STRING: self.Emit("MOVQ", _VAR_ss_Iv, _CX) // MOVQ ss.Iv, CX self.Emit("MOVQ", _IC, _AX) // MOVQ IC, AX self.Emit("SUBQ", _CX, _AX) // SUBQ CX, AX /* check for escapes */ self.Emit("CMPQ", _VAR_ss_Ep, jit.Imm(-1)) // CMPQ ss.Ep, $-1 self.Sjmp("JNE" , "_unquote") // JNE _unquote self.Emit("SUBQ", jit.Imm(1), _AX) // SUBQ $1, AX self.Emit("LEAQ", jit.Sib(_IP, _CX, 1, 0), _R8) // LEAQ (IP)(CX), R8 self.Byte(0x48, 0x8d, 0x3d) // LEAQ (PC), DI self.Sref("_copy_string_end", 4) self.Emit("BTQ", jit.Imm(_F_copy_string), _VAR_df) self.Sjmp("JC", "copy_string") self.Link("_copy_string_end") self.Emit("XORL", _DX, _DX) /* strings with no escape sequences */ self.Link("_noescape") // _noescape: self.Emit("MOVL", jit.Imm(_S_omask_key), _DI) // MOVL _S_omask, DI self.Emit("MOVQ", jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX self.Emit("MOVQ", jit.Sib(_ST, _CX, 8, _ST_Vt), _SI) // MOVQ ST.Vt[CX], SI self.Emit("BTQ" , _SI, _DI) // BTQ SI, DI self.Sjmp("JC" , "_object_key") // JC _object_key /* check for pre-packed strings, avoid 1 allocation */ self.Emit("TESTQ", _DX, _DX) // TESTQ DX, DX self.Sjmp("JNZ" , "_packed_str") // JNZ _packed_str self.Emit("MOVQ" , _AX, _BX) // MOVQ AX, BX self.Emit("MOVQ" , _R8, _AX) // MOVQ R8, AX self.call_go(_F_convTstring) // CALL_GO runtime.convTstring self.Emit("MOVQ" , _AX, _R9) // MOVQ AX, R9 /* packed string already in R9 */ self.Link("_packed_str") // _packed_str: self.Emit("MOVQ", _T_string, _R8) // MOVQ _T_string, R8 self.Emit("MOVQ", _VAR_ss_Iv, _DI) // MOVQ ss.Iv, DI self.Emit("SUBQ", jit.Imm(1), _DI) // SUBQ $1, DI self.Sjmp("JMP" , "_set_value") // JMP _set_value /* the string is an object key, get the map */ self.Link("_object_key") self.Emit("MOVQ", jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX self.Emit("MOVQ", jit.Sib(_ST, _CX, 8, _ST_Vp), _SI) // MOVQ ST.Vp[CX], SI self.Emit("MOVQ", jit.Ptr(_SI, 8), _SI) // MOVQ 8(SI), SI /* add a new delimiter */ self.Emit("ADDQ", jit.Imm(1), _CX) // ADDQ $1, CX self.Emit("CMPQ", _CX, jit.Imm(types.MAX_RECURSE)) // CMPQ CX, ${types.MAX_RECURSE} self.Sjmp("JAE" , "_stack_overflow") // JA _stack_overflow self.Emit("MOVQ", _CX, jit.Ptr(_ST, _ST_Sp)) // MOVQ CX, ST.Sp self.Emit("MOVQ", jit.Imm(_S_obj_delim), jit.Sib(_ST, _CX, 8, _ST_Vt)) // MOVQ _S_obj_delim, ST.Vt[CX] /* add a new slot int the map */ self.Emit("MOVQ", _AX, _DI) // MOVQ AX, DI self.Emit("MOVQ", _T_map, _AX) // MOVQ _T_map, AX self.Emit("MOVQ", _SI, _BX) // MOVQ SI, BX self.Emit("MOVQ", _R8, _CX) // MOVQ R9, CX self.call_go(_F_mapassign_faststr) // CALL_GO runtime.mapassign_faststr /* add to the pointer stack */ self.Emit("MOVQ", jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX self.WritePtrAX(6, jit.Sib(_ST, _CX, 8, _ST_Vp), false) // MOVQ AX, ST.Vp[CX] self.Sjmp("JMP" , "_next") // JMP _next /* allocate memory to store the string header and unquoted result */ self.Link("_unquote") // _unquote: self.Emit("ADDQ", jit.Imm(15), _AX) // ADDQ $15, AX self.Emit("MOVQ", _T_byte, _BX) // MOVQ _T_byte, BX self.Emit("MOVB", jit.Imm(0), _CX) // MOVB $0, CX self.call_go(_F_mallocgc) // CALL_GO runtime.mallocgc self.Emit("MOVQ", _AX, _R9) // MOVQ AX, R9 /* prepare the unquoting parameters */ self.Emit("MOVQ" , _VAR_ss_Iv, _CX) // MOVQ ss.Iv, CX self.Emit("LEAQ" , jit.Sib(_IP, _CX, 1, 0), _DI) // LEAQ (IP)(CX), DI self.Emit("NEGQ" , _CX) // NEGQ CX self.Emit("LEAQ" , jit.Sib(_IC, _CX, 1, -1), _SI) // LEAQ -1(IC)(CX), SI self.Emit("LEAQ" , jit.Ptr(_R9, 16), _DX) // LEAQ 16(R8), DX self.Emit("LEAQ" , _VAR_ss_Ep, _CX) // LEAQ ss.Ep, CX self.Emit("XORL" , _R8, _R8) // XORL R8, R8 self.Emit("BTQ" , jit.Imm(_F_disable_urc), _VAR_df) // BTQ ${_F_disable_urc}, fv self.Emit("SETCC", _R8) // SETCC R8 self.Emit("SHLQ" , jit.Imm(types.B_UNICODE_REPLACE), _R8) // SHLQ ${types.B_UNICODE_REPLACE}, R8 /* unquote the string, with R9 been preserved */ self.Emit("MOVQ", _R9, _VAR_R9) // SAVE R9 self.call_c(_F_unquote) // CALL unquote self.Emit("MOVQ", _VAR_R9, _R9) // LOAD R9 /* check for errors */ self.Emit("TESTQ", _AX, _AX) // TESTQ AX, AX self.Sjmp("JS" , "_unquote_error") // JS _unquote_error self.Emit("MOVL" , jit.Imm(1), _DX) // MOVL $1, DX self.Emit("LEAQ" , jit.Ptr(_R9, 16), _R8) // ADDQ $16, R8 self.Emit("MOVQ" , _R8, jit.Ptr(_R9, 0)) // MOVQ R8, (R9) self.Emit("MOVQ" , _AX, jit.Ptr(_R9, 8)) // MOVQ AX, 8(R9) self.Sjmp("JMP" , "_noescape") // JMP _noescape /** V_DOUBLE **/ self.Link("_decode_V_DOUBLE") // _decode_V_DOUBLE: self.Emit("BTQ" , jit.Imm(_F_use_number), _VAR_df) // BTQ _F_use_number, df self.Sjmp("JC" , "_use_number") // JC _use_number self.Emit("MOVSD", _VAR_ss_Dv, _X0) // MOVSD ss.Dv, X0 self.Sjmp("JMP" , "_use_float64") // JMP _use_float64 /** V_INTEGER **/ self.Link("_decode_V_INTEGER") // _decode_V_INTEGER: self.Emit("BTQ" , jit.Imm(_F_use_number), _VAR_df) // BTQ _F_use_number, df self.Sjmp("JC" , "_use_number") // JC _use_number self.Emit("BTQ" , jit.Imm(_F_use_int64), _VAR_df) // BTQ _F_use_int64, df self.Sjmp("JC" , "_use_int64") // JC _use_int64 //TODO: use ss.Dv directly self.Emit("MOVSD", _VAR_ss_Dv, _X0) // MOVSD ss.Dv, X0 /* represent numbers as `float64` */ self.Link("_use_float64") // _use_float64: self.Emit("MOVQ" , _X0, _AX) // MOVQ X0, AX self.call_go(_F_convT64) // CALL_GO runtime.convT64 self.Emit("MOVQ" , _T_float64, _R8) // MOVQ _T_float64, R8 self.Emit("MOVQ" , _AX, _R9) // MOVQ AX, R9 self.Emit("MOVQ" , _VAR_ss_Ep, _DI) // MOVQ ss.Ep, DI self.Sjmp("JMP" , "_set_value") // JMP _set_value /* represent numbers as `json.Number` */ self.Link("_use_number") // _use_number self.Emit("MOVQ", _VAR_ss_Ep, _AX) // MOVQ ss.Ep, AX self.Emit("LEAQ", jit.Sib(_IP, _AX, 1, 0), _SI) // LEAQ (IP)(AX), SI self.Emit("MOVQ", _IC, _CX) // MOVQ IC, CX self.Emit("SUBQ", _AX, _CX) // SUBQ AX, CX self.Emit("MOVQ", _SI, _AX) // MOVQ SI, AX self.Emit("MOVQ", _CX, _BX) // MOVQ CX, BX self.call_go(_F_convTstring) // CALL_GO runtime.convTstring self.Emit("MOVQ", _T_number, _R8) // MOVQ _T_number, R8 self.Emit("MOVQ", _AX, _R9) // MOVQ AX, R9 self.Emit("MOVQ", _VAR_ss_Ep, _DI) // MOVQ ss.Ep, DI self.Sjmp("JMP" , "_set_value") // JMP _set_value /* represent numbers as `int64` */ self.Link("_use_int64") // _use_int64: self.Emit("MOVQ", _VAR_ss_Iv, _AX) // MOVQ ss.Iv, AX self.call_go(_F_convT64) // CALL_GO runtime.convT64 self.Emit("MOVQ", _T_int64, _R8) // MOVQ _T_int64, R8 self.Emit("MOVQ", _AX, _R9) // MOVQ AX, R9 self.Emit("MOVQ", _VAR_ss_Ep, _DI) // MOVQ ss.Ep, DI self.Sjmp("JMP" , "_set_value") // JMP _set_value /** V_KEY_SEP **/ self.Link("_decode_V_KEY_SEP") // _decode_V_KEY_SEP: self.Emit("MOVQ", jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX self.Emit("MOVQ", jit.Sib(_ST, _CX, 8, _ST_Vt), _AX) // MOVQ ST.Vt[CX], AX self.Emit("CMPQ", _AX, jit.Imm(_S_obj_delim)) // CMPQ AX, _S_obj_delim self.Sjmp("JNE" , "_invalid_char") // JNE _invalid_char self.Emit("MOVQ", jit.Imm(_S_val), jit.Sib(_ST, _CX, 8, _ST_Vt)) // MOVQ _S_val, ST.Vt[CX] self.Emit("MOVQ", jit.Imm(_S_obj), jit.Sib(_ST, _CX, 8, _ST_Vt - 8)) // MOVQ _S_obj, ST.Vt[CX - 1] self.Sjmp("JMP" , "_next") // JMP _next /** V_ELEM_SEP **/ self.Link("_decode_V_ELEM_SEP") // _decode_V_ELEM_SEP: self.Emit("MOVQ" , jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX self.Emit("MOVQ" , jit.Sib(_ST, _CX, 8, _ST_Vt), _AX) // MOVQ ST.Vt[CX], AX self.Emit("CMPQ" , _AX, jit.Imm(_S_arr)) self.Sjmp("JE" , "_array_sep") // JZ _next self.Emit("CMPQ" , _AX, jit.Imm(_S_obj)) // CMPQ _AX, _S_arr self.Sjmp("JNE" , "_invalid_char") // JNE _invalid_char self.Emit("MOVQ" , jit.Imm(_S_obj_sep), jit.Sib(_ST, _CX, 8, _ST_Vt)) self.Sjmp("JMP" , "_next") // JMP _next /* arrays */ self.Link("_array_sep") self.Emit("MOVQ", jit.Sib(_ST, _CX, 8, _ST_Vp), _SI) // MOVQ ST.Vp[CX], SI self.Emit("MOVQ", jit.Ptr(_SI, 8), _SI) // MOVQ 8(SI), SI self.Emit("MOVQ", jit.Ptr(_SI, 8), _DX) // MOVQ 8(SI), DX self.Emit("CMPQ", _DX, jit.Ptr(_SI, 16)) // CMPQ DX, 16(SI) self.Sjmp("JAE" , "_array_more") // JAE _array_more /* add a slot for the new element */ self.Link("_array_append") // _array_append: self.Emit("ADDQ", jit.Imm(1), jit.Ptr(_SI, 8)) // ADDQ $1, 8(SI) self.Emit("MOVQ", jit.Ptr(_SI, 0), _SI) // MOVQ (SI), SI self.Emit("ADDQ", jit.Imm(1), _CX) // ADDQ $1, CX self.Emit("CMPQ", _CX, jit.Imm(types.MAX_RECURSE)) // CMPQ CX, ${types.MAX_RECURSE} self.Sjmp("JAE" , "_stack_overflow") // JA _stack_overflow self.Emit("SHLQ", jit.Imm(1), _DX) // SHLQ $1, DX self.Emit("LEAQ", jit.Sib(_SI, _DX, 8, 0), _SI) // LEAQ (SI)(DX*8), SI self.Emit("MOVQ", _CX, jit.Ptr(_ST, _ST_Sp)) // MOVQ CX, ST.Sp self.WriteRecNotAX(7 , _SI, jit.Sib(_ST, _CX, 8, _ST_Vp), false) // MOVQ SI, ST.Vp[CX] self.Emit("MOVQ", jit.Imm(_S_val), jit.Sib(_ST, _CX, 8, _ST_Vt)) // MOVQ _S_val, ST.Vt[CX} self.Sjmp("JMP" , "_next") // JMP _next /** V_ARRAY_END **/ self.Link("_decode_V_ARRAY_END") // _decode_V_ARRAY_END: self.Emit("XORL", _DX, _DX) // XORL DX, DX self.Emit("MOVQ", jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX self.Emit("MOVQ", jit.Sib(_ST, _CX, 8, _ST_Vt), _AX) // MOVQ ST.Vt[CX], AX self.Emit("CMPQ", _AX, jit.Imm(_S_arr_0)) // CMPQ AX, _S_arr_0 self.Sjmp("JE" , "_first_item") // JE _first_item self.Emit("CMPQ", _AX, jit.Imm(_S_arr)) // CMPQ AX, _S_arr self.Sjmp("JNE" , "_invalid_char") // JNE _invalid_char self.Emit("SUBQ", jit.Imm(1), jit.Ptr(_ST, _ST_Sp)) // SUBQ $1, ST.Sp self.Emit("MOVQ", _DX, jit.Sib(_ST, _CX, 8, _ST_Vp)) // MOVQ DX, ST.Vp[CX] self.Sjmp("JMP" , "_next") // JMP _next /* first element of an array */ self.Link("_first_item") // _first_item: self.Emit("MOVQ", jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX self.Emit("SUBQ", jit.Imm(2), jit.Ptr(_ST, _ST_Sp)) // SUBQ $2, ST.Sp self.Emit("MOVQ", jit.Sib(_ST, _CX, 8, _ST_Vp - 8), _SI) // MOVQ ST.Vp[CX - 1], SI self.Emit("MOVQ", jit.Ptr(_SI, 8), _SI) // MOVQ 8(SI), SI self.Emit("MOVQ", _DX, jit.Sib(_ST, _CX, 8, _ST_Vp - 8)) // MOVQ DX, ST.Vp[CX - 1] self.Emit("MOVQ", _DX, jit.Sib(_ST, _CX, 8, _ST_Vp)) // MOVQ DX, ST.Vp[CX] self.Emit("MOVQ", _DX, jit.Ptr(_SI, 8)) // MOVQ DX, 8(SI) self.Sjmp("JMP" , "_next") // JMP _next /** V_OBJECT_END **/ self.Link("_decode_V_OBJECT_END") // _decode_V_OBJECT_END: self.Emit("MOVL", jit.Imm(_S_omask_end), _DI) // MOVL _S_omask, DI self.Emit("MOVQ", jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX self.Emit("MOVQ", jit.Sib(_ST, _CX, 8, _ST_Vt), _AX) // MOVQ ST.Vt[CX], AX self.Emit("BTQ" , _AX, _DI) self.Sjmp("JNC" , "_invalid_char") // JNE _invalid_char self.Emit("XORL", _AX, _AX) // XORL AX, AX self.Emit("SUBQ", jit.Imm(1), jit.Ptr(_ST, _ST_Sp)) // SUBQ $1, ST.Sp self.Emit("MOVQ", _AX, jit.Sib(_ST, _CX, 8, _ST_Vp)) // MOVQ AX, ST.Vp[CX] self.Sjmp("JMP" , "_next") // JMP _next /* return from decoder */ self.Link("_return") // _return: self.Emit("XORL", _EP, _EP) // XORL EP, EP self.Emit("MOVQ", _EP, jit.Ptr(_ST, _ST_Vp)) // MOVQ EP, ST.Vp[0] self.Link("_epilogue") // _epilogue: self.Emit("SUBQ", jit.Imm(_FsmOffset), _ST) // SUBQ _FsmOffset, _ST self.Emit("MOVQ", jit.Ptr(_SP, _VD_offs), _BP) // MOVQ _VD_offs(SP), BP self.Emit("ADDQ", jit.Imm(_VD_size), _SP) // ADDQ $_VD_size, SP self.Emit("RET") // RET /* array expand */ self.Link("_array_more") // _array_more: self.Emit("MOVQ" , _T_eface, _AX) // MOVQ _T_eface, AX self.Emit("MOVQ" , jit.Ptr(_SI, 0), _BX) // MOVQ (SI), BX self.Emit("MOVQ" , jit.Ptr(_SI, 8), _CX) // MOVQ 8(SI), CX self.Emit("MOVQ" , jit.Ptr(_SI, 16), _DI) // MOVQ 16(SI), DI self.Emit("MOVQ" , _DI, _SI) // MOVQ DI, 24(SP) self.Emit("SHLQ" , jit.Imm(1), _SI) // SHLQ $1, SI self.call_go(_F_growslice) // CALL_GO runtime.growslice self.Emit("MOVQ" , _AX, _DI) // MOVQ AX, DI self.Emit("MOVQ" , _BX, _DX) // MOVQ BX, DX self.Emit("MOVQ" , _CX, _AX) // MOVQ CX, AX /* update the slice */ self.Emit("MOVQ", jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX self.Emit("MOVQ", jit.Sib(_ST, _CX, 8, _ST_Vp), _SI) // MOVQ ST.Vp[CX], SI self.Emit("MOVQ", jit.Ptr(_SI, 8), _SI) // MOVQ 8(SI), SI self.Emit("MOVQ", _DX, jit.Ptr(_SI, 8)) // MOVQ DX, 8(SI) self.Emit("MOVQ", _AX, jit.Ptr(_SI, 16)) // MOVQ AX, 16(AX) self.WriteRecNotAX(8 , _DI, jit.Ptr(_SI, 0), false) // MOVQ R10, (SI) self.Sjmp("JMP" , "_array_append") // JMP _array_append /* copy string */ self.Link("copy_string") // pointer: R8, length: AX, return addr: DI self.Emit("MOVQ", _R8, _VAR_cs_p) self.Emit("MOVQ", _AX, _VAR_cs_n) self.Emit("MOVQ", _DI, _VAR_cs_LR) self.Emit("MOVQ", _AX, _BX) self.Emit("MOVQ", _AX, _CX) self.Emit("MOVQ", _T_byte, _AX) self.call_go(_F_makeslice) self.Emit("MOVQ", _AX, _VAR_cs_d) self.Emit("MOVQ", _VAR_cs_p, _BX) self.Emit("MOVQ", _VAR_cs_n, _CX) self.call_go(_F_memmove) self.Emit("MOVQ", _VAR_cs_d, _R8) self.Emit("MOVQ", _VAR_cs_n, _AX) self.Emit("MOVQ", _VAR_cs_LR, _DI) self.Rjmp("JMP", _DI) /* error handlers */ self.Link("_stack_overflow") self.Emit("MOVL" , _E_recurse, _EP) // MOVQ _E_recurse, EP self.Sjmp("JMP" , "_error") // JMP _error self.Link("_vtype_error") // _vtype_error: self.Emit("MOVQ" , _DI, _IC) // MOVQ DI, IC self.Emit("MOVL" , _E_invalid, _EP) // MOVL _E_invalid, EP self.Sjmp("JMP" , "_error") // JMP _error self.Link("_invalid_char") // _invalid_char: self.Emit("SUBQ" , jit.Imm(1), _IC) // SUBQ $1, IC self.Emit("MOVL" , _E_invalid, _EP) // MOVL _E_invalid, EP self.Sjmp("JMP" , "_error") // JMP _error self.Link("_unquote_error") // _unquote_error: self.Emit("MOVQ" , _VAR_ss_Iv, _IC) // MOVQ ss.Iv, IC self.Emit("SUBQ" , jit.Imm(1), _IC) // SUBQ $1, IC self.Link("_parsing_error") // _parsing_error: self.Emit("NEGQ" , _AX) // NEGQ AX self.Emit("MOVQ" , _AX, _EP) // MOVQ AX, EP self.Link("_error") // _error: self.Emit("PXOR" , _X0, _X0) // PXOR X0, X0 self.Emit("MOVOU", _X0, jit.Ptr(_VP, 0)) // MOVOU X0, (VP) self.Sjmp("JMP" , "_epilogue") // JMP _epilogue /* invalid value type, never returns */ self.Link("_invalid_vtype") self.call_go(_F_invalid_vtype) // CALL invalid_type self.Emit("UD2") // UD2 /* switch jump table */ self.Link("_switch_table") // _switch_table: self.Sref("_decode_V_EOF", 0) // SREF &_decode_V_EOF, $0 self.Sref("_decode_V_NULL", -4) // SREF &_decode_V_NULL, $-4 self.Sref("_decode_V_TRUE", -8) // SREF &_decode_V_TRUE, $-8 self.Sref("_decode_V_FALSE", -12) // SREF &_decode_V_FALSE, $-12 self.Sref("_decode_V_ARRAY", -16) // SREF &_decode_V_ARRAY, $-16 self.Sref("_decode_V_OBJECT", -20) // SREF &_decode_V_OBJECT, $-20 self.Sref("_decode_V_STRING", -24) // SREF &_decode_V_STRING, $-24 self.Sref("_decode_V_DOUBLE", -28) // SREF &_decode_V_DOUBLE, $-28 self.Sref("_decode_V_INTEGER", -32) // SREF &_decode_V_INTEGER, $-32 self.Sref("_decode_V_KEY_SEP", -36) // SREF &_decode_V_KEY_SEP, $-36 self.Sref("_decode_V_ELEM_SEP", -40) // SREF &_decode_V_ELEM_SEP, $-40 self.Sref("_decode_V_ARRAY_END", -44) // SREF &_decode_V_ARRAY_END, $-44 self.Sref("_decode_V_OBJECT_END", -48) // SREF &_decode_V_OBJECT_END, $-48 /* fast character lookup table */ self.Link("_decode_tab") // _decode_tab: self.Sref("_decode_V_EOF", 0) // SREF &_decode_V_EOF, $0 /* generate rest of the tabs */ for i := 1; i < 256; i++ { if to, ok := _R_tab[i]; ok { self.Sref(to, -int64(i) * 4) } else { self.Byte(0x00, 0x00, 0x00, 0x00) } } } func (self *_ValueDecoder) WritePtrAX(i int, rec obj.Addr, saveDI bool) { self.Emit("MOVQ", _V_writeBarrier, _R9) self.Emit("CMPL", jit.Ptr(_R9, 0), jit.Imm(0)) self.Sjmp("JE", "_no_writeBarrier" + strconv.Itoa(i) + "_{n}") if saveDI { self.save(_DI) } self.Emit("LEAQ", rec, _DI) self.call(_F_gcWriteBarrierAX) if saveDI { self.load(_DI) } self.Sjmp("JMP", "_end_writeBarrier" + strconv.Itoa(i) + "_{n}") self.Link("_no_writeBarrier" + strconv.Itoa(i) + "_{n}") self.Emit("MOVQ", _AX, rec) self.Link("_end_writeBarrier" + strconv.Itoa(i) + "_{n}") } func (self *_ValueDecoder) WriteRecNotAX(i int, ptr obj.Addr, rec obj.Addr, saveDI bool) { if rec.Reg == x86.REG_AX || rec.Index == x86.REG_AX { panic("rec contains AX!") } self.Emit("MOVQ", _V_writeBarrier, _AX) self.Emit("CMPL", jit.Ptr(_AX, 0), jit.Imm(0)) self.Sjmp("JE", "_no_writeBarrier" + strconv.Itoa(i) + "_{n}") self.Emit("MOVQ", ptr, _AX) if saveDI { self.save(_DI) } self.Emit("LEAQ", rec, _DI) self.call(_F_gcWriteBarrierAX) if saveDI { self.load(_DI) } self.Sjmp("JMP", "_end_writeBarrier" + strconv.Itoa(i) + "_{n}") self.Link("_no_writeBarrier" + strconv.Itoa(i) + "_{n}") self.Emit("MOVQ", ptr, rec) self.Link("_end_writeBarrier" + strconv.Itoa(i) + "_{n}") } /** Generic Decoder **/ var ( _subr_decode_value = new(_ValueDecoder).build() ) //go:nosplit func invalid_vtype(vt types.ValueType) { throw(fmt.Sprintf("invalid value type: %d", vt)) }