summaryrefslogtreecommitdiff
path: root/vendor/github.com/bytedance/sonic/internal/encoder/compiler.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/bytedance/sonic/internal/encoder/compiler.go')
-rw-r--r--vendor/github.com/bytedance/sonic/internal/encoder/compiler.go1517
1 files changed, 654 insertions, 863 deletions
diff --git a/vendor/github.com/bytedance/sonic/internal/encoder/compiler.go b/vendor/github.com/bytedance/sonic/internal/encoder/compiler.go
index ca0be8f40..902fbc98b 100644
--- a/vendor/github.com/bytedance/sonic/internal/encoder/compiler.go
+++ b/vendor/github.com/bytedance/sonic/internal/encoder/compiler.go
@@ -17,869 +17,660 @@
package encoder
import (
- `fmt`
- `reflect`
- `strconv`
- `strings`
- `unsafe`
-
- `github.com/bytedance/sonic/internal/resolver`
- `github.com/bytedance/sonic/internal/rt`
- `github.com/bytedance/sonic/option`
+ "reflect"
+ "unsafe"
+
+ "github.com/bytedance/sonic/internal/encoder/ir"
+ "github.com/bytedance/sonic/internal/encoder/vars"
+ "github.com/bytedance/sonic/internal/encoder/vm"
+ "github.com/bytedance/sonic/internal/resolver"
+ "github.com/bytedance/sonic/internal/rt"
+ "github.com/bytedance/sonic/option"
)
-type _Op uint8
-
-const (
- _OP_null _Op = iota + 1
- _OP_empty_arr
- _OP_empty_obj
- _OP_bool
- _OP_i8
- _OP_i16
- _OP_i32
- _OP_i64
- _OP_u8
- _OP_u16
- _OP_u32
- _OP_u64
- _OP_f32
- _OP_f64
- _OP_str
- _OP_bin
- _OP_quote
- _OP_number
- _OP_eface
- _OP_iface
- _OP_byte
- _OP_text
- _OP_deref
- _OP_index
- _OP_load
- _OP_save
- _OP_drop
- _OP_drop_2
- _OP_recurse
- _OP_is_nil
- _OP_is_nil_p1
- _OP_is_zero_1
- _OP_is_zero_2
- _OP_is_zero_4
- _OP_is_zero_8
- _OP_is_zero_map
- _OP_goto
- _OP_map_iter
- _OP_map_stop
- _OP_map_check_key
- _OP_map_write_key
- _OP_map_value_next
- _OP_slice_len
- _OP_slice_next
- _OP_marshal
- _OP_marshal_p
- _OP_marshal_text
- _OP_marshal_text_p
- _OP_cond_set
- _OP_cond_testc
-)
-
-const (
- _INT_SIZE = 32 << (^uint(0) >> 63)
- _PTR_SIZE = 32 << (^uintptr(0) >> 63)
- _PTR_BYTE = unsafe.Sizeof(uintptr(0))
-)
-
-const (
- _MAX_ILBUF = 100000 // cutoff at 100k of IL instructions
- _MAX_FIELDS = 50 // cutoff at 50 fields struct
-)
-
-var _OpNames = [256]string {
- _OP_null : "null",
- _OP_empty_arr : "empty_arr",
- _OP_empty_obj : "empty_obj",
- _OP_bool : "bool",
- _OP_i8 : "i8",
- _OP_i16 : "i16",
- _OP_i32 : "i32",
- _OP_i64 : "i64",
- _OP_u8 : "u8",
- _OP_u16 : "u16",
- _OP_u32 : "u32",
- _OP_u64 : "u64",
- _OP_f32 : "f32",
- _OP_f64 : "f64",
- _OP_str : "str",
- _OP_bin : "bin",
- _OP_quote : "quote",
- _OP_number : "number",
- _OP_eface : "eface",
- _OP_iface : "iface",
- _OP_byte : "byte",
- _OP_text : "text",
- _OP_deref : "deref",
- _OP_index : "index",
- _OP_load : "load",
- _OP_save : "save",
- _OP_drop : "drop",
- _OP_drop_2 : "drop_2",
- _OP_recurse : "recurse",
- _OP_is_nil : "is_nil",
- _OP_is_nil_p1 : "is_nil_p1",
- _OP_is_zero_1 : "is_zero_1",
- _OP_is_zero_2 : "is_zero_2",
- _OP_is_zero_4 : "is_zero_4",
- _OP_is_zero_8 : "is_zero_8",
- _OP_is_zero_map : "is_zero_map",
- _OP_goto : "goto",
- _OP_map_iter : "map_iter",
- _OP_map_stop : "map_stop",
- _OP_map_check_key : "map_check_key",
- _OP_map_write_key : "map_write_key",
- _OP_map_value_next : "map_value_next",
- _OP_slice_len : "slice_len",
- _OP_slice_next : "slice_next",
- _OP_marshal : "marshal",
- _OP_marshal_p : "marshal_p",
- _OP_marshal_text : "marshal_text",
- _OP_marshal_text_p : "marshal_text_p",
- _OP_cond_set : "cond_set",
- _OP_cond_testc : "cond_testc",
-}
-
-func (self _Op) String() string {
- if ret := _OpNames[self]; ret != "" {
- return ret
- } else {
- return "<invalid>"
- }
-}
-
-func _OP_int() _Op {
- switch _INT_SIZE {
- case 32: return _OP_i32
- case 64: return _OP_i64
- default: panic("unsupported int size")
- }
-}
-
-func _OP_uint() _Op {
- switch _INT_SIZE {
- case 32: return _OP_u32
- case 64: return _OP_u64
- default: panic("unsupported uint size")
- }
-}
-
-func _OP_uintptr() _Op {
- switch _PTR_SIZE {
- case 32: return _OP_u32
- case 64: return _OP_u64
- default: panic("unsupported pointer size")
- }
-}
-
-func _OP_is_zero_ints() _Op {
- switch _INT_SIZE {
- case 32: return _OP_is_zero_4
- case 64: return _OP_is_zero_8
- default: panic("unsupported integer size")
- }
-}
-
-type _Instr struct {
- u uint64 // union {op: 8, _: 8, vi: 48}, vi maybe int or len(str)
- p unsafe.Pointer // maybe GoString.Ptr, or *GoType
-}
-
-func packOp(op _Op) uint64 {
- return uint64(op) << 56
-}
-
-func newInsOp(op _Op) _Instr {
- return _Instr{u: packOp(op)}
-}
-
-func newInsVi(op _Op, vi int) _Instr {
- return _Instr{u: packOp(op) | rt.PackInt(vi)}
-}
-
-func newInsVs(op _Op, vs string) _Instr {
- return _Instr {
- u: packOp(op) | rt.PackInt(len(vs)),
- p: (*rt.GoString)(unsafe.Pointer(&vs)).Ptr,
- }
-}
-
-func newInsVt(op _Op, vt reflect.Type) _Instr {
- return _Instr {
- u: packOp(op),
- p: unsafe.Pointer(rt.UnpackType(vt)),
- }
-}
-
-func newInsVp(op _Op, vt reflect.Type, pv bool) _Instr {
- i := 0
- if pv {
- i = 1
- }
- return _Instr {
- u: packOp(op) | rt.PackInt(i),
- p: unsafe.Pointer(rt.UnpackType(vt)),
- }
-}
-
-func (self _Instr) op() _Op {
- return _Op(self.u >> 56)
-}
-
-func (self _Instr) vi() int {
- return rt.UnpackInt(self.u)
-}
-
-func (self _Instr) vf() uint8 {
- return (*rt.GoType)(self.p).KindFlags
-}
-
-func (self _Instr) vs() (v string) {
- (*rt.GoString)(unsafe.Pointer(&v)).Ptr = self.p
- (*rt.GoString)(unsafe.Pointer(&v)).Len = self.vi()
- return
-}
-
-func (self _Instr) vk() reflect.Kind {
- return (*rt.GoType)(self.p).Kind()
-}
-
-func (self _Instr) vt() reflect.Type {
- return (*rt.GoType)(self.p).Pack()
-}
-
-func (self _Instr) vp() (vt reflect.Type, pv bool) {
- return (*rt.GoType)(self.p).Pack(), rt.UnpackInt(self.u) == 1
-}
-
-func (self _Instr) i64() int64 {
- return int64(self.vi())
-}
-
-func (self _Instr) vlen() int {
- return int((*rt.GoType)(self.p).Size)
-}
-
-func (self _Instr) isBranch() bool {
- switch self.op() {
- case _OP_goto : fallthrough
- case _OP_is_nil : fallthrough
- case _OP_is_nil_p1 : fallthrough
- case _OP_is_zero_1 : fallthrough
- case _OP_is_zero_2 : fallthrough
- case _OP_is_zero_4 : fallthrough
- case _OP_is_zero_8 : fallthrough
- case _OP_map_check_key : fallthrough
- case _OP_map_write_key : fallthrough
- case _OP_slice_next : fallthrough
- case _OP_cond_testc : return true
- default : return false
- }
-}
-
-func (self _Instr) disassemble() string {
- switch self.op() {
- case _OP_byte : return fmt.Sprintf("%-18s%s", self.op().String(), strconv.QuoteRune(rune(self.vi())))
- case _OP_text : return fmt.Sprintf("%-18s%s", self.op().String(), strconv.Quote(self.vs()))
- case _OP_index : return fmt.Sprintf("%-18s%d", self.op().String(), self.vi())
- case _OP_recurse : fallthrough
- case _OP_map_iter : fallthrough
- case _OP_marshal : fallthrough
- case _OP_marshal_p : fallthrough
- case _OP_marshal_text : fallthrough
- case _OP_marshal_text_p : return fmt.Sprintf("%-18s%s", self.op().String(), self.vt())
- case _OP_goto : fallthrough
- case _OP_is_nil : fallthrough
- case _OP_is_nil_p1 : fallthrough
- case _OP_is_zero_1 : fallthrough
- case _OP_is_zero_2 : fallthrough
- case _OP_is_zero_4 : fallthrough
- case _OP_is_zero_8 : fallthrough
- case _OP_is_zero_map : fallthrough
- case _OP_cond_testc : fallthrough
- case _OP_map_check_key : fallthrough
- case _OP_map_write_key : return fmt.Sprintf("%-18sL_%d", self.op().String(), self.vi())
- case _OP_slice_next : return fmt.Sprintf("%-18sL_%d, %s", self.op().String(), self.vi(), self.vt())
- default : return self.op().String()
- }
-}
-
-type (
- _Program []_Instr
-)
-
-func (self _Program) pc() int {
- return len(self)
-}
-
-func (self _Program) tag(n int) {
- if n >= _MaxStack {
- panic("type nesting too deep")
- }
-}
-
-func (self _Program) pin(i int) {
- v := &self[i]
- v.u &= 0xffff000000000000
- v.u |= rt.PackInt(self.pc())
-}
-
-func (self _Program) rel(v []int) {
- for _, i := range v {
- self.pin(i)
- }
-}
-
-func (self *_Program) add(op _Op) {
- *self = append(*self, newInsOp(op))
-}
-
-func (self *_Program) key(op _Op) {
- *self = append(*self,
- newInsVi(_OP_byte, '"'),
- newInsOp(op),
- newInsVi(_OP_byte, '"'),
- )
-}
-
-func (self *_Program) int(op _Op, vi int) {
- *self = append(*self, newInsVi(op, vi))
-}
-
-func (self *_Program) str(op _Op, vs string) {
- *self = append(*self, newInsVs(op, vs))
-}
-
-func (self *_Program) rtt(op _Op, vt reflect.Type) {
- *self = append(*self, newInsVt(op, vt))
-}
-
-func (self *_Program) vp(op _Op, vt reflect.Type, pv bool) {
- *self = append(*self, newInsVp(op, vt, pv))
-}
-
-func (self _Program) disassemble() string {
- nb := len(self)
- tab := make([]bool, nb + 1)
- ret := make([]string, 0, nb + 1)
-
- /* prescan to get all the labels */
- for _, ins := range self {
- if ins.isBranch() {
- tab[ins.vi()] = true
- }
- }
-
- /* disassemble each instruction */
- for i, ins := range self {
- if !tab[i] {
- ret = append(ret, "\t" + ins.disassemble())
- } else {
- ret = append(ret, fmt.Sprintf("L_%d:\n\t%s", i, ins.disassemble()))
- }
- }
-
- /* add the last label, if needed */
- if tab[nb] {
- ret = append(ret, fmt.Sprintf("L_%d:", nb))
- }
-
- /* add an "end" indicator, and join all the strings */
- return strings.Join(append(ret, "\tend"), "\n")
-}
-
-type _Compiler struct {
- opts option.CompileOptions
- pv bool
- tab map[reflect.Type]bool
- rec map[reflect.Type]uint8
-}
-
-func newCompiler() *_Compiler {
- return &_Compiler {
- opts: option.DefaultCompileOptions(),
- tab: map[reflect.Type]bool{},
- rec: map[reflect.Type]uint8{},
- }
-}
-
-func (self *_Compiler) apply(opts option.CompileOptions) *_Compiler {
- self.opts = opts
- if self.opts.RecursiveDepth > 0 {
- self.rec = map[reflect.Type]uint8{}
- }
- return self
-}
-
-func (self *_Compiler) rescue(ep *error) {
- if val := recover(); val != nil {
- if err, ok := val.(error); ok {
- *ep = err
- } else {
- panic(val)
- }
- }
-}
-
-func (self *_Compiler) compile(vt reflect.Type, pv bool) (ret _Program, err error) {
- defer self.rescue(&err)
- self.compileOne(&ret, 0, vt, pv)
- return
-}
-
-func (self *_Compiler) compileOne(p *_Program, sp int, vt reflect.Type, pv bool) {
- if self.tab[vt] {
- p.vp(_OP_recurse, vt, pv)
- } else {
- self.compileRec(p, sp, vt, pv)
- }
-}
-
-func (self *_Compiler) compileRec(p *_Program, sp int, vt reflect.Type, pv bool) {
- pr := self.pv
- pt := reflect.PtrTo(vt)
-
- /* check for addressable `json.Marshaler` with pointer receiver */
- if pv && pt.Implements(jsonMarshalerType) {
- p.rtt(_OP_marshal_p, pt)
- return
- }
-
- /* check for `json.Marshaler` */
- if vt.Implements(jsonMarshalerType) {
- self.compileMarshaler(p, _OP_marshal, vt, jsonMarshalerType)
- return
- }
-
- /* check for addressable `encoding.TextMarshaler` with pointer receiver */
- if pv && pt.Implements(encodingTextMarshalerType) {
- p.rtt(_OP_marshal_text_p, pt)
- return
- }
-
- /* check for `encoding.TextMarshaler` */
- if vt.Implements(encodingTextMarshalerType) {
- self.compileMarshaler(p, _OP_marshal_text, vt, encodingTextMarshalerType)
- return
- }
-
- /* enter the recursion, and compile the type */
- self.pv = pv
- self.tab[vt] = true
- self.compileOps(p, sp, vt)
-
- /* exit the recursion */
- self.pv = pr
- delete(self.tab, vt)
-}
-
-func (self *_Compiler) compileOps(p *_Program, sp int, vt reflect.Type) {
- switch vt.Kind() {
- case reflect.Bool : p.add(_OP_bool)
- case reflect.Int : p.add(_OP_int())
- case reflect.Int8 : p.add(_OP_i8)
- case reflect.Int16 : p.add(_OP_i16)
- case reflect.Int32 : p.add(_OP_i32)
- case reflect.Int64 : p.add(_OP_i64)
- case reflect.Uint : p.add(_OP_uint())
- case reflect.Uint8 : p.add(_OP_u8)
- case reflect.Uint16 : p.add(_OP_u16)
- case reflect.Uint32 : p.add(_OP_u32)
- case reflect.Uint64 : p.add(_OP_u64)
- case reflect.Uintptr : p.add(_OP_uintptr())
- case reflect.Float32 : p.add(_OP_f32)
- case reflect.Float64 : p.add(_OP_f64)
- case reflect.String : self.compileString (p, vt)
- case reflect.Array : self.compileArray (p, sp, vt.Elem(), vt.Len())
- case reflect.Interface : self.compileInterface (p, vt)
- case reflect.Map : self.compileMap (p, sp, vt)
- case reflect.Ptr : self.compilePtr (p, sp, vt.Elem())
- case reflect.Slice : self.compileSlice (p, sp, vt.Elem())
- case reflect.Struct : self.compileStruct (p, sp, vt)
- default : panic (error_type(vt))
- }
-}
-
-func (self *_Compiler) compileNil(p *_Program, sp int, vt reflect.Type, nil_op _Op, fn func(*_Program, int, reflect.Type)) {
- x := p.pc()
- p.add(_OP_is_nil)
- fn(p, sp, vt)
- e := p.pc()
- p.add(_OP_goto)
- p.pin(x)
- p.add(nil_op)
- p.pin(e)
-}
-
-func (self *_Compiler) compilePtr(p *_Program, sp int, vt reflect.Type) {
- self.compileNil(p, sp, vt, _OP_null, self.compilePtrBody)
-}
-
-func (self *_Compiler) compilePtrBody(p *_Program, sp int, vt reflect.Type) {
- p.tag(sp)
- p.add(_OP_save)
- p.add(_OP_deref)
- self.compileOne(p, sp + 1, vt, true)
- p.add(_OP_drop)
-}
-
-func (self *_Compiler) compileMap(p *_Program, sp int, vt reflect.Type) {
- self.compileNil(p, sp, vt, _OP_empty_obj, self.compileMapBody)
-}
-
-func (self *_Compiler) compileMapBody(p *_Program, sp int, vt reflect.Type) {
- p.tag(sp + 1)
- p.int(_OP_byte, '{')
- p.add(_OP_save)
- p.rtt(_OP_map_iter, vt)
- p.add(_OP_save)
- i := p.pc()
- p.add(_OP_map_check_key)
- u := p.pc()
- p.add(_OP_map_write_key)
- self.compileMapBodyKey(p, vt.Key())
- p.pin(u)
- p.int(_OP_byte, ':')
- p.add(_OP_map_value_next)
- self.compileOne(p, sp + 2, vt.Elem(), false)
- j := p.pc()
- p.add(_OP_map_check_key)
- p.int(_OP_byte, ',')
- v := p.pc()
- p.add(_OP_map_write_key)
- self.compileMapBodyKey(p, vt.Key())
- p.pin(v)
- p.int(_OP_byte, ':')
- p.add(_OP_map_value_next)
- self.compileOne(p, sp + 2, vt.Elem(), false)
- p.int(_OP_goto, j)
- p.pin(i)
- p.pin(j)
- p.add(_OP_map_stop)
- p.add(_OP_drop_2)
- p.int(_OP_byte, '}')
-}
-
-func (self *_Compiler) compileMapBodyKey(p *_Program, vk reflect.Type) {
- if !vk.Implements(encodingTextMarshalerType) {
- self.compileMapBodyTextKey(p, vk)
- } else {
- self.compileMapBodyUtextKey(p, vk)
- }
-}
-
-func (self *_Compiler) compileMapBodyTextKey(p *_Program, vk reflect.Type) {
- switch vk.Kind() {
- case reflect.Invalid : panic("map key is nil")
- case reflect.Bool : p.key(_OP_bool)
- case reflect.Int : p.key(_OP_int())
- case reflect.Int8 : p.key(_OP_i8)
- case reflect.Int16 : p.key(_OP_i16)
- case reflect.Int32 : p.key(_OP_i32)
- case reflect.Int64 : p.key(_OP_i64)
- case reflect.Uint : p.key(_OP_uint())
- case reflect.Uint8 : p.key(_OP_u8)
- case reflect.Uint16 : p.key(_OP_u16)
- case reflect.Uint32 : p.key(_OP_u32)
- case reflect.Uint64 : p.key(_OP_u64)
- case reflect.Uintptr : p.key(_OP_uintptr())
- case reflect.Float32 : p.key(_OP_f32)
- case reflect.Float64 : p.key(_OP_f64)
- case reflect.String : self.compileString(p, vk)
- default : panic(error_type(vk))
- }
-}
-
-func (self *_Compiler) compileMapBodyUtextKey(p *_Program, vk reflect.Type) {
- if vk.Kind() != reflect.Ptr {
- p.rtt(_OP_marshal_text, vk)
- } else {
- self.compileMapBodyUtextPtr(p, vk)
- }
-}
-
-func (self *_Compiler) compileMapBodyUtextPtr(p *_Program, vk reflect.Type) {
- i := p.pc()
- p.add(_OP_is_nil)
- p.rtt(_OP_marshal_text, vk)
- j := p.pc()
- p.add(_OP_goto)
- p.pin(i)
- p.str(_OP_text, "\"\"")
- p.pin(j)
-}
-
-func (self *_Compiler) compileSlice(p *_Program, sp int, vt reflect.Type) {
- self.compileNil(p, sp, vt, _OP_empty_arr, self.compileSliceBody)
-}
-
-func (self *_Compiler) compileSliceBody(p *_Program, sp int, vt reflect.Type) {
- if isSimpleByte(vt) {
- p.add(_OP_bin)
- } else {
- self.compileSliceArray(p, sp, vt)
- }
-}
-
-func (self *_Compiler) compileSliceArray(p *_Program, sp int, vt reflect.Type) {
- p.tag(sp)
- p.int(_OP_byte, '[')
- p.add(_OP_save)
- p.add(_OP_slice_len)
- i := p.pc()
- p.rtt(_OP_slice_next, vt)
- self.compileOne(p, sp + 1, vt, true)
- j := p.pc()
- p.rtt(_OP_slice_next, vt)
- p.int(_OP_byte, ',')
- self.compileOne(p, sp + 1, vt, true)
- p.int(_OP_goto, j)
- p.pin(i)
- p.pin(j)
- p.add(_OP_drop)
- p.int(_OP_byte, ']')
-}
-
-func (self *_Compiler) compileArray(p *_Program, sp int, vt reflect.Type, nb int) {
- p.tag(sp)
- p.int(_OP_byte, '[')
- p.add(_OP_save)
-
- /* first item */
- if nb != 0 {
- self.compileOne(p, sp + 1, vt, self.pv)
- p.add(_OP_load)
- }
-
- /* remaining items */
- for i := 1; i < nb; i++ {
- p.int(_OP_byte, ',')
- p.int(_OP_index, i * int(vt.Size()))
- self.compileOne(p, sp + 1, vt, self.pv)
- p.add(_OP_load)
- }
-
- /* end of array */
- p.add(_OP_drop)
- p.int(_OP_byte, ']')
-}
-
-func (self *_Compiler) compileString(p *_Program, vt reflect.Type) {
- if vt != jsonNumberType {
- p.add(_OP_str)
- } else {
- p.add(_OP_number)
- }
-}
-
-func (self *_Compiler) compileStruct(p *_Program, sp int, vt reflect.Type) {
- if sp >= self.opts.MaxInlineDepth || p.pc() >= _MAX_ILBUF || (sp > 0 && vt.NumField() >= _MAX_FIELDS) {
- p.vp(_OP_recurse, vt, self.pv)
- if self.opts.RecursiveDepth > 0 {
- if self.pv {
- self.rec[vt] = 1
- } else {
- self.rec[vt] = 0
- }
- }
- } else {
- self.compileStructBody(p, sp, vt)
- }
-}
-
-func (self *_Compiler) compileStructBody(p *_Program, sp int, vt reflect.Type) {
- p.tag(sp)
- p.int(_OP_byte, '{')
- p.add(_OP_save)
- p.add(_OP_cond_set)
-
- /* compile each field */
- for _, fv := range resolver.ResolveStruct(vt) {
- var s []int
- var o resolver.Offset
-
- /* "omitempty" for arrays */
- if fv.Type.Kind() == reflect.Array {
- if fv.Type.Len() == 0 && (fv.Opts & resolver.F_omitempty) != 0 {
- continue
- }
- }
-
- /* index to the field */
- for _, o = range fv.Path {
- if p.int(_OP_index, int(o.Size)); o.Kind == resolver.F_deref {
- s = append(s, p.pc())
- p.add(_OP_is_nil)
- p.add(_OP_deref)
- }
- }
-
- /* check for "omitempty" option */
- if fv.Type.Kind() != reflect.Struct && fv.Type.Kind() != reflect.Array && (fv.Opts & resolver.F_omitempty) != 0 {
- s = append(s, p.pc())
- self.compileStructFieldZero(p, fv.Type)
- }
-
- /* add the comma if not the first element */
- i := p.pc()
- p.add(_OP_cond_testc)
- p.int(_OP_byte, ',')
- p.pin(i)
-
- /* compile the key and value */
- ft := fv.Type
- p.str(_OP_text, Quote(fv.Name) + ":")
-
- /* check for "stringnize" option */
- if (fv.Opts & resolver.F_stringize) == 0 {
- self.compileOne(p, sp + 1, ft, self.pv)
- } else {
- self.compileStructFieldStr(p, sp + 1, ft)
- }
-
- /* patch the skipping jumps and reload the struct pointer */
- p.rel(s)
- p.add(_OP_load)
- }
-
- /* end of object */
- p.add(_OP_drop)
- p.int(_OP_byte, '}')
-}
-
-func (self *_Compiler) compileStructFieldStr(p *_Program, sp int, vt reflect.Type) {
- pc := -1
- ft := vt
- sv := false
-
- /* dereference the pointer if needed */
- if ft.Kind() == reflect.Ptr {
- ft = ft.Elem()
- }
-
- /* check if it can be stringized */
- switch ft.Kind() {
- case reflect.Bool : sv = true
- case reflect.Int : sv = true
- case reflect.Int8 : sv = true
- case reflect.Int16 : sv = true
- case reflect.Int32 : sv = true
- case reflect.Int64 : sv = true
- case reflect.Uint : sv = true
- case reflect.Uint8 : sv = true
- case reflect.Uint16 : sv = true
- case reflect.Uint32 : sv = true
- case reflect.Uint64 : sv = true
- case reflect.Uintptr : sv = true
- case reflect.Float32 : sv = true
- case reflect.Float64 : sv = true
- case reflect.String : sv = true
- }
-
- /* if it's not, ignore the "string" and follow the regular path */
- if !sv {
- self.compileOne(p, sp, vt, self.pv)
- return
- }
-
- /* dereference the pointer */
- if vt.Kind() == reflect.Ptr {
- pc = p.pc()
- vt = vt.Elem()
- p.add(_OP_is_nil)
- p.add(_OP_deref)
- }
-
- /* special case of a double-quoted string */
- if ft != jsonNumberType && ft.Kind() == reflect.String {
- p.add(_OP_quote)
- } else {
- self.compileStructFieldQuoted(p, sp, vt)
- }
-
- /* the "null" case of the pointer */
- if pc != -1 {
- e := p.pc()
- p.add(_OP_goto)
- p.pin(pc)
- p.add(_OP_null)
- p.pin(e)
- }
-}
-
-func (self *_Compiler) compileStructFieldZero(p *_Program, vt reflect.Type) {
- switch vt.Kind() {
- case reflect.Bool : p.add(_OP_is_zero_1)
- case reflect.Int : p.add(_OP_is_zero_ints())
- case reflect.Int8 : p.add(_OP_is_zero_1)
- case reflect.Int16 : p.add(_OP_is_zero_2)
- case reflect.Int32 : p.add(_OP_is_zero_4)
- case reflect.Int64 : p.add(_OP_is_zero_8)
- case reflect.Uint : p.add(_OP_is_zero_ints())
- case reflect.Uint8 : p.add(_OP_is_zero_1)
- case reflect.Uint16 : p.add(_OP_is_zero_2)
- case reflect.Uint32 : p.add(_OP_is_zero_4)
- case reflect.Uint64 : p.add(_OP_is_zero_8)
- case reflect.Uintptr : p.add(_OP_is_nil)
- case reflect.Float32 : p.add(_OP_is_zero_4)
- case reflect.Float64 : p.add(_OP_is_zero_8)
- case reflect.String : p.add(_OP_is_nil_p1)
- case reflect.Interface : p.add(_OP_is_nil)
- case reflect.Map : p.add(_OP_is_zero_map)
- case reflect.Ptr : p.add(_OP_is_nil)
- case reflect.Slice : p.add(_OP_is_nil_p1)
- default : panic(error_type(vt))
- }
-}
-
-func (self *_Compiler) compileStructFieldQuoted(p *_Program, sp int, vt reflect.Type) {
- p.int(_OP_byte, '"')
- self.compileOne(p, sp, vt, self.pv)
- p.int(_OP_byte, '"')
-}
-
-func (self *_Compiler) compileInterface(p *_Program, vt reflect.Type) {
- x := p.pc()
- p.add(_OP_is_nil_p1)
-
- /* iface and efaces are different */
- if vt.NumMethod() == 0 {
- p.add(_OP_eface)
- } else {
- p.add(_OP_iface)
- }
-
- /* the "null" value */
- e := p.pc()
- p.add(_OP_goto)
- p.pin(x)
- p.add(_OP_null)
- p.pin(e)
-}
-
-func (self *_Compiler) compileMarshaler(p *_Program, op _Op, vt reflect.Type, mt reflect.Type) {
- pc := p.pc()
- vk := vt.Kind()
-
- /* direct receiver */
- if vk != reflect.Ptr {
- p.rtt(op, vt)
- return
- }
-
- /* value receiver with a pointer type, check for nil before calling the marshaler */
- p.add(_OP_is_nil)
- p.rtt(op, vt)
- i := p.pc()
- p.add(_OP_goto)
- p.pin(pc)
- p.add(_OP_null)
- p.pin(i)
+func ForceUseVM() {
+ vm.SetCompiler(makeEncoderVM)
+ pretouchType = pretouchTypeVM
+ encodeTypedPointer = vm.EncodeTypedPointer
+ vars.UseVM = true
+}
+
+var encodeTypedPointer func(buf *[]byte, vt *rt.GoType, vp *unsafe.Pointer, sb *vars.Stack, fv uint64) error
+
+func makeEncoderVM(vt *rt.GoType, ex ...interface{}) (interface{}, error) {
+ pp, err := NewCompiler().Compile(vt.Pack(), ex[0].(bool))
+ if err != nil {
+ return nil, err
+ }
+ return &pp, nil
+}
+
+var pretouchType func(_vt reflect.Type, opts option.CompileOptions, v uint8) (map[reflect.Type]uint8, error)
+
+func pretouchTypeVM(_vt reflect.Type, opts option.CompileOptions, v uint8) (map[reflect.Type]uint8, error) {
+ /* compile function */
+ compiler := NewCompiler().apply(opts)
+
+ /* find or compile */
+ vt := rt.UnpackType(_vt)
+ if val := vars.GetProgram(vt); val != nil {
+ return nil, nil
+ } else if _, err := vars.ComputeProgram(vt, makeEncoderVM, v == 1); err == nil {
+ return compiler.rec, nil
+ } else {
+ return nil, err
+ }
+}
+
+func pretouchRec(vtm map[reflect.Type]uint8, opts option.CompileOptions) error {
+ if opts.RecursiveDepth < 0 || len(vtm) == 0 {
+ return nil
+ }
+ next := make(map[reflect.Type]uint8)
+ for vt, v := range vtm {
+ sub, err := pretouchType(vt, opts, v)
+ if err != nil {
+ return err
+ }
+ for svt, v := range sub {
+ next[svt] = v
+ }
+ }
+ opts.RecursiveDepth -= 1
+ return pretouchRec(next, opts)
+}
+
+type Compiler struct {
+ opts option.CompileOptions
+ pv bool
+ tab map[reflect.Type]bool
+ rec map[reflect.Type]uint8
+}
+
+func NewCompiler() *Compiler {
+ return &Compiler{
+ opts: option.DefaultCompileOptions(),
+ tab: map[reflect.Type]bool{},
+ rec: map[reflect.Type]uint8{},
+ }
+}
+
+func (self *Compiler) apply(opts option.CompileOptions) *Compiler {
+ self.opts = opts
+ if self.opts.RecursiveDepth > 0 {
+ self.rec = map[reflect.Type]uint8{}
+ }
+ return self
+}
+
+func (self *Compiler) rescue(ep *error) {
+ if val := recover(); val != nil {
+ if err, ok := val.(error); ok {
+ *ep = err
+ } else {
+ panic(val)
+ }
+ }
+}
+
+func (self *Compiler) Compile(vt reflect.Type, pv bool) (ret ir.Program, err error) {
+ defer self.rescue(&err)
+ self.compileOne(&ret, 0, vt, pv)
+ return
+}
+
+func (self *Compiler) compileOne(p *ir.Program, sp int, vt reflect.Type, pv bool) {
+ if self.tab[vt] {
+ p.Vp(ir.OP_recurse, vt, pv)
+ } else {
+ self.compileRec(p, sp, vt, pv)
+ }
+}
+
+func (self *Compiler) tryCompileMarshaler(p *ir.Program, vt reflect.Type, pv bool) bool {
+ pt := reflect.PtrTo(vt)
+
+ /* check for addressable `json.Marshaler` with pointer receiver */
+ if pv && pt.Implements(vars.JsonMarshalerType) {
+ addMarshalerOp(p, ir.OP_marshal_p, pt, vars.JsonMarshalerType)
+ return true
+ }
+
+ /* check for `json.Marshaler` */
+ if vt.Implements(vars.JsonMarshalerType) {
+ self.compileMarshaler(p, ir.OP_marshal, vt, vars.JsonMarshalerType)
+ return true
+ }
+
+ /* check for addressable `encoding.TextMarshaler` with pointer receiver */
+ if pv && pt.Implements(vars.EncodingTextMarshalerType) {
+ addMarshalerOp(p, ir.OP_marshal_text_p, pt, vars.EncodingTextMarshalerType)
+ return true
+ }
+
+ /* check for `encoding.TextMarshaler` */
+ if vt.Implements(vars.EncodingTextMarshalerType) {
+ self.compileMarshaler(p, ir.OP_marshal_text, vt, vars.EncodingTextMarshalerType)
+ return true
+ }
+
+ return false
+}
+
+func (self *Compiler) compileRec(p *ir.Program, sp int, vt reflect.Type, pv bool) {
+ pr := self.pv
+
+ if self.tryCompileMarshaler(p, vt, pv) {
+ return
+ }
+
+ /* enter the recursion, and compile the type */
+ self.pv = pv
+ self.tab[vt] = true
+ self.compileOps(p, sp, vt)
+
+ /* exit the recursion */
+ self.pv = pr
+ delete(self.tab, vt)
+}
+
+func (self *Compiler) compileOps(p *ir.Program, sp int, vt reflect.Type) {
+ switch vt.Kind() {
+ case reflect.Bool:
+ p.Add(ir.OP_bool)
+ case reflect.Int:
+ p.Add(ir.OP_int())
+ case reflect.Int8:
+ p.Add(ir.OP_i8)
+ case reflect.Int16:
+ p.Add(ir.OP_i16)
+ case reflect.Int32:
+ p.Add(ir.OP_i32)
+ case reflect.Int64:
+ p.Add(ir.OP_i64)
+ case reflect.Uint:
+ p.Add(ir.OP_uint())
+ case reflect.Uint8:
+ p.Add(ir.OP_u8)
+ case reflect.Uint16:
+ p.Add(ir.OP_u16)
+ case reflect.Uint32:
+ p.Add(ir.OP_u32)
+ case reflect.Uint64:
+ p.Add(ir.OP_u64)
+ case reflect.Uintptr:
+ p.Add(ir.OP_uintptr())
+ case reflect.Float32:
+ p.Add(ir.OP_f32)
+ case reflect.Float64:
+ p.Add(ir.OP_f64)
+ case reflect.String:
+ self.compileString(p, vt)
+ case reflect.Array:
+ self.compileArray(p, sp, vt.Elem(), vt.Len())
+ case reflect.Interface:
+ self.compileInterface(p, vt)
+ case reflect.Map:
+ self.compileMap(p, sp, vt)
+ case reflect.Ptr:
+ self.compilePtr(p, sp, vt.Elem())
+ case reflect.Slice:
+ self.compileSlice(p, sp, vt.Elem())
+ case reflect.Struct:
+ self.compileStruct(p, sp, vt)
+ default:
+ panic(vars.Error_type(vt))
+ }
+}
+
+func (self *Compiler) compileNil(p *ir.Program, sp int, vt reflect.Type, nil_op ir.Op, fn func(*ir.Program, int, reflect.Type)) {
+ x := p.PC()
+ p.Add(ir.OP_is_nil)
+ fn(p, sp, vt)
+ e := p.PC()
+ p.Add(ir.OP_goto)
+ p.Pin(x)
+ p.Add(nil_op)
+ p.Pin(e)
+}
+
+func (self *Compiler) compilePtr(p *ir.Program, sp int, vt reflect.Type) {
+ self.compileNil(p, sp, vt, ir.OP_null, self.compilePtrBody)
+}
+
+func (self *Compiler) compilePtrBody(p *ir.Program, sp int, vt reflect.Type) {
+ p.Tag(sp)
+ p.Add(ir.OP_save)
+ p.Add(ir.OP_deref)
+ self.compileOne(p, sp+1, vt, true)
+ p.Add(ir.OP_drop)
+}
+
+func (self *Compiler) compileMap(p *ir.Program, sp int, vt reflect.Type) {
+ self.compileNil(p, sp, vt, ir.OP_empty_obj, self.compileMapBody)
+}
+
+func (self *Compiler) compileMapBody(p *ir.Program, sp int, vt reflect.Type) {
+ p.Tag(sp + 1)
+ p.Int(ir.OP_byte, '{')
+ e := p.PC()
+ p.Add(ir.OP_is_zero_map)
+ p.Add(ir.OP_save)
+ p.Rtt(ir.OP_map_iter, vt)
+ p.Add(ir.OP_save)
+ i := p.PC()
+ p.Add(ir.OP_map_check_key)
+ u := p.PC()
+ p.Add(ir.OP_map_write_key)
+ self.compileMapBodyKey(p, vt.Key())
+ p.Pin(u)
+ p.Int(ir.OP_byte, ':')
+ p.Add(ir.OP_map_value_next)
+ self.compileOne(p, sp+2, vt.Elem(), false)
+ j := p.PC()
+ p.Add(ir.OP_map_check_key)
+ p.Int(ir.OP_byte, ',')
+ v := p.PC()
+ p.Add(ir.OP_map_write_key)
+ self.compileMapBodyKey(p, vt.Key())
+ p.Pin(v)
+ p.Int(ir.OP_byte, ':')
+ p.Add(ir.OP_map_value_next)
+ self.compileOne(p, sp+2, vt.Elem(), false)
+ p.Int(ir.OP_goto, j)
+ p.Pin(i)
+ p.Pin(j)
+ p.Add(ir.OP_map_stop)
+ p.Add(ir.OP_drop_2)
+ p.Pin(e)
+ p.Int(ir.OP_byte, '}')
+}
+
+func (self *Compiler) compileMapBodyKey(p *ir.Program, vk reflect.Type) {
+ if !vk.Implements(vars.EncodingTextMarshalerType) {
+ self.compileMapBodyTextKey(p, vk)
+ } else {
+ self.compileMapBodyUtextKey(p, vk)
+ }
+}
+
+func (self *Compiler) compileMapBodyTextKey(p *ir.Program, vk reflect.Type) {
+ switch vk.Kind() {
+ case reflect.Invalid:
+ panic("map key is nil")
+ case reflect.Bool:
+ p.Key(ir.OP_bool)
+ case reflect.Int:
+ p.Key(ir.OP_int())
+ case reflect.Int8:
+ p.Key(ir.OP_i8)
+ case reflect.Int16:
+ p.Key(ir.OP_i16)
+ case reflect.Int32:
+ p.Key(ir.OP_i32)
+ case reflect.Int64:
+ p.Key(ir.OP_i64)
+ case reflect.Uint:
+ p.Key(ir.OP_uint())
+ case reflect.Uint8:
+ p.Key(ir.OP_u8)
+ case reflect.Uint16:
+ p.Key(ir.OP_u16)
+ case reflect.Uint32:
+ p.Key(ir.OP_u32)
+ case reflect.Uint64:
+ p.Key(ir.OP_u64)
+ case reflect.Uintptr:
+ p.Key(ir.OP_uintptr())
+ case reflect.Float32:
+ p.Key(ir.OP_f32)
+ case reflect.Float64:
+ p.Key(ir.OP_f64)
+ case reflect.String:
+ self.compileString(p, vk)
+ default:
+ panic(vars.Error_type(vk))
+ }
+}
+
+func (self *Compiler) compileMapBodyUtextKey(p *ir.Program, vk reflect.Type) {
+ if vk.Kind() != reflect.Ptr {
+ addMarshalerOp(p, ir.OP_marshal_text, vk, vars.EncodingTextMarshalerType)
+ } else {
+ self.compileMapBodyUtextPtr(p, vk)
+ }
+}
+
+func (self *Compiler) compileMapBodyUtextPtr(p *ir.Program, vk reflect.Type) {
+ i := p.PC()
+ p.Add(ir.OP_is_nil)
+ addMarshalerOp(p, ir.OP_marshal_text, vk, vars.EncodingTextMarshalerType)
+ j := p.PC()
+ p.Add(ir.OP_goto)
+ p.Pin(i)
+ p.Str(ir.OP_text, "\"\"")
+ p.Pin(j)
+}
+
+func (self *Compiler) compileSlice(p *ir.Program, sp int, vt reflect.Type) {
+ self.compileNil(p, sp, vt, ir.OP_empty_arr, self.compileSliceBody)
+}
+
+func (self *Compiler) compileSliceBody(p *ir.Program, sp int, vt reflect.Type) {
+ if vars.IsSimpleByte(vt) {
+ p.Add(ir.OP_bin)
+ } else {
+ self.compileSliceArray(p, sp, vt)
+ }
+}
+
+func (self *Compiler) compileSliceArray(p *ir.Program, sp int, vt reflect.Type) {
+ p.Tag(sp)
+ p.Int(ir.OP_byte, '[')
+ e := p.PC()
+ p.Add(ir.OP_is_nil)
+ p.Add(ir.OP_save)
+ p.Add(ir.OP_slice_len)
+ i := p.PC()
+ p.Rtt(ir.OP_slice_next, vt)
+ self.compileOne(p, sp+1, vt, true)
+ j := p.PC()
+ p.Rtt(ir.OP_slice_next, vt)
+ p.Int(ir.OP_byte, ',')
+ self.compileOne(p, sp+1, vt, true)
+ p.Int(ir.OP_goto, j)
+ p.Pin(i)
+ p.Pin(j)
+ p.Add(ir.OP_drop)
+ p.Pin(e)
+ p.Int(ir.OP_byte, ']')
+}
+
+func (self *Compiler) compileArray(p *ir.Program, sp int, vt reflect.Type, nb int) {
+ p.Tag(sp)
+ p.Int(ir.OP_byte, '[')
+ p.Add(ir.OP_save)
+
+ /* first item */
+ if nb != 0 {
+ self.compileOne(p, sp+1, vt, self.pv)
+ p.Add(ir.OP_load)
+ }
+
+ /* remaining items */
+ for i := 1; i < nb; i++ {
+ p.Int(ir.OP_byte, ',')
+ p.Int(ir.OP_index, i*int(vt.Size()))
+ self.compileOne(p, sp+1, vt, self.pv)
+ p.Add(ir.OP_load)
+ }
+
+ /* end of array */
+ p.Add(ir.OP_drop)
+ p.Int(ir.OP_byte, ']')
+}
+
+func (self *Compiler) compileString(p *ir.Program, vt reflect.Type) {
+ if vt != vars.JsonNumberType {
+ p.Add(ir.OP_str)
+ } else {
+ p.Add(ir.OP_number)
+ }
+}
+
+func (self *Compiler) compileStruct(p *ir.Program, sp int, vt reflect.Type) {
+ if sp >= self.opts.MaxInlineDepth || p.PC() >= vars.MAX_ILBUF || (sp > 0 && vt.NumField() >= vars.MAX_FIELDS) {
+ p.Vp(ir.OP_recurse, vt, self.pv)
+ if self.opts.RecursiveDepth > 0 {
+ if self.pv {
+ self.rec[vt] = 1
+ } else {
+ self.rec[vt] = 0
+ }
+ }
+ } else {
+ self.compileStructBody(p, sp, vt)
+ }
+}
+
+func (self *Compiler) compileStructBody(p *ir.Program, sp int, vt reflect.Type) {
+ p.Tag(sp)
+ p.Int(ir.OP_byte, '{')
+ p.Add(ir.OP_save)
+ p.Add(ir.OP_cond_set)
+
+ /* compile each field */
+ for _, fv := range resolver.ResolveStruct(vt) {
+ var s []int
+ var o resolver.Offset
+
+ /* "omitempty" for arrays */
+ if fv.Type.Kind() == reflect.Array {
+ if fv.Type.Len() == 0 && (fv.Opts&resolver.F_omitempty) != 0 {
+ continue
+ }
+ }
+
+ /* index to the field */
+ for _, o = range fv.Path {
+ if p.Int(ir.OP_index, int(o.Size)); o.Kind == resolver.F_deref {
+ s = append(s, p.PC())
+ p.Add(ir.OP_is_nil)
+ p.Add(ir.OP_deref)
+ }
+ }
+
+ /* check for "omitempty" option */
+ if fv.Type.Kind() != reflect.Struct && fv.Type.Kind() != reflect.Array && (fv.Opts&resolver.F_omitempty) != 0 {
+ s = append(s, p.PC())
+ self.compileStructFieldZero(p, fv.Type)
+ }
+
+ /* add the comma if not the first element */
+ i := p.PC()
+ p.Add(ir.OP_cond_testc)
+ p.Int(ir.OP_byte, ',')
+ p.Pin(i)
+
+ /* compile the key and value */
+ ft := fv.Type
+ p.Str(ir.OP_text, Quote(fv.Name)+":")
+
+ /* check for "stringnize" option */
+ if (fv.Opts & resolver.F_stringize) == 0 {
+ self.compileOne(p, sp+1, ft, self.pv)
+ } else {
+ self.compileStructFieldStr(p, sp+1, ft)
+ }
+
+ /* patch the skipping jumps and reload the struct pointer */
+ p.Rel(s)
+ p.Add(ir.OP_load)
+ }
+
+ /* end of object */
+ p.Add(ir.OP_drop)
+ p.Int(ir.OP_byte, '}')
+}
+
+func (self *Compiler) compileStructFieldStr(p *ir.Program, sp int, vt reflect.Type) {
+ // NOTICE: according to encoding/json, Marshaler type has higher priority than string option
+ // see issue:
+ if self.tryCompileMarshaler(p, vt, self.pv) {
+ return
+ }
+
+ pc := -1
+ ft := vt
+ sv := false
+
+ /* dereference the pointer if needed */
+ if ft.Kind() == reflect.Ptr {
+ ft = ft.Elem()
+ }
+
+ /* check if it can be stringized */
+ switch ft.Kind() {
+ case reflect.Bool:
+ sv = true
+ case reflect.Int:
+ sv = true
+ case reflect.Int8:
+ sv = true
+ case reflect.Int16:
+ sv = true
+ case reflect.Int32:
+ sv = true
+ case reflect.Int64:
+ sv = true
+ case reflect.Uint:
+ sv = true
+ case reflect.Uint8:
+ sv = true
+ case reflect.Uint16:
+ sv = true
+ case reflect.Uint32:
+ sv = true
+ case reflect.Uint64:
+ sv = true
+ case reflect.Uintptr:
+ sv = true
+ case reflect.Float32:
+ sv = true
+ case reflect.Float64:
+ sv = true
+ case reflect.String:
+ sv = true
+ }
+
+ /* if it's not, ignore the "string" and follow the regular path */
+ if !sv {
+ self.compileOne(p, sp, vt, self.pv)
+ return
+ }
+
+ /* dereference the pointer */
+ if vt.Kind() == reflect.Ptr {
+ pc = p.PC()
+ vt = vt.Elem()
+ p.Add(ir.OP_is_nil)
+ p.Add(ir.OP_deref)
+ }
+
+ /* special case of a double-quoted string */
+ if ft != vars.JsonNumberType && ft.Kind() == reflect.String {
+ p.Add(ir.OP_quote)
+ } else {
+ self.compileStructFieldQuoted(p, sp, vt)
+ }
+
+ /* the "null" case of the pointer */
+ if pc != -1 {
+ e := p.PC()
+ p.Add(ir.OP_goto)
+ p.Pin(pc)
+ p.Add(ir.OP_null)
+ p.Pin(e)
+ }
+}
+
+func (self *Compiler) compileStructFieldZero(p *ir.Program, vt reflect.Type) {
+ switch vt.Kind() {
+ case reflect.Bool:
+ p.Add(ir.OP_is_zero_1)
+ case reflect.Int:
+ p.Add(ir.OP_is_zero_ints())
+ case reflect.Int8:
+ p.Add(ir.OP_is_zero_1)
+ case reflect.Int16:
+ p.Add(ir.OP_is_zero_2)
+ case reflect.Int32:
+ p.Add(ir.OP_is_zero_4)
+ case reflect.Int64:
+ p.Add(ir.OP_is_zero_8)
+ case reflect.Uint:
+ p.Add(ir.OP_is_zero_ints())
+ case reflect.Uint8:
+ p.Add(ir.OP_is_zero_1)
+ case reflect.Uint16:
+ p.Add(ir.OP_is_zero_2)
+ case reflect.Uint32:
+ p.Add(ir.OP_is_zero_4)
+ case reflect.Uint64:
+ p.Add(ir.OP_is_zero_8)
+ case reflect.Uintptr:
+ p.Add(ir.OP_is_nil)
+ case reflect.Float32:
+ p.Add(ir.OP_is_zero_4)
+ case reflect.Float64:
+ p.Add(ir.OP_is_zero_8)
+ case reflect.String:
+ p.Add(ir.OP_is_nil_p1)
+ case reflect.Interface:
+ p.Add(ir.OP_is_nil)
+ case reflect.Map:
+ p.Add(ir.OP_is_zero_map)
+ case reflect.Ptr:
+ p.Add(ir.OP_is_nil)
+ case reflect.Slice:
+ p.Add(ir.OP_is_nil_p1)
+ default:
+ panic(vars.Error_type(vt))
+ }
+}
+
+func (self *Compiler) compileStructFieldQuoted(p *ir.Program, sp int, vt reflect.Type) {
+ p.Int(ir.OP_byte, '"')
+ self.compileOne(p, sp, vt, self.pv)
+ p.Int(ir.OP_byte, '"')
+}
+
+func (self *Compiler) compileInterface(p *ir.Program, vt reflect.Type) {
+ x := p.PC()
+ p.Add(ir.OP_is_nil_p1)
+
+ /* iface and efaces are different */
+ if vt.NumMethod() == 0 {
+ p.Add(ir.OP_eface)
+ } else {
+ p.Add(ir.OP_iface)
+ }
+
+ /* the "null" value */
+ e := p.PC()
+ p.Add(ir.OP_goto)
+ p.Pin(x)
+ p.Add(ir.OP_null)
+ p.Pin(e)
+}
+
+func (self *Compiler) compileMarshaler(p *ir.Program, op ir.Op, vt reflect.Type, mt reflect.Type) {
+ pc := p.PC()
+ vk := vt.Kind()
+
+ /* direct receiver */
+ if vk != reflect.Ptr {
+ addMarshalerOp(p, op, vt, mt)
+ return
+ }
+ /* value receiver with a pointer type, check for nil before calling the marshaler */
+ p.Add(ir.OP_is_nil)
+
+ addMarshalerOp(p, op, vt, mt)
+
+ i := p.PC()
+ p.Add(ir.OP_goto)
+ p.Pin(pc)
+ p.Add(ir.OP_null)
+ p.Pin(i)
+}
+
+func addMarshalerOp(p *ir.Program, op ir.Op, vt reflect.Type, mt reflect.Type) {
+ if vars.UseVM {
+ itab := rt.GetItab(rt.IfaceType(rt.UnpackType(mt)), rt.UnpackType(vt), true)
+ p.Vtab(op, vt, itab)
+ } else {
+ // OPT: get itab here
+ p.Rtt(op, vt)
+ }
}