git.gammaspectra.live/P2Pool/go-json@v0.99.0/internal/encoder/compiler.go (about)

     1  package encoder
     2  
     3  import (
     4  	"context"
     5  	"encoding"
     6  	"encoding/json"
     7  	"reflect"
     8  	"sync/atomic"
     9  	"unsafe"
    10  
    11  	"git.gammaspectra.live/P2Pool/go-json/internal/errors"
    12  	"git.gammaspectra.live/P2Pool/go-json/internal/runtime"
    13  )
    14  
    15  type marshalerContext interface {
    16  	MarshalJSON(context.Context) ([]byte, error)
    17  }
    18  
    19  var (
    20  	marshalJSONType        = reflect.TypeOf((*json.Marshaler)(nil)).Elem()
    21  	marshalJSONContextType = reflect.TypeOf((*marshalerContext)(nil)).Elem()
    22  	marshalTextType        = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem()
    23  	jsonNumberType         = reflect.TypeOf(json.Number(""))
    24  	cachedOpcodeSets       []*OpcodeSet
    25  	cachedOpcodeMap        unsafe.Pointer // map[uintptr]*OpcodeSet
    26  	typeAddr               *runtime.TypeAddr
    27  )
    28  
    29  func init() {
    30  	typeAddr = runtime.AnalyzeTypeAddr()
    31  	if typeAddr == nil {
    32  		typeAddr = &runtime.TypeAddr{}
    33  	}
    34  	cachedOpcodeSets = make([]*OpcodeSet, typeAddr.AddrRange>>typeAddr.AddrShift+1)
    35  }
    36  
    37  func loadOpcodeMap() map[uintptr]*OpcodeSet {
    38  	p := atomic.LoadPointer(&cachedOpcodeMap)
    39  	return *(*map[uintptr]*OpcodeSet)(unsafe.Pointer(&p))
    40  }
    41  
    42  func storeOpcodeSet(typ uintptr, set *OpcodeSet, m map[uintptr]*OpcodeSet) {
    43  	newOpcodeMap := make(map[uintptr]*OpcodeSet, len(m)+1)
    44  	newOpcodeMap[typ] = set
    45  
    46  	for k, v := range m {
    47  		newOpcodeMap[k] = v
    48  	}
    49  
    50  	atomic.StorePointer(&cachedOpcodeMap, *(*unsafe.Pointer)(unsafe.Pointer(&newOpcodeMap)))
    51  }
    52  
    53  func compileToGetCodeSetSlowPath(typeptr uintptr) (*OpcodeSet, error) {
    54  	opcodeMap := loadOpcodeMap()
    55  	if codeSet, exists := opcodeMap[typeptr]; exists {
    56  		return codeSet, nil
    57  	}
    58  	codeSet, err := newCompiler().compile(typeptr)
    59  	if err != nil {
    60  		return nil, err
    61  	}
    62  	storeOpcodeSet(typeptr, codeSet, opcodeMap)
    63  	return codeSet, nil
    64  }
    65  
    66  func getFilteredCodeSetIfNeeded(ctx *RuntimeContext, codeSet *OpcodeSet) (*OpcodeSet, error) {
    67  	if (ctx.Option.Flag & ContextOption) == 0 {
    68  		return codeSet, nil
    69  	}
    70  	query := FieldQueryFromContext(ctx.Option.Context)
    71  	if query == nil {
    72  		return codeSet, nil
    73  	}
    74  	ctx.Option.Flag |= FieldQueryOption
    75  	cacheCodeSet := codeSet.getQueryCache(query.Hash())
    76  	if cacheCodeSet != nil {
    77  		return cacheCodeSet, nil
    78  	}
    79  	queryCodeSet, err := newCompiler().codeToOpcodeSet(codeSet.Type, codeSet.Code.Filter(query))
    80  	if err != nil {
    81  		return nil, err
    82  	}
    83  	codeSet.setQueryCache(query.Hash(), queryCodeSet)
    84  	return queryCodeSet, nil
    85  }
    86  
    87  type Compiler struct {
    88  	structTypeToCode map[uintptr]*StructCode
    89  }
    90  
    91  func newCompiler() *Compiler {
    92  	return &Compiler{
    93  		structTypeToCode: map[uintptr]*StructCode{},
    94  	}
    95  }
    96  
    97  func (c *Compiler) compile(typeptr uintptr) (*OpcodeSet, error) {
    98  	// noescape trick for header.typ ( reflect.*rtype )
    99  	typ := *(**runtime.Type)(unsafe.Pointer(&typeptr))
   100  	code, err := c.typeToCode(typ)
   101  	if err != nil {
   102  		return nil, err
   103  	}
   104  	return c.codeToOpcodeSet(typ, code)
   105  }
   106  
   107  func (c *Compiler) codeToOpcodeSet(typ *runtime.Type, code Code) (*OpcodeSet, error) {
   108  	noescapeKeyCode := c.codeToOpcode(&compileContext{
   109  		structTypeToCodes: map[uintptr]Opcodes{},
   110  		recursiveCodes:    &Opcodes{},
   111  	}, typ, code)
   112  	if err := noescapeKeyCode.Validate(); err != nil {
   113  		return nil, err
   114  	}
   115  	escapeKeyCode := c.codeToOpcode(&compileContext{
   116  		structTypeToCodes: map[uintptr]Opcodes{},
   117  		recursiveCodes:    &Opcodes{},
   118  		escapeKey:         true,
   119  	}, typ, code)
   120  	noescapeKeyCode = copyOpcode(noescapeKeyCode)
   121  	escapeKeyCode = copyOpcode(escapeKeyCode)
   122  	setTotalLengthToInterfaceOp(noescapeKeyCode)
   123  	setTotalLengthToInterfaceOp(escapeKeyCode)
   124  	interfaceNoescapeKeyCode := copyToInterfaceOpcode(noescapeKeyCode)
   125  	interfaceEscapeKeyCode := copyToInterfaceOpcode(escapeKeyCode)
   126  	codeLength := noescapeKeyCode.TotalLength()
   127  	return &OpcodeSet{
   128  		Type:                     typ,
   129  		NoescapeKeyCode:          noescapeKeyCode,
   130  		EscapeKeyCode:            escapeKeyCode,
   131  		InterfaceNoescapeKeyCode: interfaceNoescapeKeyCode,
   132  		InterfaceEscapeKeyCode:   interfaceEscapeKeyCode,
   133  		CodeLength:               codeLength,
   134  		EndCode:                  ToEndCode(interfaceNoescapeKeyCode),
   135  		Code:                     code,
   136  		QueryCache:               map[string]*OpcodeSet{},
   137  	}, nil
   138  }
   139  
   140  func (c *Compiler) typeToCode(typ *runtime.Type) (Code, error) {
   141  	switch {
   142  	case c.implementsMarshalJSON(typ):
   143  		return c.marshalJSONCode(typ)
   144  	case c.implementsMarshalText(typ):
   145  		return c.marshalTextCode(typ)
   146  	}
   147  
   148  	isPtr := false
   149  	orgType := typ
   150  	if typ.Kind() == reflect.Ptr {
   151  		typ = typ.Elem()
   152  		isPtr = true
   153  	}
   154  	switch {
   155  	case c.implementsMarshalJSON(typ):
   156  		return c.marshalJSONCode(orgType)
   157  	case c.implementsMarshalText(typ):
   158  		return c.marshalTextCode(orgType)
   159  	}
   160  	switch typ.Kind() {
   161  	case reflect.Slice:
   162  		elem := typ.Elem()
   163  		if elem.Kind() == reflect.Uint8 {
   164  			p := runtime.PtrTo(elem)
   165  			if !c.implementsMarshalJSONType(p) && !p.Implements(marshalTextType) {
   166  				return c.bytesCode(typ, isPtr)
   167  			}
   168  		}
   169  		return c.sliceCode(typ)
   170  	case reflect.Map:
   171  		if isPtr {
   172  			return c.ptrCode(runtime.PtrTo(typ))
   173  		}
   174  		return c.mapCode(typ)
   175  	case reflect.Struct:
   176  		return c.structCode(typ, isPtr)
   177  	case reflect.Int:
   178  		return c.intCode(typ, isPtr)
   179  	case reflect.Int8:
   180  		return c.int8Code(typ, isPtr)
   181  	case reflect.Int16:
   182  		return c.int16Code(typ, isPtr)
   183  	case reflect.Int32:
   184  		return c.int32Code(typ, isPtr)
   185  	case reflect.Int64:
   186  		return c.int64Code(typ, isPtr)
   187  	case reflect.Uint, reflect.Uintptr:
   188  		return c.uintCode(typ, isPtr)
   189  	case reflect.Uint8:
   190  		return c.uint8Code(typ, isPtr)
   191  	case reflect.Uint16:
   192  		return c.uint16Code(typ, isPtr)
   193  	case reflect.Uint32:
   194  		return c.uint32Code(typ, isPtr)
   195  	case reflect.Uint64:
   196  		return c.uint64Code(typ, isPtr)
   197  	case reflect.Float32:
   198  		return c.float32Code(typ, isPtr)
   199  	case reflect.Float64:
   200  		return c.float64Code(typ, isPtr)
   201  	case reflect.String:
   202  		return c.stringCode(typ, isPtr)
   203  	case reflect.Bool:
   204  		return c.boolCode(typ, isPtr)
   205  	case reflect.Interface:
   206  		return c.interfaceCode(typ, isPtr)
   207  	default:
   208  		if isPtr && typ.Implements(marshalTextType) {
   209  			typ = orgType
   210  		}
   211  		return c.typeToCodeWithPtr(typ, isPtr)
   212  	}
   213  }
   214  
   215  func (c *Compiler) typeToCodeWithPtr(typ *runtime.Type, isPtr bool) (Code, error) {
   216  	switch {
   217  	case c.implementsMarshalJSON(typ):
   218  		return c.marshalJSONCode(typ)
   219  	case c.implementsMarshalText(typ):
   220  		return c.marshalTextCode(typ)
   221  	}
   222  	switch typ.Kind() {
   223  	case reflect.Ptr:
   224  		return c.ptrCode(typ)
   225  	case reflect.Slice:
   226  		elem := typ.Elem()
   227  		if elem.Kind() == reflect.Uint8 {
   228  			p := runtime.PtrTo(elem)
   229  			if !c.implementsMarshalJSONType(p) && !p.Implements(marshalTextType) {
   230  				return c.bytesCode(typ, false)
   231  			}
   232  		}
   233  		return c.sliceCode(typ)
   234  	case reflect.Array:
   235  		return c.arrayCode(typ)
   236  	case reflect.Map:
   237  		return c.mapCode(typ)
   238  	case reflect.Struct:
   239  		return c.structCode(typ, isPtr)
   240  	case reflect.Interface:
   241  		return c.interfaceCode(typ, false)
   242  	case reflect.Int:
   243  		return c.intCode(typ, false)
   244  	case reflect.Int8:
   245  		return c.int8Code(typ, false)
   246  	case reflect.Int16:
   247  		return c.int16Code(typ, false)
   248  	case reflect.Int32:
   249  		return c.int32Code(typ, false)
   250  	case reflect.Int64:
   251  		return c.int64Code(typ, false)
   252  	case reflect.Uint:
   253  		return c.uintCode(typ, false)
   254  	case reflect.Uint8:
   255  		return c.uint8Code(typ, false)
   256  	case reflect.Uint16:
   257  		return c.uint16Code(typ, false)
   258  	case reflect.Uint32:
   259  		return c.uint32Code(typ, false)
   260  	case reflect.Uint64:
   261  		return c.uint64Code(typ, false)
   262  	case reflect.Uintptr:
   263  		return c.uintCode(typ, false)
   264  	case reflect.Float32:
   265  		return c.float32Code(typ, false)
   266  	case reflect.Float64:
   267  		return c.float64Code(typ, false)
   268  	case reflect.String:
   269  		return c.stringCode(typ, false)
   270  	case reflect.Bool:
   271  		return c.boolCode(typ, false)
   272  	}
   273  	return nil, &errors.UnsupportedTypeError{Type: runtime.RType2Type(typ)}
   274  }
   275  
   276  const intSize = 32 << (^uint(0) >> 63)
   277  
   278  //nolint:unparam
   279  func (c *Compiler) intCode(typ *runtime.Type, isPtr bool) (*IntCode, error) {
   280  	return &IntCode{typ: typ, bitSize: intSize, isPtr: isPtr}, nil
   281  }
   282  
   283  //nolint:unparam
   284  func (c *Compiler) int8Code(typ *runtime.Type, isPtr bool) (*IntCode, error) {
   285  	return &IntCode{typ: typ, bitSize: 8, isPtr: isPtr}, nil
   286  }
   287  
   288  //nolint:unparam
   289  func (c *Compiler) int16Code(typ *runtime.Type, isPtr bool) (*IntCode, error) {
   290  	return &IntCode{typ: typ, bitSize: 16, isPtr: isPtr}, nil
   291  }
   292  
   293  //nolint:unparam
   294  func (c *Compiler) int32Code(typ *runtime.Type, isPtr bool) (*IntCode, error) {
   295  	return &IntCode{typ: typ, bitSize: 32, isPtr: isPtr}, nil
   296  }
   297  
   298  //nolint:unparam
   299  func (c *Compiler) int64Code(typ *runtime.Type, isPtr bool) (*IntCode, error) {
   300  	return &IntCode{typ: typ, bitSize: 64, isPtr: isPtr}, nil
   301  }
   302  
   303  //nolint:unparam
   304  func (c *Compiler) uintCode(typ *runtime.Type, isPtr bool) (*UintCode, error) {
   305  	return &UintCode{typ: typ, bitSize: intSize, isPtr: isPtr}, nil
   306  }
   307  
   308  //nolint:unparam
   309  func (c *Compiler) uint8Code(typ *runtime.Type, isPtr bool) (*UintCode, error) {
   310  	return &UintCode{typ: typ, bitSize: 8, isPtr: isPtr}, nil
   311  }
   312  
   313  //nolint:unparam
   314  func (c *Compiler) uint16Code(typ *runtime.Type, isPtr bool) (*UintCode, error) {
   315  	return &UintCode{typ: typ, bitSize: 16, isPtr: isPtr}, nil
   316  }
   317  
   318  //nolint:unparam
   319  func (c *Compiler) uint32Code(typ *runtime.Type, isPtr bool) (*UintCode, error) {
   320  	return &UintCode{typ: typ, bitSize: 32, isPtr: isPtr}, nil
   321  }
   322  
   323  //nolint:unparam
   324  func (c *Compiler) uint64Code(typ *runtime.Type, isPtr bool) (*UintCode, error) {
   325  	return &UintCode{typ: typ, bitSize: 64, isPtr: isPtr}, nil
   326  }
   327  
   328  //nolint:unparam
   329  func (c *Compiler) float32Code(typ *runtime.Type, isPtr bool) (*FloatCode, error) {
   330  	return &FloatCode{typ: typ, bitSize: 32, isPtr: isPtr}, nil
   331  }
   332  
   333  //nolint:unparam
   334  func (c *Compiler) float64Code(typ *runtime.Type, isPtr bool) (*FloatCode, error) {
   335  	return &FloatCode{typ: typ, bitSize: 64, isPtr: isPtr}, nil
   336  }
   337  
   338  //nolint:unparam
   339  func (c *Compiler) stringCode(typ *runtime.Type, isPtr bool) (*StringCode, error) {
   340  	return &StringCode{typ: typ, isPtr: isPtr}, nil
   341  }
   342  
   343  //nolint:unparam
   344  func (c *Compiler) boolCode(typ *runtime.Type, isPtr bool) (*BoolCode, error) {
   345  	return &BoolCode{typ: typ, isPtr: isPtr}, nil
   346  }
   347  
   348  //nolint:unparam
   349  func (c *Compiler) intStringCode(typ *runtime.Type) (*IntCode, error) {
   350  	return &IntCode{typ: typ, bitSize: intSize, isString: true}, nil
   351  }
   352  
   353  //nolint:unparam
   354  func (c *Compiler) int8StringCode(typ *runtime.Type) (*IntCode, error) {
   355  	return &IntCode{typ: typ, bitSize: 8, isString: true}, nil
   356  }
   357  
   358  //nolint:unparam
   359  func (c *Compiler) int16StringCode(typ *runtime.Type) (*IntCode, error) {
   360  	return &IntCode{typ: typ, bitSize: 16, isString: true}, nil
   361  }
   362  
   363  //nolint:unparam
   364  func (c *Compiler) int32StringCode(typ *runtime.Type) (*IntCode, error) {
   365  	return &IntCode{typ: typ, bitSize: 32, isString: true}, nil
   366  }
   367  
   368  //nolint:unparam
   369  func (c *Compiler) int64StringCode(typ *runtime.Type) (*IntCode, error) {
   370  	return &IntCode{typ: typ, bitSize: 64, isString: true}, nil
   371  }
   372  
   373  //nolint:unparam
   374  func (c *Compiler) uintStringCode(typ *runtime.Type) (*UintCode, error) {
   375  	return &UintCode{typ: typ, bitSize: intSize, isString: true}, nil
   376  }
   377  
   378  //nolint:unparam
   379  func (c *Compiler) uint8StringCode(typ *runtime.Type) (*UintCode, error) {
   380  	return &UintCode{typ: typ, bitSize: 8, isString: true}, nil
   381  }
   382  
   383  //nolint:unparam
   384  func (c *Compiler) uint16StringCode(typ *runtime.Type) (*UintCode, error) {
   385  	return &UintCode{typ: typ, bitSize: 16, isString: true}, nil
   386  }
   387  
   388  //nolint:unparam
   389  func (c *Compiler) uint32StringCode(typ *runtime.Type) (*UintCode, error) {
   390  	return &UintCode{typ: typ, bitSize: 32, isString: true}, nil
   391  }
   392  
   393  //nolint:unparam
   394  func (c *Compiler) uint64StringCode(typ *runtime.Type) (*UintCode, error) {
   395  	return &UintCode{typ: typ, bitSize: 64, isString: true}, nil
   396  }
   397  
   398  //nolint:unparam
   399  func (c *Compiler) bytesCode(typ *runtime.Type, isPtr bool) (*BytesCode, error) {
   400  	return &BytesCode{typ: typ, isPtr: isPtr}, nil
   401  }
   402  
   403  //nolint:unparam
   404  func (c *Compiler) interfaceCode(typ *runtime.Type, isPtr bool) (*InterfaceCode, error) {
   405  	return &InterfaceCode{typ: typ, isPtr: isPtr}, nil
   406  }
   407  
   408  //nolint:unparam
   409  func (c *Compiler) marshalJSONCode(typ *runtime.Type) (*MarshalJSONCode, error) {
   410  	return &MarshalJSONCode{
   411  		typ:                typ,
   412  		isAddrForMarshaler: c.isPtrMarshalJSONType(typ),
   413  		isNilableType:      c.isNilableType(typ),
   414  		isMarshalerContext: typ.Implements(marshalJSONContextType) || runtime.PtrTo(typ).Implements(marshalJSONContextType),
   415  	}, nil
   416  }
   417  
   418  //nolint:unparam
   419  func (c *Compiler) marshalTextCode(typ *runtime.Type) (*MarshalTextCode, error) {
   420  	return &MarshalTextCode{
   421  		typ:                typ,
   422  		isAddrForMarshaler: c.isPtrMarshalTextType(typ),
   423  		isNilableType:      c.isNilableType(typ),
   424  	}, nil
   425  }
   426  
   427  func (c *Compiler) ptrCode(typ *runtime.Type) (*PtrCode, error) {
   428  	code, err := c.typeToCodeWithPtr(typ.Elem(), true)
   429  	if err != nil {
   430  		return nil, err
   431  	}
   432  	ptr, ok := code.(*PtrCode)
   433  	if ok {
   434  		return &PtrCode{typ: typ, value: ptr.value, ptrNum: ptr.ptrNum + 1}, nil
   435  	}
   436  	return &PtrCode{typ: typ, value: code, ptrNum: 1}, nil
   437  }
   438  
   439  func (c *Compiler) sliceCode(typ *runtime.Type) (*SliceCode, error) {
   440  	elem := typ.Elem()
   441  	code, err := c.listElemCode(elem)
   442  	if err != nil {
   443  		return nil, err
   444  	}
   445  	if code.Kind() == CodeKindStruct {
   446  		structCode := code.(*StructCode)
   447  		structCode.enableIndirect()
   448  	}
   449  	return &SliceCode{typ: typ, value: code}, nil
   450  }
   451  
   452  func (c *Compiler) arrayCode(typ *runtime.Type) (*ArrayCode, error) {
   453  	elem := typ.Elem()
   454  	code, err := c.listElemCode(elem)
   455  	if err != nil {
   456  		return nil, err
   457  	}
   458  	if code.Kind() == CodeKindStruct {
   459  		structCode := code.(*StructCode)
   460  		structCode.enableIndirect()
   461  	}
   462  	return &ArrayCode{typ: typ, value: code}, nil
   463  }
   464  
   465  func (c *Compiler) mapCode(typ *runtime.Type) (*MapCode, error) {
   466  	keyCode, err := c.mapKeyCode(typ.Key())
   467  	if err != nil {
   468  		return nil, err
   469  	}
   470  	valueCode, err := c.mapValueCode(typ.Elem())
   471  	if err != nil {
   472  		return nil, err
   473  	}
   474  	if valueCode.Kind() == CodeKindStruct {
   475  		structCode := valueCode.(*StructCode)
   476  		structCode.enableIndirect()
   477  	}
   478  	return &MapCode{typ: typ, key: keyCode, value: valueCode}, nil
   479  }
   480  
   481  func (c *Compiler) listElemCode(typ *runtime.Type) (Code, error) {
   482  	switch {
   483  	case c.isPtrMarshalJSONType(typ):
   484  		return c.marshalJSONCode(typ)
   485  	case !typ.Implements(marshalTextType) && runtime.PtrTo(typ).Implements(marshalTextType):
   486  		return c.marshalTextCode(typ)
   487  	case typ.Kind() == reflect.Map:
   488  		return c.ptrCode(runtime.PtrTo(typ))
   489  	default:
   490  		// isPtr was originally used to indicate whether the type of top level is pointer.
   491  		// However, since the slice/array element is a specification that can get the pointer address, explicitly set isPtr to true.
   492  		// See here for related issues: https://git.gammaspectra.live/P2Pool/go-json/issues/370
   493  		code, err := c.typeToCodeWithPtr(typ, true)
   494  		if err != nil {
   495  			return nil, err
   496  		}
   497  		ptr, ok := code.(*PtrCode)
   498  		if ok {
   499  			if ptr.value.Kind() == CodeKindMap {
   500  				ptr.ptrNum++
   501  			}
   502  		}
   503  		return code, nil
   504  	}
   505  }
   506  
   507  func (c *Compiler) mapKeyCode(typ *runtime.Type) (Code, error) {
   508  	switch {
   509  	case c.implementsMarshalText(typ):
   510  		return c.marshalTextCode(typ)
   511  	}
   512  	switch typ.Kind() {
   513  	case reflect.Ptr:
   514  		return c.ptrCode(typ)
   515  	case reflect.String:
   516  		return c.stringCode(typ, false)
   517  	case reflect.Int:
   518  		return c.intStringCode(typ)
   519  	case reflect.Int8:
   520  		return c.int8StringCode(typ)
   521  	case reflect.Int16:
   522  		return c.int16StringCode(typ)
   523  	case reflect.Int32:
   524  		return c.int32StringCode(typ)
   525  	case reflect.Int64:
   526  		return c.int64StringCode(typ)
   527  	case reflect.Uint:
   528  		return c.uintStringCode(typ)
   529  	case reflect.Uint8:
   530  		return c.uint8StringCode(typ)
   531  	case reflect.Uint16:
   532  		return c.uint16StringCode(typ)
   533  	case reflect.Uint32:
   534  		return c.uint32StringCode(typ)
   535  	case reflect.Uint64:
   536  		return c.uint64StringCode(typ)
   537  	case reflect.Uintptr:
   538  		return c.uintStringCode(typ)
   539  	}
   540  	return nil, &errors.UnsupportedTypeError{Type: runtime.RType2Type(typ)}
   541  }
   542  
   543  func (c *Compiler) mapValueCode(typ *runtime.Type) (Code, error) {
   544  	switch typ.Kind() {
   545  	case reflect.Map:
   546  		return c.ptrCode(runtime.PtrTo(typ))
   547  	default:
   548  		code, err := c.typeToCodeWithPtr(typ, false)
   549  		if err != nil {
   550  			return nil, err
   551  		}
   552  		ptr, ok := code.(*PtrCode)
   553  		if ok {
   554  			if ptr.value.Kind() == CodeKindMap {
   555  				ptr.ptrNum++
   556  			}
   557  		}
   558  		return code, nil
   559  	}
   560  }
   561  
   562  func (c *Compiler) structCode(typ *runtime.Type, isPtr bool) (*StructCode, error) {
   563  	typeptr := uintptr(unsafe.Pointer(typ))
   564  	if code, exists := c.structTypeToCode[typeptr]; exists {
   565  		derefCode := *code
   566  		derefCode.isRecursive = true
   567  		return &derefCode, nil
   568  	}
   569  	indirect := runtime.IfaceIndir(typ)
   570  	code := &StructCode{typ: typ, isPtr: isPtr, isIndirect: indirect}
   571  	c.structTypeToCode[typeptr] = code
   572  
   573  	fieldNum := typ.NumField()
   574  	tags := c.typeToStructTags(typ)
   575  	fields := []*StructFieldCode{}
   576  	for i, tag := range tags {
   577  		isOnlyOneFirstField := i == 0 && fieldNum == 1
   578  		field, err := c.structFieldCode(code, tag, isPtr, isOnlyOneFirstField)
   579  		if err != nil {
   580  			return nil, err
   581  		}
   582  		if field.isAnonymous {
   583  			structCode := field.getAnonymousStruct()
   584  			if structCode != nil {
   585  				structCode.removeFieldsByTags(tags)
   586  				if c.isAssignableIndirect(field, isPtr) {
   587  					if indirect {
   588  						structCode.isIndirect = true
   589  					} else {
   590  						structCode.isIndirect = false
   591  					}
   592  				}
   593  			}
   594  		} else {
   595  			structCode := field.getStruct()
   596  			if structCode != nil {
   597  				if indirect {
   598  					// if parent is indirect type, set child indirect property to true
   599  					structCode.isIndirect = true
   600  				} else {
   601  					// if parent is not indirect type, set child indirect property to false.
   602  					// but if parent's indirect is false and isPtr is true, then indirect must be true.
   603  					// Do this only if indirectConversion is enabled at the end of compileStruct.
   604  					structCode.isIndirect = false
   605  				}
   606  			}
   607  		}
   608  		fields = append(fields, field)
   609  	}
   610  	fieldMap := c.getFieldMap(fields)
   611  	duplicatedFieldMap := c.getDuplicatedFieldMap(fieldMap)
   612  	code.fields = c.filteredDuplicatedFields(fields, duplicatedFieldMap)
   613  	if !code.disableIndirectConversion && !indirect && isPtr {
   614  		code.enableIndirect()
   615  	}
   616  	delete(c.structTypeToCode, typeptr)
   617  	return code, nil
   618  }
   619  
   620  func toElemType(t *runtime.Type) *runtime.Type {
   621  	for t.Kind() == reflect.Ptr {
   622  		t = t.Elem()
   623  	}
   624  	return t
   625  }
   626  
   627  func (c *Compiler) structFieldCode(structCode *StructCode, tag *runtime.StructTag, isPtr, isOnlyOneFirstField bool) (*StructFieldCode, error) {
   628  	field := tag.Field
   629  	fieldType := runtime.Type2RType(field.Type)
   630  	isIndirectSpecialCase := isPtr && isOnlyOneFirstField
   631  	fieldCode := &StructFieldCode{
   632  		typ:           fieldType,
   633  		key:           tag.Key,
   634  		tag:           tag,
   635  		offset:        field.Offset,
   636  		isAnonymous:   field.Anonymous && !tag.IsTaggedKey && toElemType(fieldType).Kind() == reflect.Struct,
   637  		isTaggedKey:   tag.IsTaggedKey,
   638  		isNilableType: c.isNilableType(fieldType),
   639  		isNilCheck:    true,
   640  	}
   641  	switch {
   642  	case c.isMovePointerPositionFromHeadToFirstMarshalJSONFieldCase(fieldType, isIndirectSpecialCase):
   643  		code, err := c.marshalJSONCode(fieldType)
   644  		if err != nil {
   645  			return nil, err
   646  		}
   647  		fieldCode.value = code
   648  		fieldCode.isAddrForMarshaler = true
   649  		fieldCode.isNilCheck = false
   650  		structCode.isIndirect = false
   651  		structCode.disableIndirectConversion = true
   652  	case c.isMovePointerPositionFromHeadToFirstMarshalTextFieldCase(fieldType, isIndirectSpecialCase):
   653  		code, err := c.marshalTextCode(fieldType)
   654  		if err != nil {
   655  			return nil, err
   656  		}
   657  		fieldCode.value = code
   658  		fieldCode.isAddrForMarshaler = true
   659  		fieldCode.isNilCheck = false
   660  		structCode.isIndirect = false
   661  		structCode.disableIndirectConversion = true
   662  	case isPtr && c.isPtrMarshalJSONType(fieldType):
   663  		// *struct{ field T }
   664  		// func (*T) MarshalJSON() ([]byte, error)
   665  		code, err := c.marshalJSONCode(fieldType)
   666  		if err != nil {
   667  			return nil, err
   668  		}
   669  		fieldCode.value = code
   670  		fieldCode.isAddrForMarshaler = true
   671  		fieldCode.isNilCheck = false
   672  	case isPtr && c.isPtrMarshalTextType(fieldType):
   673  		// *struct{ field T }
   674  		// func (*T) MarshalText() ([]byte, error)
   675  		code, err := c.marshalTextCode(fieldType)
   676  		if err != nil {
   677  			return nil, err
   678  		}
   679  		fieldCode.value = code
   680  		fieldCode.isAddrForMarshaler = true
   681  		fieldCode.isNilCheck = false
   682  	default:
   683  		code, err := c.typeToCodeWithPtr(fieldType, isPtr)
   684  		if err != nil {
   685  			return nil, err
   686  		}
   687  		switch code.Kind() {
   688  		case CodeKindPtr, CodeKindInterface:
   689  			fieldCode.isNextOpPtrType = true
   690  		}
   691  		fieldCode.value = code
   692  	}
   693  	return fieldCode, nil
   694  }
   695  
   696  func (c *Compiler) isAssignableIndirect(fieldCode *StructFieldCode, isPtr bool) bool {
   697  	if isPtr {
   698  		return false
   699  	}
   700  	codeType := fieldCode.value.Kind()
   701  	if codeType == CodeKindMarshalJSON {
   702  		return false
   703  	}
   704  	if codeType == CodeKindMarshalText {
   705  		return false
   706  	}
   707  	return true
   708  }
   709  
   710  func (c *Compiler) getFieldMap(fields []*StructFieldCode) map[string][]*StructFieldCode {
   711  	fieldMap := map[string][]*StructFieldCode{}
   712  	for _, field := range fields {
   713  		if field.isAnonymous {
   714  			for k, v := range c.getAnonymousFieldMap(field) {
   715  				fieldMap[k] = append(fieldMap[k], v...)
   716  			}
   717  			continue
   718  		}
   719  		fieldMap[field.key] = append(fieldMap[field.key], field)
   720  	}
   721  	return fieldMap
   722  }
   723  
   724  func (c *Compiler) getAnonymousFieldMap(field *StructFieldCode) map[string][]*StructFieldCode {
   725  	fieldMap := map[string][]*StructFieldCode{}
   726  	structCode := field.getAnonymousStruct()
   727  	if structCode == nil || structCode.isRecursive {
   728  		fieldMap[field.key] = append(fieldMap[field.key], field)
   729  		return fieldMap
   730  	}
   731  	for k, v := range c.getFieldMapFromAnonymousParent(structCode.fields) {
   732  		fieldMap[k] = append(fieldMap[k], v...)
   733  	}
   734  	return fieldMap
   735  }
   736  
   737  func (c *Compiler) getFieldMapFromAnonymousParent(fields []*StructFieldCode) map[string][]*StructFieldCode {
   738  	fieldMap := map[string][]*StructFieldCode{}
   739  	for _, field := range fields {
   740  		if field.isAnonymous {
   741  			for k, v := range c.getAnonymousFieldMap(field) {
   742  				// Do not handle tagged key when embedding more than once
   743  				for _, vv := range v {
   744  					vv.isTaggedKey = false
   745  				}
   746  				fieldMap[k] = append(fieldMap[k], v...)
   747  			}
   748  			continue
   749  		}
   750  		fieldMap[field.key] = append(fieldMap[field.key], field)
   751  	}
   752  	return fieldMap
   753  }
   754  
   755  func (c *Compiler) getDuplicatedFieldMap(fieldMap map[string][]*StructFieldCode) map[*StructFieldCode]struct{} {
   756  	duplicatedFieldMap := map[*StructFieldCode]struct{}{}
   757  	for _, fields := range fieldMap {
   758  		if len(fields) == 1 {
   759  			continue
   760  		}
   761  		if c.isTaggedKeyOnly(fields) {
   762  			for _, field := range fields {
   763  				if field.isTaggedKey {
   764  					continue
   765  				}
   766  				duplicatedFieldMap[field] = struct{}{}
   767  			}
   768  		} else {
   769  			for _, field := range fields {
   770  				duplicatedFieldMap[field] = struct{}{}
   771  			}
   772  		}
   773  	}
   774  	return duplicatedFieldMap
   775  }
   776  
   777  func (c *Compiler) filteredDuplicatedFields(fields []*StructFieldCode, duplicatedFieldMap map[*StructFieldCode]struct{}) []*StructFieldCode {
   778  	filteredFields := make([]*StructFieldCode, 0, len(fields))
   779  	for _, field := range fields {
   780  		if field.isAnonymous {
   781  			structCode := field.getAnonymousStruct()
   782  			if structCode != nil && !structCode.isRecursive {
   783  				structCode.fields = c.filteredDuplicatedFields(structCode.fields, duplicatedFieldMap)
   784  				if len(structCode.fields) > 0 {
   785  					filteredFields = append(filteredFields, field)
   786  				}
   787  				continue
   788  			}
   789  		}
   790  		if _, exists := duplicatedFieldMap[field]; exists {
   791  			continue
   792  		}
   793  		filteredFields = append(filteredFields, field)
   794  	}
   795  	return filteredFields
   796  }
   797  
   798  func (c *Compiler) isTaggedKeyOnly(fields []*StructFieldCode) bool {
   799  	var taggedKeyFieldCount int
   800  	for _, field := range fields {
   801  		if field.isTaggedKey {
   802  			taggedKeyFieldCount++
   803  		}
   804  	}
   805  	return taggedKeyFieldCount == 1
   806  }
   807  
   808  func (c *Compiler) typeToStructTags(typ *runtime.Type) runtime.StructTags {
   809  	tags := runtime.StructTags{}
   810  	fieldNum := typ.NumField()
   811  	for i := 0; i < fieldNum; i++ {
   812  		field := typ.Field(i)
   813  		if runtime.IsIgnoredStructField(field) {
   814  			continue
   815  		}
   816  		tags = append(tags, runtime.StructTagFromField(field))
   817  	}
   818  	return tags
   819  }
   820  
   821  // *struct{ field T } => struct { field *T }
   822  // func (*T) MarshalJSON() ([]byte, error)
   823  func (c *Compiler) isMovePointerPositionFromHeadToFirstMarshalJSONFieldCase(typ *runtime.Type, isIndirectSpecialCase bool) bool {
   824  	return isIndirectSpecialCase && !c.isNilableType(typ) && c.isPtrMarshalJSONType(typ)
   825  }
   826  
   827  // *struct{ field T } => struct { field *T }
   828  // func (*T) MarshalText() ([]byte, error)
   829  func (c *Compiler) isMovePointerPositionFromHeadToFirstMarshalTextFieldCase(typ *runtime.Type, isIndirectSpecialCase bool) bool {
   830  	return isIndirectSpecialCase && !c.isNilableType(typ) && c.isPtrMarshalTextType(typ)
   831  }
   832  
   833  func (c *Compiler) implementsMarshalJSON(typ *runtime.Type) bool {
   834  	if !c.implementsMarshalJSONType(typ) {
   835  		return false
   836  	}
   837  	if typ.Kind() != reflect.Ptr {
   838  		return true
   839  	}
   840  	// type kind is reflect.Ptr
   841  	if !c.implementsMarshalJSONType(typ.Elem()) {
   842  		return true
   843  	}
   844  	// needs to dereference
   845  	return false
   846  }
   847  
   848  func (c *Compiler) implementsMarshalText(typ *runtime.Type) bool {
   849  	if !typ.Implements(marshalTextType) {
   850  		return false
   851  	}
   852  	if typ.Kind() != reflect.Ptr {
   853  		return true
   854  	}
   855  	// type kind is reflect.Ptr
   856  	if !typ.Elem().Implements(marshalTextType) {
   857  		return true
   858  	}
   859  	// needs to dereference
   860  	return false
   861  }
   862  
   863  func (c *Compiler) isNilableType(typ *runtime.Type) bool {
   864  	if !runtime.IfaceIndir(typ) {
   865  		return true
   866  	}
   867  	switch typ.Kind() {
   868  	case reflect.Ptr:
   869  		return true
   870  	case reflect.Map:
   871  		return true
   872  	case reflect.Func:
   873  		return true
   874  	default:
   875  		return false
   876  	}
   877  }
   878  
   879  func (c *Compiler) implementsMarshalJSONType(typ *runtime.Type) bool {
   880  	return typ.Implements(marshalJSONType) || typ.Implements(marshalJSONContextType)
   881  }
   882  
   883  func (c *Compiler) isPtrMarshalJSONType(typ *runtime.Type) bool {
   884  	return !c.implementsMarshalJSONType(typ) && c.implementsMarshalJSONType(runtime.PtrTo(typ))
   885  }
   886  
   887  func (c *Compiler) isPtrMarshalTextType(typ *runtime.Type) bool {
   888  	return !typ.Implements(marshalTextType) && runtime.PtrTo(typ).Implements(marshalTextType)
   889  }
   890  
   891  func (c *Compiler) codeToOpcode(ctx *compileContext, typ *runtime.Type, code Code) *Opcode {
   892  	codes := code.ToOpcode(ctx)
   893  	codes.Last().Next = newEndOp(ctx, typ)
   894  	c.linkRecursiveCode(ctx)
   895  	return codes.First()
   896  }
   897  
   898  func (c *Compiler) linkRecursiveCode(ctx *compileContext) {
   899  	recursiveCodes := map[uintptr]*CompiledCode{}
   900  	for _, recursive := range *ctx.recursiveCodes {
   901  		typeptr := uintptr(unsafe.Pointer(recursive.Type))
   902  		codes := ctx.structTypeToCodes[typeptr]
   903  		if recursiveCode, ok := recursiveCodes[typeptr]; ok {
   904  			*recursive.Jmp = *recursiveCode
   905  			continue
   906  		}
   907  
   908  		code := copyOpcode(codes.First())
   909  		code.Op = code.Op.PtrHeadToHead()
   910  		lastCode := newEndOp(&compileContext{}, recursive.Type)
   911  		lastCode.Op = OpRecursiveEnd
   912  
   913  		// OpRecursiveEnd must set before call TotalLength
   914  		code.End.Next = lastCode
   915  
   916  		totalLength := code.TotalLength()
   917  
   918  		// Idx, ElemIdx, Length must set after call TotalLength
   919  		lastCode.Idx = uint32((totalLength + 1) * uintptrSize)
   920  		lastCode.ElemIdx = lastCode.Idx + uintptrSize
   921  		lastCode.Length = lastCode.Idx + 2*uintptrSize
   922  
   923  		// extend length to alloc slot for elemIdx + length
   924  		curTotalLength := uintptr(recursive.TotalLength()) + 3
   925  		nextTotalLength := uintptr(totalLength) + 3
   926  
   927  		compiled := recursive.Jmp
   928  		compiled.Code = code
   929  		compiled.CurLen = curTotalLength
   930  		compiled.NextLen = nextTotalLength
   931  		compiled.Linked = true
   932  
   933  		recursiveCodes[typeptr] = compiled
   934  	}
   935  }