compiler.go raw
1 /*
2 * Copyright 2021 ByteDance Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package encoder
18
19 import (
20 "reflect"
21 "unsafe"
22
23 "github.com/bytedance/sonic/internal/encoder/ir"
24 "github.com/bytedance/sonic/internal/encoder/vars"
25 "github.com/bytedance/sonic/internal/encoder/vm"
26 "github.com/bytedance/sonic/internal/resolver"
27 "github.com/bytedance/sonic/internal/rt"
28 "github.com/bytedance/sonic/option"
29 )
30
31 func ForceUseVM() {
32 vm.SetCompiler(makeEncoderVM)
33 pretouchType = pretouchTypeVM
34 encodeTypedPointer = vm.EncodeTypedPointer
35 vars.UseVM = true
36 }
37
38 var encodeTypedPointer func(buf *[]byte, vt *rt.GoType, vp *unsafe.Pointer, sb *vars.Stack, fv uint64) error
39
40 func makeEncoderVM(vt *rt.GoType, ex ...interface{}) (interface{}, error) {
41 pp, err := NewCompiler().Compile(vt.Pack(), ex[0].(bool))
42 if err != nil {
43 return nil, err
44 }
45 return &pp, nil
46 }
47
48 var pretouchType func(_vt reflect.Type, opts option.CompileOptions, v uint8) (map[reflect.Type]uint8, error)
49
50 func pretouchTypeVM(_vt reflect.Type, opts option.CompileOptions, v uint8) (map[reflect.Type]uint8, error) {
51 /* compile function */
52 compiler := NewCompiler().apply(opts)
53
54 /* find or compile */
55 vt := rt.UnpackType(_vt)
56 if val := vars.GetProgram(vt); val != nil {
57 return nil, nil
58 } else if _, err := vars.ComputeProgram(vt, makeEncoderVM, v == 1); err == nil {
59 return compiler.rec, nil
60 } else {
61 return nil, err
62 }
63 }
64
65 func pretouchRec(vtm map[reflect.Type]uint8, opts option.CompileOptions) error {
66 if opts.RecursiveDepth < 0 || len(vtm) == 0 {
67 return nil
68 }
69 next := make(map[reflect.Type]uint8)
70 for vt, v := range vtm {
71 sub, err := pretouchType(vt, opts, v)
72 if err != nil {
73 return err
74 }
75 for svt, v := range sub {
76 next[svt] = v
77 }
78 }
79 opts.RecursiveDepth -= 1
80 return pretouchRec(next, opts)
81 }
82
83 type Compiler struct {
84 opts option.CompileOptions
85 pv bool
86 tab map[reflect.Type]bool
87 rec map[reflect.Type]uint8
88 }
89
90 func NewCompiler() *Compiler {
91 return &Compiler{
92 opts: option.DefaultCompileOptions(),
93 tab: map[reflect.Type]bool{},
94 rec: map[reflect.Type]uint8{},
95 }
96 }
97
98 func (self *Compiler) apply(opts option.CompileOptions) *Compiler {
99 self.opts = opts
100 if self.opts.RecursiveDepth > 0 {
101 self.rec = map[reflect.Type]uint8{}
102 }
103 return self
104 }
105
106 func (self *Compiler) rescue(ep *error) {
107 if val := recover(); val != nil {
108 if err, ok := val.(error); ok {
109 *ep = err
110 } else {
111 panic(val)
112 }
113 }
114 }
115
116 func (self *Compiler) Compile(vt reflect.Type, pv bool) (ret ir.Program, err error) {
117 defer self.rescue(&err)
118 self.compileOne(&ret, 0, vt, pv)
119 return
120 }
121
122 func (self *Compiler) compileOne(p *ir.Program, sp int, vt reflect.Type, pv bool) {
123 if self.tab[vt] {
124 p.Vp(ir.OP_recurse, vt, pv)
125 } else {
126 self.compileRec(p, sp, vt, pv)
127 }
128 }
129
130 func (self *Compiler) tryCompileMarshaler(p *ir.Program, vt reflect.Type, pv bool) bool {
131 pt := reflect.PtrTo(vt)
132
133 /* check for addressable `json.Marshaler` with pointer receiver */
134 if pv && pt.Implements(vars.JsonMarshalerType) {
135 addMarshalerOp(p, ir.OP_marshal_p, pt, vars.JsonMarshalerType)
136 return true
137 }
138
139 /* check for `json.Marshaler` */
140 if vt.Implements(vars.JsonMarshalerType) {
141 self.compileMarshaler(p, ir.OP_marshal, vt, vars.JsonMarshalerType)
142 return true
143 }
144
145 /* check for addressable `encoding.TextMarshaler` with pointer receiver */
146 if pv && pt.Implements(vars.EncodingTextMarshalerType) {
147 addMarshalerOp(p, ir.OP_marshal_text_p, pt, vars.EncodingTextMarshalerType)
148 return true
149 }
150
151 /* check for `encoding.TextMarshaler` */
152 if vt.Implements(vars.EncodingTextMarshalerType) {
153 self.compileMarshaler(p, ir.OP_marshal_text, vt, vars.EncodingTextMarshalerType)
154 return true
155 }
156
157 return false
158 }
159
160 func (self *Compiler) compileRec(p *ir.Program, sp int, vt reflect.Type, pv bool) {
161 pr := self.pv
162
163 if self.tryCompileMarshaler(p, vt, pv) {
164 return
165 }
166
167 /* enter the recursion, and compile the type */
168 self.pv = pv
169 self.tab[vt] = true
170 self.compileOps(p, sp, vt)
171
172 /* exit the recursion */
173 self.pv = pr
174 delete(self.tab, vt)
175 }
176
177 func (self *Compiler) compileOps(p *ir.Program, sp int, vt reflect.Type) {
178 switch vt.Kind() {
179 case reflect.Bool:
180 p.Add(ir.OP_bool)
181 case reflect.Int:
182 p.Add(ir.OP_int())
183 case reflect.Int8:
184 p.Add(ir.OP_i8)
185 case reflect.Int16:
186 p.Add(ir.OP_i16)
187 case reflect.Int32:
188 p.Add(ir.OP_i32)
189 case reflect.Int64:
190 p.Add(ir.OP_i64)
191 case reflect.Uint:
192 p.Add(ir.OP_uint())
193 case reflect.Uint8:
194 p.Add(ir.OP_u8)
195 case reflect.Uint16:
196 p.Add(ir.OP_u16)
197 case reflect.Uint32:
198 p.Add(ir.OP_u32)
199 case reflect.Uint64:
200 p.Add(ir.OP_u64)
201 case reflect.Uintptr:
202 p.Add(ir.OP_uintptr())
203 case reflect.Float32:
204 p.Add(ir.OP_f32)
205 case reflect.Float64:
206 p.Add(ir.OP_f64)
207 case reflect.String:
208 self.compileString(p, vt)
209 case reflect.Array:
210 self.compileArray(p, sp, vt.Elem(), vt.Len())
211 case reflect.Interface:
212 self.compileInterface(p, vt)
213 case reflect.Map:
214 self.compileMap(p, sp, vt)
215 case reflect.Ptr:
216 self.compilePtr(p, sp, vt.Elem())
217 case reflect.Slice:
218 self.compileSlice(p, sp, vt.Elem())
219 case reflect.Struct:
220 self.compileStruct(p, sp, vt)
221 default:
222 self.compileUnsupportedType(p, vt)
223 }
224 }
225
226 func (self *Compiler) compileNil(p *ir.Program, sp int, vt reflect.Type, nil_op ir.Op, fn func(*ir.Program, int, reflect.Type)) {
227 x := p.PC()
228 p.Add(ir.OP_is_nil)
229 fn(p, sp, vt)
230 e := p.PC()
231 p.Add(ir.OP_goto)
232 p.Pin(x)
233 p.Add(nil_op)
234 p.Pin(e)
235 }
236
237 func (self *Compiler) compilePtr(p *ir.Program, sp int, vt reflect.Type) {
238 self.compileNil(p, sp, vt, ir.OP_null, self.compilePtrBody)
239 }
240
241 func (self *Compiler) compilePtrBody(p *ir.Program, sp int, vt reflect.Type) {
242 p.Tag(sp)
243 p.Add(ir.OP_save)
244 p.Add(ir.OP_deref)
245 self.compileOne(p, sp+1, vt, true)
246 p.Add(ir.OP_drop)
247 }
248
249 func (self *Compiler) compileMap(p *ir.Program, sp int, vt reflect.Type) {
250 self.compileNil(p, sp, vt, ir.OP_empty_obj, self.compileMapBody)
251 }
252
253 func (self *Compiler) compileMapBody(p *ir.Program, sp int, vt reflect.Type) {
254 p.Tag(sp + 1)
255 p.Int(ir.OP_byte, '{')
256 e := p.PC()
257 p.Add(ir.OP_is_zero_map)
258 p.Add(ir.OP_save)
259 p.Rtt(ir.OP_map_iter, vt)
260 p.Add(ir.OP_save)
261 i := p.PC()
262 p.Add(ir.OP_map_check_key)
263 u := p.PC()
264 p.Add(ir.OP_map_write_key)
265 self.compileMapBodyKey(p, vt.Key())
266 p.Pin(u)
267 p.Int(ir.OP_byte, ':')
268 p.Add(ir.OP_map_value_next)
269 self.compileOne(p, sp+2, vt.Elem(), false)
270 j := p.PC()
271 p.Add(ir.OP_map_check_key)
272 p.Int(ir.OP_byte, ',')
273 v := p.PC()
274 p.Add(ir.OP_map_write_key)
275 self.compileMapBodyKey(p, vt.Key())
276 p.Pin(v)
277 p.Int(ir.OP_byte, ':')
278 p.Add(ir.OP_map_value_next)
279 self.compileOne(p, sp+2, vt.Elem(), false)
280 p.Int(ir.OP_goto, j)
281 p.Pin(i)
282 p.Pin(j)
283 p.Add(ir.OP_map_stop)
284 p.Add(ir.OP_drop_2)
285 p.Pin(e)
286 p.Int(ir.OP_byte, '}')
287 }
288
289 func (self *Compiler) compileMapBodyKey(p *ir.Program, vk reflect.Type) {
290 if !vk.Implements(vars.EncodingTextMarshalerType) {
291 self.compileMapBodyTextKey(p, vk)
292 } else {
293 self.compileMapBodyUtextKey(p, vk)
294 }
295 }
296
297 func (self *Compiler) compileMapBodyTextKey(p *ir.Program, vk reflect.Type) {
298 switch vk.Kind() {
299 case reflect.Invalid:
300 panic("map key is nil")
301 case reflect.Bool:
302 p.Key(ir.OP_bool)
303 case reflect.Int:
304 p.Key(ir.OP_int())
305 case reflect.Int8:
306 p.Key(ir.OP_i8)
307 case reflect.Int16:
308 p.Key(ir.OP_i16)
309 case reflect.Int32:
310 p.Key(ir.OP_i32)
311 case reflect.Int64:
312 p.Key(ir.OP_i64)
313 case reflect.Uint:
314 p.Key(ir.OP_uint())
315 case reflect.Uint8:
316 p.Key(ir.OP_u8)
317 case reflect.Uint16:
318 p.Key(ir.OP_u16)
319 case reflect.Uint32:
320 p.Key(ir.OP_u32)
321 case reflect.Uint64:
322 p.Key(ir.OP_u64)
323 case reflect.Uintptr:
324 p.Key(ir.OP_uintptr())
325 case reflect.Float32:
326 p.Key(ir.OP_f32)
327 case reflect.Float64:
328 p.Key(ir.OP_f64)
329 case reflect.String:
330 self.compileString(p, vk)
331 default:
332 panic(vars.Error_type(vk))
333 }
334 }
335
336 func (self *Compiler) compileMapBodyUtextKey(p *ir.Program, vk reflect.Type) {
337 if vk.Kind() != reflect.Ptr {
338 addMarshalerOp(p, ir.OP_marshal_text, vk, vars.EncodingTextMarshalerType)
339 } else {
340 self.compileMapBodyUtextPtr(p, vk)
341 }
342 }
343
344 func (self *Compiler) compileMapBodyUtextPtr(p *ir.Program, vk reflect.Type) {
345 i := p.PC()
346 p.Add(ir.OP_is_nil)
347 addMarshalerOp(p, ir.OP_marshal_text, vk, vars.EncodingTextMarshalerType)
348 j := p.PC()
349 p.Add(ir.OP_goto)
350 p.Pin(i)
351 p.Str(ir.OP_text, "\"\"")
352 p.Pin(j)
353 }
354
355 func (self *Compiler) compileSlice(p *ir.Program, sp int, vt reflect.Type) {
356 self.compileNil(p, sp, vt, ir.OP_empty_arr, self.compileSliceBody)
357 }
358
359 func (self *Compiler) compileSliceBody(p *ir.Program, sp int, vt reflect.Type) {
360 if vars.IsSimpleByte(vt) {
361 p.Add(ir.OP_bin)
362 } else {
363 self.compileSliceArray(p, sp, vt)
364 }
365 }
366
367 func (self *Compiler) compileSliceArray(p *ir.Program, sp int, vt reflect.Type) {
368 p.Tag(sp)
369 p.Int(ir.OP_byte, '[')
370 e := p.PC()
371 p.Add(ir.OP_is_nil)
372 p.Add(ir.OP_save)
373 p.Add(ir.OP_slice_len)
374 i := p.PC()
375 p.Rtt(ir.OP_slice_next, vt)
376 self.compileOne(p, sp+1, vt, true)
377 j := p.PC()
378 p.Rtt(ir.OP_slice_next, vt)
379 p.Int(ir.OP_byte, ',')
380 self.compileOne(p, sp+1, vt, true)
381 p.Int(ir.OP_goto, j)
382 p.Pin(i)
383 p.Pin(j)
384 p.Add(ir.OP_drop)
385 p.Pin(e)
386 p.Int(ir.OP_byte, ']')
387 }
388
389 func (self *Compiler) compileArray(p *ir.Program, sp int, vt reflect.Type, nb int) {
390 p.Tag(sp)
391 p.Int(ir.OP_byte, '[')
392 p.Add(ir.OP_save)
393
394 /* first item */
395 if nb != 0 {
396 self.compileOne(p, sp+1, vt, self.pv)
397 p.Add(ir.OP_load)
398 }
399
400 /* remaining items */
401 for i := 1; i < nb; i++ {
402 p.Int(ir.OP_byte, ',')
403 p.Int(ir.OP_index, i*int(vt.Size()))
404 self.compileOne(p, sp+1, vt, self.pv)
405 p.Add(ir.OP_load)
406 }
407
408 /* end of array */
409 p.Add(ir.OP_drop)
410 p.Int(ir.OP_byte, ']')
411 }
412
413 func (self *Compiler) compileString(p *ir.Program, vt reflect.Type) {
414 if vt != vars.JsonNumberType {
415 p.Add(ir.OP_str)
416 } else {
417 p.Add(ir.OP_number)
418 }
419 }
420
421 func (self *Compiler) compileStruct(p *ir.Program, sp int, vt reflect.Type) {
422 if sp >= self.opts.MaxInlineDepth || p.PC() >= vars.MAX_ILBUF || (sp > 0 && vt.NumField() >= vars.MAX_FIELDS) {
423 p.Vp(ir.OP_recurse, vt, self.pv)
424 if self.opts.RecursiveDepth > 0 {
425 if self.pv {
426 self.rec[vt] = 1
427 } else {
428 self.rec[vt] = 0
429 }
430 }
431 } else {
432 self.compileStructBody(p, sp, vt)
433 }
434 }
435
436 func (self *Compiler) compileStructBody(p *ir.Program, sp int, vt reflect.Type) {
437 p.Tag(sp)
438 p.Int(ir.OP_byte, '{')
439 p.Add(ir.OP_save)
440 p.Add(ir.OP_cond_set)
441
442 /* compile each field */
443 fvs := resolver.ResolveStruct(vt)
444 for i, fv := range fvs {
445 var s []int
446 var o resolver.Offset
447
448 /* "omitempty" for arrays */
449 if fv.Type.Kind() == reflect.Array {
450 if fv.Type.Len() == 0 && (fv.Opts&resolver.F_omitempty) != 0 {
451 continue
452 }
453 }
454
455 /* index to the field */
456 for _, o = range fv.Path {
457 if p.Int(ir.OP_index, int(o.Size)); o.Kind == resolver.F_deref {
458 s = append(s, p.PC())
459 p.Add(ir.OP_is_nil)
460 p.Add(ir.OP_deref)
461 }
462 }
463
464 /* check for "omitempty" option */
465 if fv.Type.Kind() != reflect.Struct && fv.Type.Kind() != reflect.Array && (fv.Opts&resolver.F_omitempty) != 0 {
466 s = append(s, p.PC())
467 self.compileStructFieldEmpty(p, fv.Type)
468 }
469 /* check for "omitzero" option */
470 if fv.Opts&resolver.F_omitzero != 0 {
471 s = append(s, p.PC())
472 p.VField(ir.OP_is_zero, &fvs[i])
473 }
474
475 /* add the comma if not the first element */
476 i := p.PC()
477 p.Add(ir.OP_cond_testc)
478 p.Int(ir.OP_byte, ',')
479 p.Pin(i)
480
481 /* compile the key and value */
482 ft := fv.Type
483 p.Str(ir.OP_text, Quote(fv.Name)+":")
484
485 /* check for "stringnize" option */
486 if (fv.Opts & resolver.F_stringize) == 0 {
487 self.compileOne(p, sp+1, ft, self.pv)
488 } else {
489 self.compileStructFieldStr(p, sp+1, ft)
490 }
491
492 /* patch the skipping jumps and reload the struct pointer */
493 p.Rel(s)
494 p.Add(ir.OP_load)
495 }
496
497 /* end of object */
498 p.Add(ir.OP_drop)
499 p.Int(ir.OP_byte, '}')
500 }
501
502 func (self *Compiler) compileStructFieldStr(p *ir.Program, sp int, vt reflect.Type) {
503 // NOTICE: according to encoding/json, Marshaler type has higher priority than string option
504 // see issue:
505 if self.tryCompileMarshaler(p, vt, self.pv) {
506 return
507 }
508
509 pc := -1
510 ft := vt
511 sv := false
512
513 /* dereference the pointer if needed */
514 if ft.Kind() == reflect.Ptr {
515 ft = ft.Elem()
516 }
517
518 /* check if it can be stringized */
519 switch ft.Kind() {
520 case reflect.Bool:
521 sv = true
522 case reflect.Int:
523 sv = true
524 case reflect.Int8:
525 sv = true
526 case reflect.Int16:
527 sv = true
528 case reflect.Int32:
529 sv = true
530 case reflect.Int64:
531 sv = true
532 case reflect.Uint:
533 sv = true
534 case reflect.Uint8:
535 sv = true
536 case reflect.Uint16:
537 sv = true
538 case reflect.Uint32:
539 sv = true
540 case reflect.Uint64:
541 sv = true
542 case reflect.Uintptr:
543 sv = true
544 case reflect.Float32:
545 sv = true
546 case reflect.Float64:
547 sv = true
548 case reflect.String:
549 sv = true
550 }
551
552 /* if it's not, ignore the "string" and follow the regular path */
553 if !sv {
554 self.compileOne(p, sp, vt, self.pv)
555 return
556 }
557
558 /* dereference the pointer */
559 if vt.Kind() == reflect.Ptr {
560 pc = p.PC()
561 vt = vt.Elem()
562 p.Add(ir.OP_is_nil)
563 p.Add(ir.OP_deref)
564 }
565
566 /* special case of a double-quoted string */
567 if ft != vars.JsonNumberType && ft.Kind() == reflect.String {
568 p.Add(ir.OP_quote)
569 } else {
570 self.compileStructFieldQuoted(p, sp, vt)
571 }
572
573 /* the "null" case of the pointer */
574 if pc != -1 {
575 e := p.PC()
576 p.Add(ir.OP_goto)
577 p.Pin(pc)
578 p.Add(ir.OP_null)
579 p.Pin(e)
580 }
581 }
582
583 func (self *Compiler) compileStructFieldEmpty(p *ir.Program, vt reflect.Type) {
584 switch vt.Kind() {
585 case reflect.Bool:
586 p.Add(ir.OP_is_zero_1)
587 case reflect.Int:
588 p.Add(ir.OP_is_zero_ints())
589 case reflect.Int8:
590 p.Add(ir.OP_is_zero_1)
591 case reflect.Int16:
592 p.Add(ir.OP_is_zero_2)
593 case reflect.Int32:
594 p.Add(ir.OP_is_zero_4)
595 case reflect.Int64:
596 p.Add(ir.OP_is_zero_8)
597 case reflect.Uint:
598 p.Add(ir.OP_is_zero_ints())
599 case reflect.Uint8:
600 p.Add(ir.OP_is_zero_1)
601 case reflect.Uint16:
602 p.Add(ir.OP_is_zero_2)
603 case reflect.Uint32:
604 p.Add(ir.OP_is_zero_4)
605 case reflect.Uint64:
606 p.Add(ir.OP_is_zero_8)
607 case reflect.Uintptr:
608 p.Add(ir.OP_is_nil)
609 case reflect.Float32:
610 p.Add(ir.OP_is_zero_4)
611 case reflect.Float64:
612 p.Add(ir.OP_is_zero_8)
613 case reflect.String:
614 p.Add(ir.OP_is_nil_p1)
615 case reflect.Interface:
616 p.Add(ir.OP_is_nil)
617 case reflect.Map:
618 p.Add(ir.OP_is_zero_map)
619 case reflect.Ptr:
620 p.Add(ir.OP_is_nil)
621 case reflect.Slice:
622 p.Add(ir.OP_is_nil_p1)
623 default:
624 panic(vars.Error_type(vt))
625 }
626 }
627
628 func (self *Compiler) compileStructFieldQuoted(p *ir.Program, sp int, vt reflect.Type) {
629 p.Int(ir.OP_byte, '"')
630 self.compileOne(p, sp, vt, self.pv)
631 p.Int(ir.OP_byte, '"')
632 }
633
634 func (self *Compiler) compileInterface(p *ir.Program, vt reflect.Type) {
635 /* iface and efaces are different */
636 if vt.NumMethod() == 0 {
637 p.Add(ir.OP_eface)
638 return
639 }
640
641 x := p.PC()
642 p.Add(ir.OP_is_nil_p1)
643 p.Add(ir.OP_iface)
644
645 /* the "null" value */
646 e := p.PC()
647 p.Add(ir.OP_goto)
648 p.Pin(x)
649 p.Add(ir.OP_null)
650 p.Pin(e)
651 }
652
653 func (self *Compiler) compileUnsupportedType(p *ir.Program, vt reflect.Type) {
654 p.Rtt(ir.OP_unsupported, vt)
655 }
656
657
658 func (self *Compiler) compileMarshaler(p *ir.Program, op ir.Op, vt reflect.Type, mt reflect.Type) {
659 pc := p.PC()
660 vk := vt.Kind()
661
662 /* direct receiver */
663 if vk != reflect.Ptr {
664 addMarshalerOp(p, op, vt, mt)
665 return
666 }
667 /* value receiver with a pointer type, check for nil before calling the marshaler */
668 p.Add(ir.OP_is_nil)
669
670 addMarshalerOp(p, op, vt, mt)
671
672 i := p.PC()
673 p.Add(ir.OP_goto)
674 p.Pin(pc)
675 p.Add(ir.OP_null)
676 p.Pin(i)
677 }
678
679 func addMarshalerOp(p *ir.Program, op ir.Op, vt reflect.Type, mt reflect.Type) {
680 if vars.UseVM {
681 itab := rt.GetItab(rt.IfaceType(rt.UnpackType(mt)), rt.UnpackType(vt), true)
682 p.Vtab(op, vt, itab)
683 } else {
684 // OPT: get itab here
685 p.Rtt(op, vt)
686 }
687 }
688