podman
733 строки · 37.8 Кб
1// +build go1.16,!go1.17
2
3/*
4* Copyright 2021 ByteDance Inc.
5*
6* Licensed under the Apache License, Version 2.0 (the "License");
7* you may not use this file except in compliance with the License.
8* You may obtain a copy of the License at
9*
10* http://www.apache.org/licenses/LICENSE-2.0
11*
12* Unless required by applicable law or agreed to in writing, software
13* distributed under the License is distributed on an "AS IS" BASIS,
14* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15* See the License for the specific language governing permissions and
16* limitations under the License.
17*/
18
19package decoder
20
21import (
22`encoding/json`
23`fmt`
24`reflect`
25
26`github.com/bytedance/sonic/internal/jit`
27`github.com/bytedance/sonic/internal/native`
28`github.com/bytedance/sonic/internal/native/types`
29`github.com/twitchyliquid64/golang-asm/obj`
30)
31
32/** Crucial Registers:
33*
34* ST(BX) : ro, decoder stack
35* DF(R10) : ro, decoder flags
36* EP(R11) : wo, error pointer
37* IP(R12) : ro, input pointer
38* IL(R13) : ro, input length
39* IC(R14) : rw, input cursor
40* VP(R15) : ro, value pointer (to an interface{})
41*/
42
43const (
44_VD_args = 8 // 8 bytes for passing arguments to this functions
45_VD_fargs = 64 // 64 bytes for passing arguments to other Go functions
46_VD_saves = 40 // 40 bytes for saving the registers before CALL instructions
47_VD_locals = 88 // 88 bytes for local variables
48)
49
50const (
51_VD_offs = _VD_fargs + _VD_saves + _VD_locals
52_VD_size = _VD_offs + 8 // 8 bytes for the parent frame pointer
53)
54
55var (
56_VAR_ss = _VAR_ss_Vt
57_VAR_df = jit.Ptr(_SP, _VD_fargs + _VD_saves)
58)
59
60var (
61_VAR_ss_Vt = jit.Ptr(_SP, _VD_fargs + _VD_saves + 8)
62_VAR_ss_Dv = jit.Ptr(_SP, _VD_fargs + _VD_saves + 16)
63_VAR_ss_Iv = jit.Ptr(_SP, _VD_fargs + _VD_saves + 24)
64_VAR_ss_Ep = jit.Ptr(_SP, _VD_fargs + _VD_saves + 32)
65_VAR_ss_Db = jit.Ptr(_SP, _VD_fargs + _VD_saves + 40)
66_VAR_ss_Dc = jit.Ptr(_SP, _VD_fargs + _VD_saves + 48)
67)
68
69var (
70_VAR_cs_LR = jit.Ptr(_SP, _VD_fargs + _VD_saves + 56)
71_VAR_cs_p = jit.Ptr(_SP, _VD_fargs + _VD_saves + 64)
72_VAR_cs_n = jit.Ptr(_SP, _VD_fargs + _VD_saves + 72)
73_VAR_cs_d = jit.Ptr(_SP, _VD_fargs + _VD_saves + 80)
74)
75
76type _ValueDecoder struct {
77jit.BaseAssembler
78}
79
80func (self *_ValueDecoder) build() uintptr {
81self.Init(self.compile)
82return *(*uintptr)(self.Load("decode_value", _VD_size, _VD_args, argPtrs_generic, localPtrs_generic))
83}
84
85/** Function Calling Helpers **/
86
87func (self *_ValueDecoder) save(r ...obj.Addr) {
88for i, v := range r {
89if i > _VD_saves / 8 - 1 {
90panic("too many registers to save")
91} else {
92self.Emit("MOVQ", v, jit.Ptr(_SP, _VD_fargs + int64(i) * 8))
93}
94}
95}
96
97func (self *_ValueDecoder) load(r ...obj.Addr) {
98for i, v := range r {
99if i > _VD_saves / 8 - 1 {
100panic("too many registers to load")
101} else {
102self.Emit("MOVQ", jit.Ptr(_SP, _VD_fargs + int64(i) * 8), v)
103}
104}
105}
106
107func (self *_ValueDecoder) call(fn obj.Addr) {
108self.Emit("MOVQ", fn, _AX) // MOVQ ${fn}, AX
109self.Rjmp("CALL", _AX) // CALL AX
110}
111
112func (self *_ValueDecoder) call_go(fn obj.Addr) {
113self.save(_REG_go...) // SAVE $REG_go
114self.call(fn) // CALL ${fn}
115self.load(_REG_go...) // LOAD $REG_go
116}
117
118/** Decoder Assembler **/
119
120const (
121_S_val = iota + 1
122_S_arr
123_S_arr_0
124_S_obj
125_S_obj_0
126_S_obj_delim
127_S_obj_sep
128)
129
130const (
131_S_omask_key = (1 << _S_obj_0) | (1 << _S_obj_sep)
132_S_omask_end = (1 << _S_obj_0) | (1 << _S_obj)
133_S_vmask = (1 << _S_val) | (1 << _S_arr_0)
134)
135
136const (
137_A_init_len = 1
138_A_init_cap = 16
139)
140
141const (
142_ST_Sp = 0
143_ST_Vt = _PtrBytes
144_ST_Vp = _PtrBytes * (types.MAX_RECURSE + 1)
145)
146
147var (
148_V_true = jit.Imm(int64(pbool(true)))
149_V_false = jit.Imm(int64(pbool(false)))
150_F_value = jit.Imm(int64(native.S_value))
151)
152
153var (
154_V_max = jit.Imm(int64(types.V_MAX))
155_E_eof = jit.Imm(int64(types.ERR_EOF))
156_E_invalid = jit.Imm(int64(types.ERR_INVALID_CHAR))
157_E_recurse = jit.Imm(int64(types.ERR_RECURSE_EXCEED_MAX))
158)
159
160var (
161_F_convTslice = jit.Func(convTslice)
162_F_convTstring = jit.Func(convTstring)
163_F_invalid_vtype = jit.Func(invalid_vtype)
164)
165
166var (
167_T_map = jit.Type(reflect.TypeOf((map[string]interface{})(nil)))
168_T_bool = jit.Type(reflect.TypeOf(false))
169_T_int64 = jit.Type(reflect.TypeOf(int64(0)))
170_T_eface = jit.Type(reflect.TypeOf((*interface{})(nil)).Elem())
171_T_slice = jit.Type(reflect.TypeOf(([]interface{})(nil)))
172_T_string = jit.Type(reflect.TypeOf(""))
173_T_number = jit.Type(reflect.TypeOf(json.Number("")))
174_T_float64 = jit.Type(reflect.TypeOf(float64(0)))
175)
176
177var _R_tab = map[int]string {
178'[': "_decode_V_ARRAY",
179'{': "_decode_V_OBJECT",
180':': "_decode_V_KEY_SEP",
181',': "_decode_V_ELEM_SEP",
182']': "_decode_V_ARRAY_END",
183'}': "_decode_V_OBJECT_END",
184}
185
186func (self *_ValueDecoder) compile() {
187self.Emit("SUBQ", jit.Imm(_VD_size), _SP) // SUBQ $_VD_size, SP
188self.Emit("MOVQ", _BP, jit.Ptr(_SP, _VD_offs)) // MOVQ BP, _VD_offs(SP)
189self.Emit("LEAQ", jit.Ptr(_SP, _VD_offs), _BP) // LEAQ _VD_offs(SP), BP
190
191/* initialize the state machine */
192self.Emit("XORL", _CX, _CX) // XORL CX, CX
193self.Emit("MOVQ", _DF, _VAR_df) // MOVQ DF, df
194/* initialize digital buffer first */
195self.Emit("MOVQ", jit.Imm(_MaxDigitNums), _VAR_ss_Dc) // MOVQ $_MaxDigitNums, ss.Dcap
196self.Emit("LEAQ", jit.Ptr(_ST, _DbufOffset), _AX) // LEAQ _DbufOffset(ST), AX
197self.Emit("MOVQ", _AX, _VAR_ss_Db) // MOVQ AX, ss.Dbuf
198/* add ST offset */
199self.Emit("ADDQ", jit.Imm(_FsmOffset), _ST) // ADDQ _FsmOffset, _ST
200self.Emit("MOVQ", _CX, jit.Ptr(_ST, _ST_Sp)) // MOVQ CX, ST.Sp
201self.WriteRecNotAX(0, _VP, jit.Ptr(_ST, _ST_Vp), false) // MOVQ VP, ST.Vp[0]
202self.Emit("MOVQ", jit.Imm(_S_val), jit.Ptr(_ST, _ST_Vt)) // MOVQ _S_val, ST.Vt[0]
203self.Sjmp("JMP" , "_next") // JMP _next
204
205/* set the value from previous round */
206self.Link("_set_value") // _set_value:
207self.Emit("MOVL" , jit.Imm(_S_vmask), _DX) // MOVL _S_vmask, DX
208self.Emit("MOVQ" , jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX
209self.Emit("MOVQ" , jit.Sib(_ST, _CX, 8, _ST_Vt), _AX) // MOVQ ST.Vt[CX], AX
210self.Emit("BTQ" , _AX, _DX) // BTQ AX, DX
211self.Sjmp("JNC" , "_vtype_error") // JNC _vtype_error
212self.Emit("XORL" , _SI, _SI) // XORL SI, SI
213self.Emit("SUBQ" , jit.Imm(1), jit.Ptr(_ST, _ST_Sp)) // SUBQ $1, ST.Sp
214self.Emit("XCHGQ", jit.Sib(_ST, _CX, 8, _ST_Vp), _SI) // XCHGQ ST.Vp[CX], SI
215self.Emit("MOVQ" , _R8, jit.Ptr(_SI, 0)) // MOVQ R8, (SI)
216self.WriteRecNotAX(1, _R9, jit.Ptr(_SI, 8), false) // MOVQ R9, 8(SI)
217
218/* check for value stack */
219self.Link("_next") // _next:
220self.Emit("MOVQ" , jit.Ptr(_ST, _ST_Sp), _AX) // MOVQ ST.Sp, AX
221self.Emit("TESTQ", _AX, _AX) // TESTQ AX, AX
222self.Sjmp("JS" , "_return") // JS _return
223
224/* fast path: test up to 4 characters manually */
225self.Emit("CMPQ" , _IC, _IL) // CMPQ IC, IL
226self.Sjmp("JAE" , "_decode_V_EOF") // JAE _decode_V_EOF
227self.Emit("MOVBQZX", jit.Sib(_IP, _IC, 1, 0), _AX) // MOVBQZX (IP)(IC), AX
228self.Emit("MOVQ" , jit.Imm(_BM_space), _DX) // MOVQ _BM_space, DX
229self.Emit("CMPQ" , _AX, jit.Imm(' ')) // CMPQ AX, $' '
230self.Sjmp("JA" , "_decode_fast") // JA _decode_fast
231self.Emit("BTQ" , _AX, _DX) // BTQ _AX, _DX
232self.Sjmp("JNC" , "_decode_fast") // JNC _decode_fast
233self.Emit("ADDQ" , jit.Imm(1), _IC) // ADDQ $1, IC
234
235/* at least 1 to 3 spaces */
236for i := 0; i < 3; i++ {
237self.Emit("CMPQ" , _IC, _IL) // CMPQ IC, IL
238self.Sjmp("JAE" , "_decode_V_EOF") // JAE _decode_V_EOF
239self.Emit("MOVBQZX", jit.Sib(_IP, _IC, 1, 0), _AX) // MOVBQZX (IP)(IC), AX
240self.Emit("CMPQ" , _AX, jit.Imm(' ')) // CMPQ AX, $' '
241self.Sjmp("JA" , "_decode_fast") // JA _decode_fast
242self.Emit("BTQ" , _AX, _DX) // BTQ _AX, _DX
243self.Sjmp("JNC" , "_decode_fast") // JNC _decode_fast
244self.Emit("ADDQ" , jit.Imm(1), _IC) // ADDQ $1, IC
245}
246
247/* at least 4 spaces */
248self.Emit("CMPQ" , _IC, _IL) // CMPQ IC, IL
249self.Sjmp("JAE" , "_decode_V_EOF") // JAE _decode_V_EOF
250self.Emit("MOVBQZX", jit.Sib(_IP, _IC, 1, 0), _AX) // MOVBQZX (IP)(IC), AX
251
252/* fast path: use lookup table to select decoder */
253self.Link("_decode_fast") // _decode_fast:
254self.Byte(0x48, 0x8d, 0x3d) // LEAQ ?(PC), DI
255self.Sref("_decode_tab", 4) // .... &_decode_tab
256self.Emit("MOVLQSX", jit.Sib(_DI, _AX, 4, 0), _AX) // MOVLQSX (DI)(AX*4), AX
257self.Emit("TESTQ" , _AX, _AX) // TESTQ AX, AX
258self.Sjmp("JZ" , "_decode_native") // JZ _decode_native
259self.Emit("ADDQ" , jit.Imm(1), _IC) // ADDQ $1, IC
260self.Emit("ADDQ" , _DI, _AX) // ADDQ DI, AX
261self.Rjmp("JMP" , _AX) // JMP AX
262
263/* decode with native decoder */
264self.Link("_decode_native") // _decode_native:
265self.Emit("MOVQ", _IP, _DI) // MOVQ IP, DI
266self.Emit("MOVQ", _IL, _SI) // MOVQ IL, SI
267self.Emit("MOVQ", _IC, _DX) // MOVQ IC, DX
268self.Emit("LEAQ", _VAR_ss, _CX) // LEAQ ss, CX
269self.Emit("MOVQ", _VAR_df, _R8) // MOVQ $df, R8
270self.Emit("BTSQ", jit.Imm(_F_allow_control), _R8) // ANDQ $1<<_F_allow_control, R8
271self.call(_F_value) // CALL value
272self.Emit("MOVQ", _AX, _IC) // MOVQ AX, IC
273
274/* check for errors */
275self.Emit("MOVQ" , _VAR_ss_Vt, _AX) // MOVQ ss.Vt, AX
276self.Emit("TESTQ", _AX, _AX) // TESTQ AX, AX
277self.Sjmp("JS" , "_parsing_error")
278self.Sjmp("JZ" , "_invalid_vtype") // JZ _invalid_vtype
279self.Emit("CMPQ" , _AX, _V_max) // CMPQ AX, _V_max
280self.Sjmp("JA" , "_invalid_vtype") // JA _invalid_vtype
281
282/* jump table selector */
283self.Byte(0x48, 0x8d, 0x3d) // LEAQ ?(PC), DI
284self.Sref("_switch_table", 4) // .... &_switch_table
285self.Emit("MOVLQSX", jit.Sib(_DI, _AX, 4, -4), _AX) // MOVLQSX -4(DI)(AX*4), AX
286self.Emit("ADDQ" , _DI, _AX) // ADDQ DI, AX
287self.Rjmp("JMP" , _AX) // JMP AX
288
289/** V_EOF **/
290self.Link("_decode_V_EOF") // _decode_V_EOF:
291self.Emit("MOVL", _E_eof, _EP) // MOVL _E_eof, EP
292self.Sjmp("JMP" , "_error") // JMP _error
293
294/** V_NULL **/
295self.Link("_decode_V_NULL") // _decode_V_NULL:
296self.Emit("XORL", _R8, _R8) // XORL R8, R8
297self.Emit("XORL", _R9, _R9) // XORL R9, R9
298self.Emit("LEAQ", jit.Ptr(_IC, -4), _DI) // LEAQ -4(IC), DI
299self.Sjmp("JMP" , "_set_value") // JMP _set_value
300
301/** V_TRUE **/
302self.Link("_decode_V_TRUE") // _decode_V_TRUE:
303self.Emit("MOVQ", _T_bool, _R8) // MOVQ _T_bool, R8
304// TODO: maybe modified by users?
305self.Emit("MOVQ", _V_true, _R9) // MOVQ _V_true, R9
306self.Emit("LEAQ", jit.Ptr(_IC, -4), _DI) // LEAQ -4(IC), DI
307self.Sjmp("JMP" , "_set_value") // JMP _set_value
308
309/** V_FALSE **/
310self.Link("_decode_V_FALSE") // _decode_V_FALSE:
311self.Emit("MOVQ", _T_bool, _R8) // MOVQ _T_bool, R8
312self.Emit("MOVQ", _V_false, _R9) // MOVQ _V_false, R9
313self.Emit("LEAQ", jit.Ptr(_IC, -5), _DI) // LEAQ -5(IC), DI
314self.Sjmp("JMP" , "_set_value") // JMP _set_value
315
316/** V_ARRAY **/
317self.Link("_decode_V_ARRAY") // _decode_V_ARRAY
318self.Emit("MOVL", jit.Imm(_S_vmask), _DX) // MOVL _S_vmask, DX
319self.Emit("MOVQ", jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX
320self.Emit("MOVQ", jit.Sib(_ST, _CX, 8, _ST_Vt), _AX) // MOVQ ST.Vt[CX], AX
321self.Emit("BTQ" , _AX, _DX) // BTQ AX, DX
322self.Sjmp("JNC" , "_invalid_char") // JNC _invalid_char
323
324/* create a new array */
325self.Emit("MOVQ", _T_eface, _AX) // MOVQ _T_eface, AX
326self.Emit("MOVQ", _AX, jit.Ptr(_SP, 0)) // MOVQ AX, (SP)
327self.Emit("MOVQ", jit.Imm(_A_init_len), jit.Ptr(_SP, 8)) // MOVQ _A_init_len, 8(SP)
328self.Emit("MOVQ", jit.Imm(_A_init_cap), jit.Ptr(_SP, 16)) // MOVQ _A_init_cap, 16(SP)
329self.call_go(_F_makeslice) // CALL_GO runtime.makeslice
330self.Emit("MOVQ", jit.Ptr(_SP, 24), _DX) // MOVQ 24(SP), DX
331
332/* pack into an interface */
333self.Emit("MOVQ", _DX, jit.Ptr(_SP, 0)) // MOVQ DX, (SP)
334self.Emit("MOVQ", jit.Imm(_A_init_len), jit.Ptr(_SP, 8)) // MOVQ _A_init_len, 8(SP)
335self.Emit("MOVQ", jit.Imm(_A_init_cap), jit.Ptr(_SP, 16)) // MOVQ _A_init_cap, 16(SP)
336self.call_go(_F_convTslice) // CALL_GO runtime.convTslice
337self.Emit("MOVQ", jit.Ptr(_SP, 24), _R8) // MOVQ 24(SP), R8
338
339/* replace current state with an array */
340self.Emit("MOVQ", jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX
341self.Emit("MOVQ", jit.Sib(_ST, _CX, 8, _ST_Vp), _SI) // MOVQ ST.Vp[CX], SI
342self.Emit("MOVQ", jit.Imm(_S_arr), jit.Sib(_ST, _CX, 8, _ST_Vt)) // MOVQ _S_arr, ST.Vt[CX]
343self.Emit("MOVQ", _T_slice, _AX) // MOVQ _T_slice, AX
344self.Emit("MOVQ", _AX, jit.Ptr(_SI, 0)) // MOVQ AX, (SI)
345self.WriteRecNotAX(2, _R8, jit.Ptr(_SI, 8), false) // MOVQ R8, 8(SI)
346
347/* add a new slot for the first element */
348self.Emit("ADDQ", jit.Imm(1), _CX) // ADDQ $1, CX
349self.Emit("CMPQ", _CX, jit.Imm(types.MAX_RECURSE)) // CMPQ CX, ${types.MAX_RECURSE}
350self.Sjmp("JAE" , "_stack_overflow") // JA _stack_overflow
351self.Emit("MOVQ", jit.Ptr(_R8, 0), _AX) // MOVQ (R8), AX
352self.Emit("MOVQ", _CX, jit.Ptr(_ST, _ST_Sp)) // MOVQ CX, ST.Sp
353self.WritePtrAX(3, jit.Sib(_ST, _CX, 8, _ST_Vp), false) // MOVQ AX, ST.Vp[CX]
354self.Emit("MOVQ", jit.Imm(_S_arr_0), jit.Sib(_ST, _CX, 8, _ST_Vt)) // MOVQ _S_arr_0, ST.Vt[CX]
355self.Sjmp("JMP" , "_next") // JMP _next
356
357/** V_OBJECT **/
358self.Link("_decode_V_OBJECT") // _decode_V_OBJECT:
359self.Emit("MOVL", jit.Imm(_S_vmask), _DX) // MOVL _S_vmask, DX
360self.Emit("MOVQ", jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX
361self.Emit("MOVQ", jit.Sib(_ST, _CX, 8, _ST_Vt), _AX) // MOVQ ST.Vt[CX], AX
362self.Emit("BTQ" , _AX, _DX) // BTQ AX, DX
363self.Sjmp("JNC" , "_invalid_char") // JNC _invalid_char
364self.call_go(_F_makemap_small) // CALL_GO runtime.makemap_small
365self.Emit("MOVQ", jit.Ptr(_SP, 0), _AX) // MOVQ (SP), AX
366self.Emit("MOVQ", jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX
367self.Emit("MOVQ", jit.Imm(_S_obj_0), jit.Sib(_ST, _CX, 8, _ST_Vt)) // MOVQ _S_obj, ST.Vt[CX]
368self.Emit("MOVQ", jit.Sib(_ST, _CX, 8, _ST_Vp), _SI) // MOVQ ST.Vp[CX], SI
369self.Emit("MOVQ", _T_map, _DX) // MOVQ _T_map, DX
370self.Emit("MOVQ", _DX, jit.Ptr(_SI, 0)) // MOVQ DX, (SI)
371self.WritePtrAX(4, jit.Ptr(_SI, 8), false) // MOVQ AX, 8(SI)
372self.Sjmp("JMP" , "_next") // JMP _next
373
374/** V_STRING **/
375self.Link("_decode_V_STRING") // _decode_V_STRING:
376self.Emit("MOVQ", _VAR_ss_Iv, _CX) // MOVQ ss.Iv, CX
377self.Emit("MOVQ", _IC, _AX) // MOVQ IC, AX
378self.Emit("SUBQ", _CX, _AX) // SUBQ CX, AX
379
380/* check for escapes */
381self.Emit("CMPQ", _VAR_ss_Ep, jit.Imm(-1)) // CMPQ ss.Ep, $-1
382self.Sjmp("JNE" , "_unquote") // JNE _unquote
383self.Emit("SUBQ", jit.Imm(1), _AX) // SUBQ $1, AX
384self.Emit("LEAQ", jit.Sib(_IP, _CX, 1, 0), _R8) // LEAQ (IP)(CX), R8
385self.Byte(0x48, 0x8d, 0x3d) // LEAQ (PC), DI
386self.Sref("_copy_string_end", 4)
387self.Emit("BTQ", jit.Imm(_F_copy_string), _VAR_df)
388self.Sjmp("JC", "copy_string")
389self.Link("_copy_string_end")
390self.Emit("XORL", _DX, _DX) // XORL DX, DX
391/* strings with no escape sequences */
392self.Link("_noescape") // _noescape:
393self.Emit("MOVL", jit.Imm(_S_omask_key), _DI) // MOVL _S_omask, DI
394self.Emit("MOVQ", jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX
395self.Emit("MOVQ", jit.Sib(_ST, _CX, 8, _ST_Vt), _SI) // MOVQ ST.Vt[CX], SI
396self.Emit("BTQ" , _SI, _DI) // BTQ SI, DI
397self.Sjmp("JC" , "_object_key") // JC _object_key
398
399/* check for pre-packed strings, avoid 1 allocation */
400self.Emit("TESTQ", _DX, _DX) // TESTQ DX, DX
401self.Sjmp("JNZ" , "_packed_str") // JNZ _packed_str
402self.Emit("MOVQ" , _R8, jit.Ptr(_SP, 0)) // MOVQ R8, (SP)
403self.Emit("MOVQ" , _AX, jit.Ptr(_SP, 8)) // MOVQ AX, 8(SP)
404self.call_go(_F_convTstring) // CALL_GO runtime.convTstring
405self.Emit("MOVQ" , jit.Ptr(_SP, 16), _R9) // MOVQ 16(SP), R9
406
407/* packed string already in R9 */
408self.Link("_packed_str") // _packed_str:
409self.Emit("MOVQ", _T_string, _R8) // MOVQ _T_string, R8
410self.Emit("MOVQ", _VAR_ss_Iv, _DI) // MOVQ ss.Iv, DI
411self.Emit("SUBQ", jit.Imm(1), _DI) // SUBQ $1, DI
412self.Sjmp("JMP" , "_set_value") // JMP _set_value
413
414/* the string is an object key, get the map */
415self.Link("_object_key")
416self.Emit("MOVQ", jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX
417self.Emit("MOVQ", jit.Sib(_ST, _CX, 8, _ST_Vp), _SI) // MOVQ ST.Vp[CX], SI
418self.Emit("MOVQ", jit.Ptr(_SI, 8), _SI) // MOVQ 8(SI), SI
419
420/* add a new delimiter */
421self.Emit("ADDQ", jit.Imm(1), _CX) // ADDQ $1, CX
422self.Emit("CMPQ", _CX, jit.Imm(types.MAX_RECURSE)) // CMPQ CX, ${types.MAX_RECURSE}
423self.Sjmp("JAE" , "_stack_overflow") // JA _stack_overflow
424self.Emit("MOVQ", _CX, jit.Ptr(_ST, _ST_Sp)) // MOVQ CX, ST.Sp
425self.Emit("MOVQ", jit.Imm(_S_obj_delim), jit.Sib(_ST, _CX, 8, _ST_Vt)) // MOVQ _S_obj_delim, ST.Vt[CX]
426
427/* add a new slot int the map */
428self.Emit("MOVQ", _T_map, _DX) // MOVQ _T_map, DX
429self.Emit("MOVQ", _DX, jit.Ptr(_SP, 0)) // MOVQ DX, (SP)
430self.Emit("MOVQ", _SI, jit.Ptr(_SP, 8)) // MOVQ SI, 8(SP)
431self.Emit("MOVQ", _R8, jit.Ptr(_SP, 16)) // MOVQ R9, 16(SP)
432self.Emit("MOVQ", _AX, jit.Ptr(_SP, 24)) // MOVQ AX, 24(SP)
433self.call_go(_F_mapassign_faststr) // CALL_GO runtime.mapassign_faststr
434self.Emit("MOVQ", jit.Ptr(_SP, 32), _AX) // MOVQ 32(SP), AX
435
436/* add to the pointer stack */
437self.Emit("MOVQ", jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX
438self.WritePtrAX(6, jit.Sib(_ST, _CX, 8, _ST_Vp), false) // MOVQ AX, ST.Vp[CX]
439self.Sjmp("JMP" , "_next") // JMP _next
440
441/* allocate memory to store the string header and unquoted result */
442self.Link("_unquote") // _unquote:
443self.Emit("ADDQ", jit.Imm(15), _AX) // ADDQ $15, AX
444self.Emit("MOVQ", _T_byte, _CX) // MOVQ _T_byte, CX
445self.Emit("MOVQ", _AX, jit.Ptr(_SP, 0)) // MOVQ AX, (SP)
446self.Emit("MOVQ", _CX, jit.Ptr(_SP, 8)) // MOVQ CX, 8(SP)
447self.Emit("MOVB", jit.Imm(0), jit.Ptr(_SP, 16)) // MOVB $0, 16(SP)
448self.call_go(_F_mallocgc) // CALL_GO runtime.mallocgc
449self.Emit("MOVQ", jit.Ptr(_SP, 24), _R9) // MOVQ 24(SP), R9
450
451/* prepare the unquoting parameters */
452self.Emit("MOVQ" , _VAR_ss_Iv, _CX) // MOVQ ss.Iv, CX
453self.Emit("LEAQ" , jit.Sib(_IP, _CX, 1, 0), _DI) // LEAQ (IP)(CX), DI
454self.Emit("NEGQ" , _CX) // NEGQ CX
455self.Emit("LEAQ" , jit.Sib(_IC, _CX, 1, -1), _SI) // LEAQ -1(IC)(CX), SI
456self.Emit("LEAQ" , jit.Ptr(_R9, 16), _DX) // LEAQ 16(R8), DX
457self.Emit("LEAQ" , _VAR_ss_Ep, _CX) // LEAQ ss.Ep, CX
458self.Emit("XORL" , _R8, _R8) // XORL R8, R8
459self.Emit("BTQ" , jit.Imm(_F_disable_urc), _VAR_df) // BTQ ${_F_disable_urc}, fv
460self.Emit("SETCC", _R8) // SETCC R8
461self.Emit("SHLQ" , jit.Imm(types.B_UNICODE_REPLACE), _R8) // SHLQ ${types.B_UNICODE_REPLACE}, R8
462
463/* unquote the string, with R9 been preserved */
464self.save(_R9) // SAVE R9
465self.call(_F_unquote) // CALL unquote
466self.load(_R9) // LOAD R9
467
468/* check for errors */
469self.Emit("TESTQ", _AX, _AX) // TESTQ AX, AX
470self.Sjmp("JS" , "_unquote_error") // JS _unquote_error
471self.Emit("MOVL" , jit.Imm(1), _DX) // MOVL $1, DX
472self.Emit("LEAQ" , jit.Ptr(_R9, 16), _R8) // ADDQ $16, R8
473self.Emit("MOVQ" , _R8, jit.Ptr(_R9, 0)) // MOVQ R8, (R9)
474self.Emit("MOVQ" , _AX, jit.Ptr(_R9, 8)) // MOVQ AX, 8(R9)
475self.Sjmp("JMP" , "_noescape") // JMP _noescape
476
477/** V_DOUBLE **/
478self.Link("_decode_V_DOUBLE") // _decode_V_DOUBLE:
479self.Emit("BTQ" , jit.Imm(_F_use_number), _VAR_df) // BTQ _F_use_number, df
480self.Sjmp("JC" , "_use_number") // JC _use_number
481self.Emit("MOVSD", _VAR_ss_Dv, _X0) // MOVSD ss.Dv, X0
482self.Sjmp("JMP" , "_use_float64") // JMP _use_float64
483
484/** V_INTEGER **/
485self.Link("_decode_V_INTEGER") // _decode_V_INTEGER:
486self.Emit("BTQ" , jit.Imm(_F_use_number), _VAR_df) // BTQ _F_use_number, df
487self.Sjmp("JC" , "_use_number") // JC _use_number
488self.Emit("BTQ" , jit.Imm(_F_use_int64), _VAR_df) // BTQ _F_use_int64, df
489self.Sjmp("JC" , "_use_int64") // JC _use_int64
490self.Emit("MOVQ" , _VAR_ss_Iv, _AX) // MOVQ ss.Iv, AX
491self.Emit("CVTSQ2SD", _AX, _X0) // CVTSQ2SD AX, X0
492
493/* represent numbers as `float64` */
494self.Link("_use_float64") // _use_float64:
495self.Emit("MOVSD", _X0, jit.Ptr(_SP, 0)) // MOVSD X0, (SP)
496self.call_go(_F_convT64) // CALL_GO runtime.convT64
497self.Emit("MOVQ" , _T_float64, _R8) // MOVQ _T_float64, R8
498self.Emit("MOVQ" , jit.Ptr(_SP, 8), _R9) // MOVQ 8(SP), R9
499self.Emit("MOVQ" , _VAR_ss_Ep, _DI) // MOVQ ss.Ep, DI
500self.Sjmp("JMP" , "_set_value") // JMP _set_value
501
502/* represent numbers as `json.Number` */
503self.Link("_use_number") // _use_number
504self.Emit("MOVQ", _VAR_ss_Ep, _AX) // MOVQ ss.Ep, AX
505self.Emit("LEAQ", jit.Sib(_IP, _AX, 1, 0), _SI) // LEAQ (IP)(AX), SI
506self.Emit("MOVQ", _IC, _CX) // MOVQ IC, CX
507self.Emit("SUBQ", _AX, _CX) // SUBQ AX, CX
508self.Emit("MOVQ", _SI, jit.Ptr(_SP, 0)) // MOVQ SI, (SP)
509self.Emit("MOVQ", _CX, jit.Ptr(_SP, 8)) // MOVQ CX, 8(SP)
510self.call_go(_F_convTstring) // CALL_GO runtime.convTstring
511self.Emit("MOVQ", _T_number, _R8) // MOVQ _T_number, R8
512self.Emit("MOVQ", jit.Ptr(_SP, 16), _R9) // MOVQ 16(SP), R9
513self.Emit("MOVQ", _VAR_ss_Ep, _DI) // MOVQ ss.Ep, DI
514self.Sjmp("JMP" , "_set_value") // JMP _set_value
515
516/* represent numbers as `int64` */
517self.Link("_use_int64") // _use_int64:
518self.Emit("MOVQ", _VAR_ss_Iv, _AX) // MOVQ ss.Iv, AX
519self.Emit("MOVQ", _AX, jit.Ptr(_SP, 0)) // MOVQ AX, (SP)
520self.call_go(_F_convT64) // CALL_GO runtime.convT64
521self.Emit("MOVQ", _T_int64, _R8) // MOVQ _T_int64, R8
522self.Emit("MOVQ", jit.Ptr(_SP, 8), _R9) // MOVQ 8(SP), R9
523self.Emit("MOVQ", _VAR_ss_Ep, _DI) // MOVQ ss.Ep, DI
524self.Sjmp("JMP" , "_set_value") // JMP _set_value
525
526/** V_KEY_SEP **/
527self.Link("_decode_V_KEY_SEP") // _decode_V_KEY_SEP:
528// self.Byte(0xcc)
529self.Emit("MOVQ", jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX
530self.Emit("MOVQ", jit.Sib(_ST, _CX, 8, _ST_Vt), _AX) // MOVQ ST.Vt[CX], AX
531self.Emit("CMPQ", _AX, jit.Imm(_S_obj_delim)) // CMPQ AX, _S_obj_delim
532self.Sjmp("JNE" , "_invalid_char") // JNE _invalid_char
533self.Emit("MOVQ", jit.Imm(_S_val), jit.Sib(_ST, _CX, 8, _ST_Vt)) // MOVQ _S_val, ST.Vt[CX]
534self.Emit("MOVQ", jit.Imm(_S_obj), jit.Sib(_ST, _CX, 8, _ST_Vt - 8)) // MOVQ _S_obj, ST.Vt[CX - 1]
535self.Sjmp("JMP" , "_next") // JMP _next
536
537/** V_ELEM_SEP **/
538self.Link("_decode_V_ELEM_SEP") // _decode_V_ELEM_SEP:
539self.Emit("MOVQ" , jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX
540self.Emit("MOVQ" , jit.Sib(_ST, _CX, 8, _ST_Vt), _AX) // MOVQ ST.Vt[CX], AX
541self.Emit("CMPQ" , _AX, jit.Imm(_S_arr)) // CMPQ _AX, _S_arr
542self.Sjmp("JE" , "_array_sep") // JZ _next
543self.Emit("CMPQ" , _AX, jit.Imm(_S_obj)) // CMPQ _AX, _S_arr
544self.Sjmp("JNE" , "_invalid_char") // JNE _invalid_char
545self.Emit("MOVQ" , jit.Imm(_S_obj_sep), jit.Sib(_ST, _CX, 8, _ST_Vt))
546self.Sjmp("JMP" , "_next") // JMP _next
547
548/* arrays */
549self.Link("_array_sep")
550self.Emit("MOVQ", jit.Sib(_ST, _CX, 8, _ST_Vp), _SI) // MOVQ ST.Vp[CX], SI
551self.Emit("MOVQ", jit.Ptr(_SI, 8), _SI) // MOVQ 8(SI), SI
552self.Emit("MOVQ", jit.Ptr(_SI, 8), _DX) // MOVQ 8(SI), DX
553self.Emit("CMPQ", _DX, jit.Ptr(_SI, 16)) // CMPQ DX, 16(SI)
554self.Sjmp("JAE" , "_array_more") // JAE _array_more
555
556/* add a slot for the new element */
557self.Link("_array_append") // _array_append:
558self.Emit("ADDQ", jit.Imm(1), jit.Ptr(_SI, 8)) // ADDQ $1, 8(SI)
559self.Emit("MOVQ", jit.Ptr(_SI, 0), _SI) // MOVQ (SI), SI
560self.Emit("ADDQ", jit.Imm(1), _CX) // ADDQ $1, CX
561self.Emit("CMPQ", _CX, jit.Imm(types.MAX_RECURSE)) // CMPQ CX, ${types.MAX_RECURSE}
562self.Sjmp("JAE" , "_stack_overflow")
563self.Emit("SHLQ", jit.Imm(1), _DX) // SHLQ $1, DX
564self.Emit("LEAQ", jit.Sib(_SI, _DX, 8, 0), _SI) // LEAQ (SI)(DX*8), SI
565self.Emit("MOVQ", _CX, jit.Ptr(_ST, _ST_Sp)) // MOVQ CX, ST.Sp
566self.WriteRecNotAX(7 , _SI, jit.Sib(_ST, _CX, 8, _ST_Vp), false) // MOVQ SI, ST.Vp[CX]
567self.Emit("MOVQ", jit.Imm(_S_val), jit.Sib(_ST, _CX, 8, _ST_Vt)) // MOVQ _S_val, ST.Vt[CX}
568self.Sjmp("JMP" , "_next") // JMP _next
569
570/** V_ARRAY_END **/
571self.Link("_decode_V_ARRAY_END") // _decode_V_ARRAY_END:
572self.Emit("XORL", _DX, _DX) // XORL DX, DX
573self.Emit("MOVQ", jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX
574self.Emit("MOVQ", jit.Sib(_ST, _CX, 8, _ST_Vt), _AX) // MOVQ ST.Vt[CX], AX
575self.Emit("CMPQ", _AX, jit.Imm(_S_arr_0)) // CMPQ AX, _S_arr_0
576self.Sjmp("JE" , "_first_item") // JE _first_item
577self.Emit("CMPQ", _AX, jit.Imm(_S_arr)) // CMPQ AX, _S_arr
578self.Sjmp("JNE" , "_invalid_char") // JNE _invalid_char
579self.Emit("SUBQ", jit.Imm(1), jit.Ptr(_ST, _ST_Sp)) // SUBQ $1, ST.Sp
580self.Emit("MOVQ", _DX, jit.Sib(_ST, _CX, 8, _ST_Vp)) // MOVQ DX, ST.Vp[CX]
581self.Sjmp("JMP" , "_next") // JMP _next
582
583/* first element of an array */
584self.Link("_first_item") // _first_item:
585self.Emit("MOVQ", jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX
586self.Emit("SUBQ", jit.Imm(2), jit.Ptr(_ST, _ST_Sp)) // SUBQ $2, ST.Sp
587self.Emit("MOVQ", jit.Sib(_ST, _CX, 8, _ST_Vp - 8), _SI) // MOVQ ST.Vp[CX - 1], SI
588self.Emit("MOVQ", jit.Ptr(_SI, 8), _SI) // MOVQ 8(SI), SI
589self.Emit("MOVQ", _DX, jit.Sib(_ST, _CX, 8, _ST_Vp - 8)) // MOVQ DX, ST.Vp[CX - 1]
590self.Emit("MOVQ", _DX, jit.Sib(_ST, _CX, 8, _ST_Vp)) // MOVQ DX, ST.Vp[CX]
591self.Emit("MOVQ", _DX, jit.Ptr(_SI, 8)) // MOVQ DX, 8(SI)
592self.Sjmp("JMP" , "_next") // JMP _next
593
594/** V_OBJECT_END **/
595self.Link("_decode_V_OBJECT_END") // _decode_V_OBJECT_END:
596self.Emit("MOVL", jit.Imm(_S_omask_end), _DX) // MOVL _S_omask, DI
597self.Emit("MOVQ", jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX
598self.Emit("MOVQ", jit.Sib(_ST, _CX, 8, _ST_Vt), _AX) // MOVQ ST.Vt[CX], AX
599self.Emit("BTQ" , _AX, _DX)
600self.Sjmp("JNC" , "_invalid_char") // JNE _invalid_char
601self.Emit("XORL", _AX, _AX) // XORL AX, AX
602self.Emit("SUBQ", jit.Imm(1), jit.Ptr(_ST, _ST_Sp)) // SUBQ $1, ST.Sp
603self.Emit("MOVQ", _AX, jit.Sib(_ST, _CX, 8, _ST_Vp)) // MOVQ AX, ST.Vp[CX]
604self.Sjmp("JMP" , "_next") // JMP _next
605
606/* return from decoder */
607self.Link("_return") // _return:
608self.Emit("XORL", _EP, _EP) // XORL EP, EP
609self.Emit("MOVQ", _EP, jit.Ptr(_ST, _ST_Vp)) // MOVQ EP, ST.Vp[0]
610self.Link("_epilogue") // _epilogue:
611self.Emit("SUBQ", jit.Imm(_FsmOffset), _ST) // SUBQ _FsmOffset, _ST
612self.Emit("MOVQ", jit.Ptr(_SP, _VD_offs), _BP) // MOVQ _VD_offs(SP), BP
613self.Emit("ADDQ", jit.Imm(_VD_size), _SP) // ADDQ $_VD_size, SP
614self.Emit("RET") // RET
615
616/* array expand */
617self.Link("_array_more") // _array_more:
618self.Emit("MOVQ" , _T_eface, _AX) // MOVQ _T_eface, AX
619self.Emit("MOVOU", jit.Ptr(_SI, 0), _X0) // MOVOU (SI), X0
620self.Emit("MOVQ" , jit.Ptr(_SI, 16), _DX) // MOVQ 16(SI), DX
621self.Emit("MOVQ" , _AX, jit.Ptr(_SP, 0)) // MOVQ AX, (SP)
622self.Emit("MOVOU", _X0, jit.Ptr(_SP, 8)) // MOVOU X0, 8(SP)
623self.Emit("MOVQ" , _DX, jit.Ptr(_SP, 24)) // MOVQ DX, 24(SP)
624self.Emit("SHLQ" , jit.Imm(1), _DX) // SHLQ $1, DX
625self.Emit("MOVQ" , _DX, jit.Ptr(_SP, 32)) // MOVQ DX, 32(SP)
626self.call_go(_F_growslice) // CALL_GO runtime.growslice
627self.Emit("MOVQ" , jit.Ptr(_SP, 40), _DI) // MOVOU 40(SP), DI
628self.Emit("MOVQ" , jit.Ptr(_SP, 48), _DX) // MOVOU 48(SP), DX
629self.Emit("MOVQ" , jit.Ptr(_SP, 56), _AX) // MOVQ 56(SP), AX
630
631/* update the slice */
632self.Emit("MOVQ", jit.Ptr(_ST, _ST_Sp), _CX) // MOVQ ST.Sp, CX
633self.Emit("MOVQ", jit.Sib(_ST, _CX, 8, _ST_Vp), _SI) // MOVQ ST.Vp[CX], SI
634self.Emit("MOVQ", jit.Ptr(_SI, 8), _SI) // MOVQ 8(SI), SI
635self.Emit("MOVQ", _DX, jit.Ptr(_SI, 8)) // MOVQ DX, 8(SI)
636self.Emit("MOVQ", _AX, jit.Ptr(_SI, 16)) // MOVQ AX, 16(AX)
637self.WriteRecNotAX(8 , _DI, jit.Ptr(_SI, 0), false) // MOVQ R10, (SI)
638self.Sjmp("JMP" , "_array_append") // JMP _array_append
639
640/* copy string */
641self.Link("copy_string") // pointer: R8, length: AX, return addr: DI
642// self.Byte(0xcc)
643self.Emit("MOVQ", _R8, _VAR_cs_p)
644self.Emit("MOVQ", _AX, _VAR_cs_n)
645self.Emit("MOVQ", _DI, _VAR_cs_LR)
646self.Emit("MOVQ", _T_byte, _R8)
647self.Emit("MOVQ", _R8, jit.Ptr(_SP, 0))
648self.Emit("MOVQ", _AX, jit.Ptr(_SP, 8))
649self.Emit("MOVQ", _AX, jit.Ptr(_SP, 16))
650self.call_go(_F_makeslice)
651self.Emit("MOVQ", jit.Ptr(_SP, 24), _R8)
652self.Emit("MOVQ", _R8, _VAR_cs_d)
653self.Emit("MOVQ", _R8, jit.Ptr(_SP, 0))
654self.Emit("MOVQ", _VAR_cs_p, _R8)
655self.Emit("MOVQ", _R8, jit.Ptr(_SP, 8))
656self.Emit("MOVQ", _VAR_cs_n, _AX)
657self.Emit("MOVQ", _AX, jit.Ptr(_SP, 16))
658self.call_go(_F_memmove)
659self.Emit("MOVQ", _VAR_cs_d, _R8)
660self.Emit("MOVQ", _VAR_cs_n, _AX)
661self.Emit("MOVQ", _VAR_cs_LR, _DI)
662// self.Byte(0xcc)
663self.Rjmp("JMP", _DI)
664
665/* error handlers */
666self.Link("_stack_overflow")
667self.Emit("MOVL" , _E_recurse, _EP) // MOVQ _E_recurse, EP
668self.Sjmp("JMP" , "_error") // JMP _error
669self.Link("_vtype_error") // _vtype_error:
670self.Emit("MOVQ" , _DI, _IC) // MOVQ DI, IC
671self.Emit("MOVL" , _E_invalid, _EP) // MOVL _E_invalid, EP
672self.Sjmp("JMP" , "_error") // JMP _error
673self.Link("_invalid_char") // _invalid_char:
674self.Emit("SUBQ" , jit.Imm(1), _IC) // SUBQ $1, IC
675self.Emit("MOVL" , _E_invalid, _EP) // MOVL _E_invalid, EP
676self.Sjmp("JMP" , "_error") // JMP _error
677self.Link("_unquote_error") // _unquote_error:
678self.Emit("MOVQ" , _VAR_ss_Iv, _IC) // MOVQ ss.Iv, IC
679self.Emit("SUBQ" , jit.Imm(1), _IC) // SUBQ $1, IC
680self.Link("_parsing_error") // _parsing_error:
681self.Emit("NEGQ" , _AX) // NEGQ AX
682self.Emit("MOVQ" , _AX, _EP) // MOVQ AX, EP
683self.Link("_error") // _error:
684self.Emit("PXOR" , _X0, _X0) // PXOR X0, X0
685self.Emit("MOVOU", _X0, jit.Ptr(_VP, 0)) // MOVOU X0, (VP)
686self.Sjmp("JMP" , "_epilogue") // JMP _epilogue
687
688/* invalid value type, never returns */
689self.Link("_invalid_vtype")
690self.Emit("MOVQ", _AX, jit.Ptr(_SP, 0)) // MOVQ AX, (SP)
691self.call(_F_invalid_vtype) // CALL invalid_type
692self.Emit("UD2") // UD2
693
694/* switch jump table */
695self.Link("_switch_table") // _switch_table:
696self.Sref("_decode_V_EOF", 0) // SREF &_decode_V_EOF, $0
697self.Sref("_decode_V_NULL", -4) // SREF &_decode_V_NULL, $-4
698self.Sref("_decode_V_TRUE", -8) // SREF &_decode_V_TRUE, $-8
699self.Sref("_decode_V_FALSE", -12) // SREF &_decode_V_FALSE, $-12
700self.Sref("_decode_V_ARRAY", -16) // SREF &_decode_V_ARRAY, $-16
701self.Sref("_decode_V_OBJECT", -20) // SREF &_decode_V_OBJECT, $-20
702self.Sref("_decode_V_STRING", -24) // SREF &_decode_V_STRING, $-24
703self.Sref("_decode_V_DOUBLE", -28) // SREF &_decode_V_DOUBLE, $-28
704self.Sref("_decode_V_INTEGER", -32) // SREF &_decode_V_INTEGER, $-32
705self.Sref("_decode_V_KEY_SEP", -36) // SREF &_decode_V_KEY_SEP, $-36
706self.Sref("_decode_V_ELEM_SEP", -40) // SREF &_decode_V_ELEM_SEP, $-40
707self.Sref("_decode_V_ARRAY_END", -44) // SREF &_decode_V_ARRAY_END, $-44
708self.Sref("_decode_V_OBJECT_END", -48) // SREF &_decode_V_OBJECT_END, $-48
709
710/* fast character lookup table */
711self.Link("_decode_tab") // _decode_tab:
712self.Sref("_decode_V_EOF", 0) // SREF &_decode_V_EOF, $0
713
714/* generate rest of the tabs */
715for i := 1; i < 256; i++ {
716if to, ok := _R_tab[i]; ok {
717self.Sref(to, -int64(i) * 4)
718} else {
719self.Byte(0x00, 0x00, 0x00, 0x00)
720}
721}
722}
723
724/** Generic Decoder **/
725
726var (
727_subr_decode_value = new(_ValueDecoder).build()
728)
729
730//go:nosplit
731func invalid_vtype(vt types.ValueType) {
732throw(fmt.Sprintf("invalid value type: %d", vt))
733}
734