forked from mirror/go-json
Merge pull request #45 from goccy/feature/update-encode-engine
Upgrade encoding engine to the 2nd generation
This commit is contained in:
commit
eb088b8b76
|
@ -220,6 +220,7 @@ func (t opType) fieldToStringTagField() opType {
|
|||
opTypes := []opType{
|
||||
{"End", "EndIndent", "Op"},
|
||||
{"Interface", "InterfaceIndent", "Op"},
|
||||
{"InterfaceEnd", "InterfaceEndIndent", "Op"},
|
||||
{"Ptr", "PtrIndent", "Op"},
|
||||
{"SliceHead", "SliceHeadIndent", "SliceHead"},
|
||||
{"RootSliceHead", "RootSliceHeadIndent", "SliceHead"},
|
||||
|
@ -252,6 +253,7 @@ func (t opType) fieldToStringTagField() opType {
|
|||
{"StructFieldOmitEmpty", "StructFieldOmitEmptyIndent", "StructField"},
|
||||
{"StructFieldStringTag", "StructFieldStringTagIndent", "StructField"},
|
||||
{"StructFieldRecursive", "StructFieldRecursiveIndent", "StructFieldRecursive"},
|
||||
{"StructFieldRecursiveEnd", "StructFieldRecursiveEndIndent", "Op"},
|
||||
{"StructEnd", "StructEndIndent", "StructField"},
|
||||
{"StructAnonymousEnd", "StructAnonymousEndIndent", "StructField"},
|
||||
}
|
||||
|
|
71
encode.go
71
encode.go
|
@ -19,7 +19,6 @@ type Encoder struct {
|
|||
enabledHTMLEscape bool
|
||||
prefix []byte
|
||||
indentStr []byte
|
||||
indent int
|
||||
structTypeToCompiledCode map[uintptr]*compiledCode
|
||||
structTypeToCompiledIndentCode map[uintptr]*compiledCode
|
||||
}
|
||||
|
@ -37,8 +36,9 @@ type opcodeMap struct {
|
|||
}
|
||||
|
||||
type opcodeSet struct {
|
||||
codeIndent sync.Pool
|
||||
code sync.Pool
|
||||
codeIndent *opcode
|
||||
code *opcode
|
||||
ctx sync.Pool
|
||||
}
|
||||
|
||||
func (m *opcodeMap) get(k uintptr) *opcodeSet {
|
||||
|
@ -123,7 +123,6 @@ func (e *Encoder) release() {
|
|||
|
||||
func (e *Encoder) reset() {
|
||||
e.buf = e.buf[:0]
|
||||
e.indent = 0
|
||||
e.enabledHTMLEscape = true
|
||||
e.enabledIndent = false
|
||||
}
|
||||
|
@ -159,54 +158,68 @@ func (e *Encoder) encode(v interface{}) error {
|
|||
if codeSet := cachedOpcode.get(typeptr); codeSet != nil {
|
||||
var code *opcode
|
||||
if e.enabledIndent {
|
||||
code = codeSet.codeIndent.Get().(*opcode)
|
||||
code = codeSet.codeIndent
|
||||
} else {
|
||||
code = codeSet.code.Get().(*opcode)
|
||||
code = codeSet.code
|
||||
}
|
||||
ctx := codeSet.ctx.Get().(*encodeRuntimeContext)
|
||||
p := uintptr(header.ptr)
|
||||
code.ptr = p
|
||||
if err := e.run(code); err != nil {
|
||||
return err
|
||||
}
|
||||
if e.enabledIndent {
|
||||
codeSet.codeIndent.Put(code)
|
||||
} else {
|
||||
codeSet.code.Put(code)
|
||||
}
|
||||
return nil
|
||||
ctx.init(p)
|
||||
err := e.run(ctx, code)
|
||||
codeSet.ctx.Put(ctx)
|
||||
return err
|
||||
}
|
||||
|
||||
// noescape trick for header.typ ( reflect.*rtype )
|
||||
copiedType := (*rtype)(unsafe.Pointer(typeptr))
|
||||
|
||||
codeIndent, err := e.compileHead(copiedType, true)
|
||||
codeIndent, err := e.compileHead(&encodeCompileContext{
|
||||
typ: copiedType,
|
||||
root: true,
|
||||
withIndent: true,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
code, err := e.compileHead(copiedType, false)
|
||||
code, err := e.compileHead(&encodeCompileContext{
|
||||
typ: copiedType,
|
||||
root: true,
|
||||
withIndent: false,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
codeLength := code.totalLength()
|
||||
codeSet := &opcodeSet{
|
||||
codeIndent: sync.Pool{
|
||||
codeIndent: codeIndent,
|
||||
code: code,
|
||||
ctx: sync.Pool{
|
||||
New: func() interface{} {
|
||||
return copyOpcode(codeIndent)
|
||||
},
|
||||
},
|
||||
code: sync.Pool{
|
||||
New: func() interface{} {
|
||||
return copyOpcode(code)
|
||||
return &encodeRuntimeContext{
|
||||
ptrs: make([]uintptr, codeLength),
|
||||
keepRefs: make([]unsafe.Pointer, 8),
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
cachedOpcode.set(typeptr, codeSet)
|
||||
p := uintptr(header.ptr)
|
||||
ctx := codeSet.ctx.Get().(*encodeRuntimeContext)
|
||||
ctx.init(p)
|
||||
|
||||
var c *opcode
|
||||
if e.enabledIndent {
|
||||
codeIndent.ptr = p
|
||||
return e.run(codeIndent)
|
||||
c = codeIndent
|
||||
} else {
|
||||
c = code
|
||||
}
|
||||
code.ptr = p
|
||||
return e.run(code)
|
||||
|
||||
if err := e.run(ctx, c); err != nil {
|
||||
codeSet.ctx.Put(ctx)
|
||||
return err
|
||||
}
|
||||
codeSet.ctx.Put(ctx)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *Encoder) encodeInt(v int) {
|
||||
|
|
|
@ -6,17 +6,17 @@ import (
|
|||
"unsafe"
|
||||
)
|
||||
|
||||
func (e *Encoder) compileHead(typ *rtype, withIndent bool) (*opcode, error) {
|
||||
root := true
|
||||
func (e *Encoder) compileHead(ctx *encodeCompileContext) (*opcode, error) {
|
||||
typ := ctx.typ
|
||||
switch {
|
||||
case typ.Implements(marshalJSONType):
|
||||
return newOpCode(opMarshalJSON, typ, e.indent, newEndOp(e.indent)), nil
|
||||
return e.compileMarshalJSON(ctx)
|
||||
case rtype_ptrTo(typ).Implements(marshalJSONType):
|
||||
return newOpCode(opMarshalJSON, rtype_ptrTo(typ), e.indent, newEndOp(e.indent)), nil
|
||||
return e.compileMarshalJSONPtr(ctx)
|
||||
case typ.Implements(marshalTextType):
|
||||
return newOpCode(opMarshalText, typ, e.indent, newEndOp(e.indent)), nil
|
||||
return e.compileMarshalText(ctx)
|
||||
case rtype_ptrTo(typ).Implements(marshalTextType):
|
||||
return newOpCode(opMarshalText, rtype_ptrTo(typ), e.indent, newEndOp(e.indent)), nil
|
||||
return e.compileMarshalTextPtr(ctx)
|
||||
}
|
||||
isPtr := false
|
||||
if typ.Kind() == reflect.Ptr {
|
||||
|
@ -24,11 +24,11 @@ func (e *Encoder) compileHead(typ *rtype, withIndent bool) (*opcode, error) {
|
|||
isPtr = true
|
||||
}
|
||||
if typ.Kind() == reflect.Map {
|
||||
return e.compileMap(typ, isPtr, root, withIndent)
|
||||
return e.compileMap(ctx.withType(typ), isPtr)
|
||||
} else if typ.Kind() == reflect.Struct {
|
||||
return e.compileStruct(typ, isPtr, root, withIndent)
|
||||
return e.compileStruct(ctx.withType(typ), isPtr)
|
||||
}
|
||||
return e.compile(typ, root, withIndent)
|
||||
return e.compile(ctx.withType(typ))
|
||||
}
|
||||
|
||||
func (e *Encoder) implementsMarshaler(typ *rtype) bool {
|
||||
|
@ -45,215 +45,240 @@ func (e *Encoder) implementsMarshaler(typ *rtype) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func (e *Encoder) compile(typ *rtype, root, withIndent bool) (*opcode, error) {
|
||||
func (e *Encoder) compile(ctx *encodeCompileContext) (*opcode, error) {
|
||||
typ := ctx.typ
|
||||
switch {
|
||||
case typ.Implements(marshalJSONType):
|
||||
return newOpCode(opMarshalJSON, typ, e.indent, newEndOp(e.indent)), nil
|
||||
return e.compileMarshalJSON(ctx)
|
||||
case rtype_ptrTo(typ).Implements(marshalJSONType):
|
||||
return newOpCode(opMarshalJSON, rtype_ptrTo(typ), e.indent, newEndOp(e.indent)), nil
|
||||
return e.compileMarshalJSONPtr(ctx)
|
||||
case typ.Implements(marshalTextType):
|
||||
return newOpCode(opMarshalText, typ, e.indent, newEndOp(e.indent)), nil
|
||||
return e.compileMarshalText(ctx)
|
||||
case rtype_ptrTo(typ).Implements(marshalTextType):
|
||||
return newOpCode(opMarshalText, rtype_ptrTo(typ), e.indent, newEndOp(e.indent)), nil
|
||||
return e.compileMarshalTextPtr(ctx)
|
||||
}
|
||||
switch typ.Kind() {
|
||||
case reflect.Ptr:
|
||||
return e.compilePtr(typ, root, withIndent)
|
||||
return e.compilePtr(ctx)
|
||||
case reflect.Slice:
|
||||
elem := typ.Elem()
|
||||
if !e.implementsMarshaler(elem) && elem.Kind() == reflect.Uint8 {
|
||||
return e.compileBytes(typ)
|
||||
return e.compileBytes(ctx)
|
||||
}
|
||||
return e.compileSlice(typ, root, withIndent)
|
||||
return e.compileSlice(ctx)
|
||||
case reflect.Array:
|
||||
return e.compileArray(typ, root, withIndent)
|
||||
return e.compileArray(ctx)
|
||||
case reflect.Map:
|
||||
return e.compileMap(typ, true, root, withIndent)
|
||||
return e.compileMap(ctx, true)
|
||||
case reflect.Struct:
|
||||
return e.compileStruct(typ, false, root, withIndent)
|
||||
return e.compileStruct(ctx, false)
|
||||
case reflect.Interface:
|
||||
return e.compileInterface(typ, root)
|
||||
return e.compileInterface(ctx)
|
||||
case reflect.Int:
|
||||
return e.compileInt(typ)
|
||||
return e.compileInt(ctx)
|
||||
case reflect.Int8:
|
||||
return e.compileInt8(typ)
|
||||
return e.compileInt8(ctx)
|
||||
case reflect.Int16:
|
||||
return e.compileInt16(typ)
|
||||
return e.compileInt16(ctx)
|
||||
case reflect.Int32:
|
||||
return e.compileInt32(typ)
|
||||
return e.compileInt32(ctx)
|
||||
case reflect.Int64:
|
||||
return e.compileInt64(typ)
|
||||
return e.compileInt64(ctx)
|
||||
case reflect.Uint:
|
||||
return e.compileUint(typ)
|
||||
return e.compileUint(ctx)
|
||||
case reflect.Uint8:
|
||||
return e.compileUint8(typ)
|
||||
return e.compileUint8(ctx)
|
||||
case reflect.Uint16:
|
||||
return e.compileUint16(typ)
|
||||
return e.compileUint16(ctx)
|
||||
case reflect.Uint32:
|
||||
return e.compileUint32(typ)
|
||||
return e.compileUint32(ctx)
|
||||
case reflect.Uint64:
|
||||
return e.compileUint64(typ)
|
||||
return e.compileUint64(ctx)
|
||||
case reflect.Uintptr:
|
||||
return e.compileUint(typ)
|
||||
return e.compileUint(ctx)
|
||||
case reflect.Float32:
|
||||
return e.compileFloat32(typ)
|
||||
return e.compileFloat32(ctx)
|
||||
case reflect.Float64:
|
||||
return e.compileFloat64(typ)
|
||||
return e.compileFloat64(ctx)
|
||||
case reflect.String:
|
||||
return e.compileString(typ)
|
||||
return e.compileString(ctx)
|
||||
case reflect.Bool:
|
||||
return e.compileBool(typ)
|
||||
return e.compileBool(ctx)
|
||||
}
|
||||
return nil, &UnsupportedTypeError{Type: rtype2type(typ)}
|
||||
}
|
||||
|
||||
func (e *Encoder) compileKey(typ *rtype, root, withIndent bool) (*opcode, error) {
|
||||
func (e *Encoder) compileKey(ctx *encodeCompileContext) (*opcode, error) {
|
||||
typ := ctx.typ
|
||||
switch {
|
||||
case typ.Implements(marshalJSONType):
|
||||
return newOpCode(opMarshalJSON, typ, e.indent, newEndOp(e.indent)), nil
|
||||
return e.compileMarshalJSON(ctx)
|
||||
case rtype_ptrTo(typ).Implements(marshalJSONType):
|
||||
return newOpCode(opMarshalJSON, rtype_ptrTo(typ), e.indent, newEndOp(e.indent)), nil
|
||||
return e.compileMarshalJSONPtr(ctx)
|
||||
case typ.Implements(marshalTextType):
|
||||
return newOpCode(opMarshalText, typ, e.indent, newEndOp(e.indent)), nil
|
||||
return e.compileMarshalText(ctx)
|
||||
case rtype_ptrTo(typ).Implements(marshalTextType):
|
||||
return newOpCode(opMarshalText, rtype_ptrTo(typ), e.indent, newEndOp(e.indent)), nil
|
||||
return e.compileMarshalTextPtr(ctx)
|
||||
}
|
||||
switch typ.Kind() {
|
||||
case reflect.Ptr:
|
||||
return e.compilePtr(typ, root, withIndent)
|
||||
return e.compilePtr(ctx)
|
||||
case reflect.Interface:
|
||||
return e.compileInterface(typ, root)
|
||||
case reflect.Int:
|
||||
return e.compileInt(typ)
|
||||
case reflect.Int8:
|
||||
return e.compileInt8(typ)
|
||||
case reflect.Int16:
|
||||
return e.compileInt16(typ)
|
||||
case reflect.Int32:
|
||||
return e.compileInt32(typ)
|
||||
case reflect.Int64:
|
||||
return e.compileInt64(typ)
|
||||
case reflect.Uint:
|
||||
return e.compileUint(typ)
|
||||
case reflect.Uint8:
|
||||
return e.compileUint8(typ)
|
||||
case reflect.Uint16:
|
||||
return e.compileUint16(typ)
|
||||
case reflect.Uint32:
|
||||
return e.compileUint32(typ)
|
||||
case reflect.Uint64:
|
||||
return e.compileUint64(typ)
|
||||
case reflect.Uintptr:
|
||||
return e.compileUint(typ)
|
||||
case reflect.Float32:
|
||||
return e.compileFloat32(typ)
|
||||
case reflect.Float64:
|
||||
return e.compileFloat64(typ)
|
||||
return e.compileInterface(ctx)
|
||||
case reflect.String:
|
||||
return e.compileString(typ)
|
||||
case reflect.Bool:
|
||||
return e.compileBool(typ)
|
||||
return e.compileString(ctx)
|
||||
}
|
||||
return nil, &UnsupportedTypeError{Type: rtype2type(typ)}
|
||||
}
|
||||
|
||||
func (e *Encoder) optimizeStructFieldPtrHead(typ *rtype, code *opcode) *opcode {
|
||||
ptrHeadOp := code.op.headToPtrHead()
|
||||
if code.op != ptrHeadOp {
|
||||
code.op = ptrHeadOp
|
||||
return code
|
||||
}
|
||||
return newOpCode(opPtr, typ, e.indent, code)
|
||||
}
|
||||
|
||||
func (e *Encoder) compilePtr(typ *rtype, root, withIndent bool) (*opcode, error) {
|
||||
code, err := e.compile(typ.Elem(), root, withIndent)
|
||||
func (e *Encoder) compilePtr(ctx *encodeCompileContext) (*opcode, error) {
|
||||
ptrOpcodeIndex := ctx.opcodeIndex
|
||||
ctx.incIndex()
|
||||
code, err := e.compile(ctx.withType(ctx.typ.Elem()))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return e.optimizeStructFieldPtrHead(typ, code), nil
|
||||
ptrHeadOp := code.op.headToPtrHead()
|
||||
if code.op != ptrHeadOp {
|
||||
code.op = ptrHeadOp
|
||||
code.decOpcodeIndex()
|
||||
ctx.decIndex()
|
||||
return code, nil
|
||||
}
|
||||
c := ctx.context()
|
||||
c.opcodeIndex = ptrOpcodeIndex
|
||||
return newOpCodeWithNext(c, opPtr, code), nil
|
||||
}
|
||||
|
||||
func (e *Encoder) compileInt(typ *rtype) (*opcode, error) {
|
||||
return newOpCode(opInt, typ, e.indent, newEndOp(e.indent)), nil
|
||||
func (e *Encoder) compileMarshalJSON(ctx *encodeCompileContext) (*opcode, error) {
|
||||
code := newOpCode(ctx, opMarshalJSON)
|
||||
ctx.incIndex()
|
||||
return code, nil
|
||||
}
|
||||
|
||||
func (e *Encoder) compileInt8(typ *rtype) (*opcode, error) {
|
||||
return newOpCode(opInt8, typ, e.indent, newEndOp(e.indent)), nil
|
||||
func (e *Encoder) compileMarshalJSONPtr(ctx *encodeCompileContext) (*opcode, error) {
|
||||
code := newOpCode(ctx.withType(rtype_ptrTo(ctx.typ)), opMarshalJSON)
|
||||
ctx.incIndex()
|
||||
return code, nil
|
||||
}
|
||||
|
||||
func (e *Encoder) compileInt16(typ *rtype) (*opcode, error) {
|
||||
return newOpCode(opInt16, typ, e.indent, newEndOp(e.indent)), nil
|
||||
func (e *Encoder) compileMarshalText(ctx *encodeCompileContext) (*opcode, error) {
|
||||
code := newOpCode(ctx, opMarshalText)
|
||||
ctx.incIndex()
|
||||
return code, nil
|
||||
}
|
||||
|
||||
func (e *Encoder) compileInt32(typ *rtype) (*opcode, error) {
|
||||
return newOpCode(opInt32, typ, e.indent, newEndOp(e.indent)), nil
|
||||
func (e *Encoder) compileMarshalTextPtr(ctx *encodeCompileContext) (*opcode, error) {
|
||||
code := newOpCode(ctx.withType(rtype_ptrTo(ctx.typ)), opMarshalText)
|
||||
ctx.incIndex()
|
||||
return code, nil
|
||||
}
|
||||
|
||||
func (e *Encoder) compileInt64(typ *rtype) (*opcode, error) {
|
||||
return newOpCode(opInt64, typ, e.indent, newEndOp(e.indent)), nil
|
||||
func (e *Encoder) compileInt(ctx *encodeCompileContext) (*opcode, error) {
|
||||
code := newOpCode(ctx, opInt)
|
||||
ctx.incIndex()
|
||||
return code, nil
|
||||
}
|
||||
|
||||
func (e *Encoder) compileUint(typ *rtype) (*opcode, error) {
|
||||
return newOpCode(opUint, typ, e.indent, newEndOp(e.indent)), nil
|
||||
func (e *Encoder) compileInt8(ctx *encodeCompileContext) (*opcode, error) {
|
||||
code := newOpCode(ctx, opInt8)
|
||||
ctx.incIndex()
|
||||
return code, nil
|
||||
}
|
||||
|
||||
func (e *Encoder) compileUint8(typ *rtype) (*opcode, error) {
|
||||
return newOpCode(opUint8, typ, e.indent, newEndOp(e.indent)), nil
|
||||
func (e *Encoder) compileInt16(ctx *encodeCompileContext) (*opcode, error) {
|
||||
code := newOpCode(ctx, opInt16)
|
||||
ctx.incIndex()
|
||||
return code, nil
|
||||
}
|
||||
|
||||
func (e *Encoder) compileUint16(typ *rtype) (*opcode, error) {
|
||||
return newOpCode(opUint16, typ, e.indent, newEndOp(e.indent)), nil
|
||||
func (e *Encoder) compileInt32(ctx *encodeCompileContext) (*opcode, error) {
|
||||
code := newOpCode(ctx, opInt32)
|
||||
ctx.incIndex()
|
||||
return code, nil
|
||||
}
|
||||
|
||||
func (e *Encoder) compileUint32(typ *rtype) (*opcode, error) {
|
||||
return newOpCode(opUint32, typ, e.indent, newEndOp(e.indent)), nil
|
||||
func (e *Encoder) compileInt64(ctx *encodeCompileContext) (*opcode, error) {
|
||||
code := newOpCode(ctx, opInt64)
|
||||
ctx.incIndex()
|
||||
return code, nil
|
||||
}
|
||||
|
||||
func (e *Encoder) compileUint64(typ *rtype) (*opcode, error) {
|
||||
return newOpCode(opUint64, typ, e.indent, newEndOp(e.indent)), nil
|
||||
func (e *Encoder) compileUint(ctx *encodeCompileContext) (*opcode, error) {
|
||||
code := newOpCode(ctx, opUint)
|
||||
ctx.incIndex()
|
||||
return code, nil
|
||||
}
|
||||
|
||||
func (e *Encoder) compileFloat32(typ *rtype) (*opcode, error) {
|
||||
return newOpCode(opFloat32, typ, e.indent, newEndOp(e.indent)), nil
|
||||
func (e *Encoder) compileUint8(ctx *encodeCompileContext) (*opcode, error) {
|
||||
code := newOpCode(ctx, opUint8)
|
||||
ctx.incIndex()
|
||||
return code, nil
|
||||
}
|
||||
|
||||
func (e *Encoder) compileFloat64(typ *rtype) (*opcode, error) {
|
||||
return newOpCode(opFloat64, typ, e.indent, newEndOp(e.indent)), nil
|
||||
func (e *Encoder) compileUint16(ctx *encodeCompileContext) (*opcode, error) {
|
||||
code := newOpCode(ctx, opUint16)
|
||||
ctx.incIndex()
|
||||
return code, nil
|
||||
}
|
||||
|
||||
func (e *Encoder) compileString(typ *rtype) (*opcode, error) {
|
||||
return newOpCode(opString, typ, e.indent, newEndOp(e.indent)), nil
|
||||
func (e *Encoder) compileUint32(ctx *encodeCompileContext) (*opcode, error) {
|
||||
code := newOpCode(ctx, opUint32)
|
||||
ctx.incIndex()
|
||||
return code, nil
|
||||
}
|
||||
|
||||
func (e *Encoder) compileBool(typ *rtype) (*opcode, error) {
|
||||
return newOpCode(opBool, typ, e.indent, newEndOp(e.indent)), nil
|
||||
func (e *Encoder) compileUint64(ctx *encodeCompileContext) (*opcode, error) {
|
||||
code := newOpCode(ctx, opUint64)
|
||||
ctx.incIndex()
|
||||
return code, nil
|
||||
}
|
||||
|
||||
func (e *Encoder) compileBytes(typ *rtype) (*opcode, error) {
|
||||
return newOpCode(opBytes, typ, e.indent, newEndOp(e.indent)), nil
|
||||
func (e *Encoder) compileFloat32(ctx *encodeCompileContext) (*opcode, error) {
|
||||
code := newOpCode(ctx, opFloat32)
|
||||
ctx.incIndex()
|
||||
return code, nil
|
||||
}
|
||||
|
||||
func (e *Encoder) compileInterface(typ *rtype, root bool) (*opcode, error) {
|
||||
return (*opcode)(unsafe.Pointer(&interfaceCode{
|
||||
opcodeHeader: &opcodeHeader{
|
||||
op: opInterface,
|
||||
typ: typ,
|
||||
indent: e.indent,
|
||||
next: newEndOp(e.indent),
|
||||
},
|
||||
root: root,
|
||||
})), nil
|
||||
func (e *Encoder) compileFloat64(ctx *encodeCompileContext) (*opcode, error) {
|
||||
code := newOpCode(ctx, opFloat64)
|
||||
ctx.incIndex()
|
||||
return code, nil
|
||||
}
|
||||
|
||||
func (e *Encoder) compileSlice(typ *rtype, root, withIndent bool) (*opcode, error) {
|
||||
elem := typ.Elem()
|
||||
func (e *Encoder) compileString(ctx *encodeCompileContext) (*opcode, error) {
|
||||
code := newOpCode(ctx, opString)
|
||||
ctx.incIndex()
|
||||
return code, nil
|
||||
}
|
||||
|
||||
func (e *Encoder) compileBool(ctx *encodeCompileContext) (*opcode, error) {
|
||||
code := newOpCode(ctx, opBool)
|
||||
ctx.incIndex()
|
||||
return code, nil
|
||||
}
|
||||
|
||||
func (e *Encoder) compileBytes(ctx *encodeCompileContext) (*opcode, error) {
|
||||
code := newOpCode(ctx, opBytes)
|
||||
ctx.incIndex()
|
||||
return code, nil
|
||||
}
|
||||
|
||||
func (e *Encoder) compileInterface(ctx *encodeCompileContext) (*opcode, error) {
|
||||
code := newInterfaceCode(ctx)
|
||||
ctx.incIndex()
|
||||
return code, nil
|
||||
}
|
||||
|
||||
func (e *Encoder) compileSlice(ctx *encodeCompileContext) (*opcode, error) {
|
||||
ctx.root = false
|
||||
elem := ctx.typ.Elem()
|
||||
size := elem.Size()
|
||||
|
||||
e.indent++
|
||||
code, err := e.compile(elem, false, withIndent)
|
||||
e.indent--
|
||||
header := newSliceHeaderCode(ctx)
|
||||
ctx.incIndex()
|
||||
|
||||
code, err := e.compile(ctx.withType(ctx.typ.Elem()).incIndent())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -262,17 +287,13 @@ func (e *Encoder) compileSlice(typ *rtype, root, withIndent bool) (*opcode, erro
|
|||
// ^ |
|
||||
// |________|
|
||||
|
||||
header := newSliceHeaderCode(e.indent)
|
||||
elemCode := &sliceElemCode{
|
||||
opcodeHeader: &opcodeHeader{
|
||||
op: opSliceElem,
|
||||
indent: e.indent,
|
||||
},
|
||||
size: size,
|
||||
}
|
||||
end := newOpCode(opSliceEnd, nil, e.indent, newEndOp(e.indent))
|
||||
if withIndent {
|
||||
if root {
|
||||
elemCode := newSliceElemCode(ctx, header, size)
|
||||
ctx.incIndex()
|
||||
|
||||
end := newOpCode(ctx, opSliceEnd)
|
||||
ctx.incIndex()
|
||||
if ctx.withIndent {
|
||||
if ctx.root {
|
||||
header.op = opRootSliceHeadIndent
|
||||
elemCode.op = opRootSliceElemIndent
|
||||
} else {
|
||||
|
@ -291,15 +312,17 @@ func (e *Encoder) compileSlice(typ *rtype, root, withIndent bool) (*opcode, erro
|
|||
return (*opcode)(unsafe.Pointer(header)), nil
|
||||
}
|
||||
|
||||
func (e *Encoder) compileArray(typ *rtype, root, withIndent bool) (*opcode, error) {
|
||||
func (e *Encoder) compileArray(ctx *encodeCompileContext) (*opcode, error) {
|
||||
ctx.root = false
|
||||
typ := ctx.typ
|
||||
elem := typ.Elem()
|
||||
alen := typ.Len()
|
||||
size := elem.Size()
|
||||
|
||||
e.indent++
|
||||
code, err := e.compile(elem, false, withIndent)
|
||||
e.indent--
|
||||
header := newArrayHeaderCode(ctx, alen)
|
||||
ctx.incIndex()
|
||||
|
||||
code, err := e.compile(ctx.withType(elem).incIndent())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -307,17 +330,13 @@ func (e *Encoder) compileArray(typ *rtype, root, withIndent bool) (*opcode, erro
|
|||
// ^ |
|
||||
// |________|
|
||||
|
||||
header := newArrayHeaderCode(e.indent, alen)
|
||||
elemCode := &arrayElemCode{
|
||||
opcodeHeader: &opcodeHeader{
|
||||
op: opArrayElem,
|
||||
},
|
||||
len: uintptr(alen),
|
||||
size: size,
|
||||
}
|
||||
end := newOpCode(opArrayEnd, nil, e.indent, newEndOp(e.indent))
|
||||
elemCode := newArrayElemCode(ctx, header, alen, size)
|
||||
ctx.incIndex()
|
||||
|
||||
if withIndent {
|
||||
end := newOpCode(ctx, opArrayEnd)
|
||||
ctx.incIndex()
|
||||
|
||||
if ctx.withIndent {
|
||||
header.op = opArrayHeadIndent
|
||||
elemCode.op = opArrayElemIndent
|
||||
end.op = opArrayEndIndent
|
||||
|
@ -348,35 +367,43 @@ func mapiternext(it unsafe.Pointer)
|
|||
//go:noescape
|
||||
func maplen(m unsafe.Pointer) int
|
||||
|
||||
func (e *Encoder) compileMap(typ *rtype, withLoad, root, withIndent bool) (*opcode, error) {
|
||||
func (e *Encoder) compileMap(ctx *encodeCompileContext, withLoad bool) (*opcode, error) {
|
||||
// header => code => value => code => key => code => value => code => end
|
||||
// ^ |
|
||||
// |_______________________|
|
||||
e.indent++
|
||||
keyType := typ.Key()
|
||||
keyCode, err := e.compileKey(keyType, false, withIndent)
|
||||
ctx = ctx.incIndent()
|
||||
header := newMapHeaderCode(ctx, withLoad)
|
||||
ctx.incIndex()
|
||||
|
||||
typ := ctx.typ
|
||||
keyType := ctx.typ.Key()
|
||||
keyCode, err := e.compileKey(ctx.withType(keyType))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
value := newMapValueCode(ctx, header)
|
||||
ctx.incIndex()
|
||||
|
||||
valueType := typ.Elem()
|
||||
valueCode, err := e.compile(valueType, false, withIndent)
|
||||
valueCode, err := e.compile(ctx.withType(valueType))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
key := newMapKeyCode(e.indent)
|
||||
value := newMapValueCode(e.indent)
|
||||
key := newMapKeyCode(ctx, header)
|
||||
ctx.incIndex()
|
||||
|
||||
e.indent--
|
||||
ctx = ctx.decIndent()
|
||||
|
||||
header := newMapHeaderCode(typ, withLoad, e.indent)
|
||||
header.key = key
|
||||
header.value = value
|
||||
end := newOpCode(opMapEnd, nil, e.indent, newEndOp(e.indent))
|
||||
header.mapKey = key
|
||||
header.mapValue = value
|
||||
end := newOpCode(ctx, opMapEnd)
|
||||
ctx.incIndex()
|
||||
|
||||
if withIndent {
|
||||
if ctx.withIndent {
|
||||
if header.op == opMapHead {
|
||||
if root {
|
||||
if ctx.root {
|
||||
header.op = opRootMapHeadIndent
|
||||
} else {
|
||||
header.op = opMapHeadIndent
|
||||
|
@ -384,7 +411,7 @@ func (e *Encoder) compileMap(typ *rtype, withLoad, root, withIndent bool) (*opco
|
|||
} else {
|
||||
header.op = opMapHeadLoadIndent
|
||||
}
|
||||
if root {
|
||||
if ctx.root {
|
||||
key.op = opRootMapKeyIndent
|
||||
} else {
|
||||
key.op = opMapKeyIndent
|
||||
|
@ -549,35 +576,30 @@ func (e *Encoder) optimizeStructField(op opType, tag *structTag, withIndent bool
|
|||
return fieldType
|
||||
}
|
||||
|
||||
func (e *Encoder) recursiveCode(typ *rtype, code *compiledCode) *opcode {
|
||||
return (*opcode)(unsafe.Pointer(&recursiveCode{
|
||||
opcodeHeader: &opcodeHeader{
|
||||
op: opStructFieldRecursive,
|
||||
typ: typ,
|
||||
indent: e.indent,
|
||||
next: newEndOp(e.indent),
|
||||
},
|
||||
jmp: code,
|
||||
}))
|
||||
func (e *Encoder) recursiveCode(ctx *encodeCompileContext, jmp *compiledCode) *opcode {
|
||||
code := newRecursiveCode(ctx, jmp)
|
||||
ctx.incIndex()
|
||||
return code
|
||||
}
|
||||
|
||||
func (e *Encoder) compiledCode(typ *rtype, withIndent bool) *opcode {
|
||||
func (e *Encoder) compiledCode(ctx *encodeCompileContext) *opcode {
|
||||
typ := ctx.typ
|
||||
typeptr := uintptr(unsafe.Pointer(typ))
|
||||
if withIndent {
|
||||
if ctx.withIndent {
|
||||
if compiledCode, exists := e.structTypeToCompiledIndentCode[typeptr]; exists {
|
||||
return e.recursiveCode(typ, compiledCode)
|
||||
return e.recursiveCode(ctx, compiledCode)
|
||||
}
|
||||
} else {
|
||||
if compiledCode, exists := e.structTypeToCompiledCode[typeptr]; exists {
|
||||
return e.recursiveCode(typ, compiledCode)
|
||||
return e.recursiveCode(ctx, compiledCode)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *Encoder) structHeader(fieldCode *structFieldCode, valueCode *opcode, tag *structTag, withIndent bool) *opcode {
|
||||
func (e *Encoder) structHeader(ctx *encodeCompileContext, fieldCode *opcode, valueCode *opcode, tag *structTag) *opcode {
|
||||
fieldCode.indent--
|
||||
op := e.optimizeStructHeader(valueCode.op, tag, withIndent)
|
||||
op := e.optimizeStructHeader(valueCode.op, tag, ctx.withIndent)
|
||||
fieldCode.op = op
|
||||
switch op {
|
||||
case opStructFieldHead,
|
||||
|
@ -608,12 +630,13 @@ func (e *Encoder) structHeader(fieldCode *structFieldCode, valueCode *opcode, ta
|
|||
opStructFieldHeadStringTagIndent:
|
||||
return valueCode.beforeLastCode()
|
||||
}
|
||||
ctx.decOpcodeIndex()
|
||||
return (*opcode)(unsafe.Pointer(fieldCode))
|
||||
}
|
||||
|
||||
func (e *Encoder) structField(fieldCode *structFieldCode, valueCode *opcode, tag *structTag, withIndent bool) *opcode {
|
||||
func (e *Encoder) structField(ctx *encodeCompileContext, fieldCode *opcode, valueCode *opcode, tag *structTag) *opcode {
|
||||
code := (*opcode)(unsafe.Pointer(fieldCode))
|
||||
op := e.optimizeStructField(valueCode.op, tag, withIndent)
|
||||
op := e.optimizeStructField(valueCode.op, tag, ctx.withIndent)
|
||||
fieldCode.op = op
|
||||
switch op {
|
||||
case opStructField,
|
||||
|
@ -644,10 +667,11 @@ func (e *Encoder) structField(fieldCode *structFieldCode, valueCode *opcode, tag
|
|||
opStructFieldStringTagIndent:
|
||||
return valueCode.beforeLastCode()
|
||||
}
|
||||
ctx.decIndex()
|
||||
return code
|
||||
}
|
||||
|
||||
func (e *Encoder) isNotExistsField(head *structFieldCode) bool {
|
||||
func (e *Encoder) isNotExistsField(head *opcode) bool {
|
||||
if head == nil {
|
||||
return false
|
||||
}
|
||||
|
@ -669,12 +693,12 @@ func (e *Encoder) isNotExistsField(head *structFieldCode) bool {
|
|||
if head.next.op.codeType() != codeStructField {
|
||||
return false
|
||||
}
|
||||
return e.isNotExistsField(head.next.toStructFieldCode())
|
||||
return e.isNotExistsField(head.next)
|
||||
}
|
||||
|
||||
func (e *Encoder) optimizeAnonymousFields(head *structFieldCode) {
|
||||
func (e *Encoder) optimizeAnonymousFields(head *opcode) {
|
||||
code := head
|
||||
var prev *structFieldCode
|
||||
var prev *opcode
|
||||
for {
|
||||
if code.op == opStructEnd || code.op == opStructEndIndent {
|
||||
break
|
||||
|
@ -682,29 +706,33 @@ func (e *Encoder) optimizeAnonymousFields(head *structFieldCode) {
|
|||
if code.op == opStructField || code.op == opStructFieldIndent {
|
||||
codeType := code.next.op.codeType()
|
||||
if codeType == codeStructField {
|
||||
if e.isNotExistsField(code.next.toStructFieldCode()) {
|
||||
if e.isNotExistsField(code.next) {
|
||||
code.next = code.nextField
|
||||
diff := code.next.displayIdx - code.displayIdx
|
||||
for i := 0; i < diff; i++ {
|
||||
code.next.decOpcodeIndex()
|
||||
}
|
||||
linkPrevToNextField(prev, code)
|
||||
code = prev
|
||||
}
|
||||
}
|
||||
}
|
||||
prev = code
|
||||
code = code.nextField.toStructFieldCode()
|
||||
code = code.nextField
|
||||
}
|
||||
}
|
||||
|
||||
type structFieldPair struct {
|
||||
prevField *structFieldCode
|
||||
curField *structFieldCode
|
||||
prevField *opcode
|
||||
curField *opcode
|
||||
isTaggedKey bool
|
||||
linked bool
|
||||
}
|
||||
|
||||
func (e *Encoder) anonymousStructFieldPairMap(typ *rtype, tags structTags, valueCode *structFieldCode) map[string][]structFieldPair {
|
||||
func (e *Encoder) anonymousStructFieldPairMap(typ *rtype, tags structTags, valueCode *opcode) map[string][]structFieldPair {
|
||||
anonymousFields := map[string][]structFieldPair{}
|
||||
f := valueCode
|
||||
var prevAnonymousField *structFieldCode
|
||||
var prevAnonymousField *opcode
|
||||
for {
|
||||
existsKey := tags.existsKey(f.displayKey)
|
||||
op := f.op.headToAnonymousHead()
|
||||
|
@ -717,6 +745,10 @@ func (e *Encoder) anonymousStructFieldPairMap(typ *rtype, tags structTags, value
|
|||
} else if f.op == opStructEnd {
|
||||
f.op = opStructAnonymousEnd
|
||||
} else if existsKey {
|
||||
diff := f.nextField.displayIdx - f.displayIdx
|
||||
for i := 0; i < diff; i++ {
|
||||
f.nextField.decOpcodeIndex()
|
||||
}
|
||||
linkPrevToNextField(prevAnonymousField, f)
|
||||
}
|
||||
|
||||
|
@ -725,7 +757,7 @@ func (e *Encoder) anonymousStructFieldPairMap(typ *rtype, tags structTags, value
|
|||
break
|
||||
}
|
||||
prevAnonymousField = f
|
||||
f = f.nextField.toStructFieldCode()
|
||||
f = f.nextField
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -735,7 +767,7 @@ func (e *Encoder) anonymousStructFieldPairMap(typ *rtype, tags structTags, value
|
|||
isTaggedKey: f.isTaggedKey,
|
||||
})
|
||||
if f.next != nil && f.nextField != f.next && f.next.op.codeType() == codeStructField {
|
||||
for k, v := range e.anonymousStructFieldPairMap(typ, tags, f.next.toStructFieldCode()) {
|
||||
for k, v := range e.anonymousStructFieldPairMap(typ, tags, f.next) {
|
||||
anonymousFields[k] = append(anonymousFields[k], v...)
|
||||
}
|
||||
}
|
||||
|
@ -743,7 +775,7 @@ func (e *Encoder) anonymousStructFieldPairMap(typ *rtype, tags structTags, value
|
|||
break
|
||||
}
|
||||
prevAnonymousField = f
|
||||
f = f.nextField.toStructFieldCode()
|
||||
f = f.nextField
|
||||
}
|
||||
return anonymousFields
|
||||
}
|
||||
|
@ -764,6 +796,10 @@ func (e *Encoder) optimizeConflictAnonymousFields(anonymousFields map[string][]s
|
|||
// head operation
|
||||
fieldPair.curField.op = opStructFieldAnonymousHead
|
||||
} else {
|
||||
diff := fieldPair.curField.nextField.displayIdx - fieldPair.curField.displayIdx
|
||||
for i := 0; i < diff; i++ {
|
||||
fieldPair.curField.nextField.decOpcodeIndex()
|
||||
}
|
||||
linkPrevToNextField(fieldPair.prevField, fieldPair.curField)
|
||||
}
|
||||
fieldPair.linked = true
|
||||
|
@ -777,6 +813,10 @@ func (e *Encoder) optimizeConflictAnonymousFields(anonymousFields map[string][]s
|
|||
// head operation
|
||||
fieldPair.curField.op = opStructFieldAnonymousHead
|
||||
} else {
|
||||
diff := fieldPair.curField.nextField.displayIdx - fieldPair.curField.displayIdx
|
||||
for i := 0; i < diff; i++ {
|
||||
fieldPair.curField.nextField.decOpcodeIndex()
|
||||
}
|
||||
linkPrevToNextField(fieldPair.prevField, fieldPair.curField)
|
||||
}
|
||||
fieldPair.linked = true
|
||||
|
@ -790,13 +830,15 @@ func (e *Encoder) optimizeConflictAnonymousFields(anonymousFields map[string][]s
|
|||
}
|
||||
}
|
||||
|
||||
func (e *Encoder) compileStruct(typ *rtype, isPtr, root, withIndent bool) (*opcode, error) {
|
||||
if code := e.compiledCode(typ, withIndent); code != nil {
|
||||
func (e *Encoder) compileStruct(ctx *encodeCompileContext, isPtr bool) (*opcode, error) {
|
||||
ctx.root = false
|
||||
if code := e.compiledCode(ctx); code != nil {
|
||||
return code, nil
|
||||
}
|
||||
typ := ctx.typ
|
||||
typeptr := uintptr(unsafe.Pointer(typ))
|
||||
compiled := &compiledCode{}
|
||||
if withIndent {
|
||||
if ctx.withIndent {
|
||||
e.structTypeToCompiledIndentCode[typeptr] = compiled
|
||||
} else {
|
||||
e.structTypeToCompiledCode[typeptr] = compiled
|
||||
|
@ -807,11 +849,11 @@ func (e *Encoder) compileStruct(typ *rtype, isPtr, root, withIndent bool) (*opco
|
|||
fieldNum := typ.NumField()
|
||||
fieldIdx := 0
|
||||
var (
|
||||
head *structFieldCode
|
||||
head *opcode
|
||||
code *opcode
|
||||
prevField *structFieldCode
|
||||
prevField *opcode
|
||||
)
|
||||
e.indent++
|
||||
ctx = ctx.incIndent()
|
||||
tags := structTags{}
|
||||
anonymousFields := map[string][]structFieldPair{}
|
||||
for i := 0; i < fieldNum; i++ {
|
||||
|
@ -833,12 +875,16 @@ func (e *Encoder) compileStruct(typ *rtype, isPtr, root, withIndent bool) (*opco
|
|||
fieldType = rtype_ptrTo(fieldType)
|
||||
}
|
||||
}
|
||||
valueCode, err := e.compile(fieldType, false, withIndent)
|
||||
fieldOpcodeIndex := ctx.opcodeIndex
|
||||
fieldPtrIndex := ctx.ptrIndex
|
||||
ctx.incIndex()
|
||||
valueCode, err := e.compile(ctx.withType(fieldType))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if field.Anonymous {
|
||||
for k, v := range e.anonymousStructFieldPairMap(typ, tags, valueCode.toStructFieldCode()) {
|
||||
for k, v := range e.anonymousStructFieldPairMap(typ, tags, valueCode) {
|
||||
anonymousFields[k] = append(anonymousFields[k], v...)
|
||||
}
|
||||
}
|
||||
|
@ -850,15 +896,16 @@ func (e *Encoder) compileStruct(typ *rtype, isPtr, root, withIndent bool) (*opco
|
|||
opUint, opUint8, opUint16, opUint32, opUint64,
|
||||
opFloat32, opFloat64, opBool, opString, opBytes:
|
||||
valueCode = valueCode.next
|
||||
ctx.decOpcodeIndex()
|
||||
}
|
||||
}
|
||||
key := fmt.Sprintf(`"%s":`, tag.key)
|
||||
fieldCode := &structFieldCode{
|
||||
opcodeHeader: &opcodeHeader{
|
||||
typ: valueCode.typ,
|
||||
next: valueCode,
|
||||
indent: e.indent,
|
||||
},
|
||||
fieldCode := &opcode{
|
||||
typ: valueCode.typ,
|
||||
displayIdx: fieldOpcodeIndex,
|
||||
idx: opcodeOffset(fieldPtrIndex),
|
||||
next: valueCode,
|
||||
indent: ctx.indent,
|
||||
anonymousKey: field.Anonymous,
|
||||
key: []byte(key),
|
||||
isTaggedKey: tag.isTaggedKey,
|
||||
|
@ -866,29 +913,51 @@ func (e *Encoder) compileStruct(typ *rtype, isPtr, root, withIndent bool) (*opco
|
|||
offset: field.Offset,
|
||||
}
|
||||
if fieldIdx == 0 {
|
||||
code = e.structHeader(fieldCode, valueCode, tag, withIndent)
|
||||
fieldCode.headIdx = fieldCode.idx
|
||||
code = e.structHeader(ctx, fieldCode, valueCode, tag)
|
||||
head = fieldCode
|
||||
prevField = fieldCode
|
||||
} else {
|
||||
fcode := (*opcode)(unsafe.Pointer(fieldCode))
|
||||
code.next = fcode
|
||||
code = e.structField(fieldCode, valueCode, tag, withIndent)
|
||||
prevField.nextField = fcode
|
||||
fieldCode.headIdx = head.headIdx
|
||||
code.next = fieldCode
|
||||
code = e.structField(ctx, fieldCode, valueCode, tag)
|
||||
prevField.nextField = fieldCode
|
||||
prevField = fieldCode
|
||||
}
|
||||
fieldIdx++
|
||||
}
|
||||
e.indent--
|
||||
ctx = ctx.decIndent()
|
||||
|
||||
structEndCode := (*opcode)(unsafe.Pointer(&structFieldCode{
|
||||
opcodeHeader: &opcodeHeader{
|
||||
op: opStructEnd,
|
||||
typ: nil,
|
||||
indent: e.indent,
|
||||
},
|
||||
}))
|
||||
structEndCode.next = newEndOp(e.indent)
|
||||
if withIndent {
|
||||
structEndCode := &opcode{
|
||||
op: opStructEnd,
|
||||
typ: nil,
|
||||
indent: ctx.indent,
|
||||
next: newEndOp(ctx),
|
||||
}
|
||||
|
||||
// no struct field
|
||||
if head == nil {
|
||||
head = &opcode{
|
||||
op: opStructFieldHead,
|
||||
typ: typ,
|
||||
displayIdx: ctx.opcodeIndex,
|
||||
idx: opcodeOffset(ctx.ptrIndex),
|
||||
headIdx: opcodeOffset(ctx.ptrIndex),
|
||||
indent: ctx.indent,
|
||||
nextField: structEndCode,
|
||||
}
|
||||
ctx.incIndex()
|
||||
if ctx.withIndent {
|
||||
head.op = opStructFieldHeadIndent
|
||||
}
|
||||
code = head
|
||||
}
|
||||
|
||||
structEndCode.displayIdx = ctx.opcodeIndex
|
||||
structEndCode.idx = opcodeOffset(ctx.ptrIndex)
|
||||
ctx.incIndex()
|
||||
|
||||
if ctx.withIndent {
|
||||
structEndCode.op = opStructEndIndent
|
||||
}
|
||||
|
||||
|
@ -896,21 +965,6 @@ func (e *Encoder) compileStruct(typ *rtype, isPtr, root, withIndent bool) (*opco
|
|||
prevField.nextField = structEndCode
|
||||
}
|
||||
|
||||
// no struct field
|
||||
if head == nil {
|
||||
head = &structFieldCode{
|
||||
opcodeHeader: &opcodeHeader{
|
||||
op: opStructFieldHead,
|
||||
typ: typ,
|
||||
indent: e.indent,
|
||||
},
|
||||
nextField: structEndCode,
|
||||
}
|
||||
if withIndent {
|
||||
head.op = opStructFieldHeadIndent
|
||||
}
|
||||
code = (*opcode)(unsafe.Pointer(head))
|
||||
}
|
||||
head.end = structEndCode
|
||||
code.next = structEndCode
|
||||
|
||||
|
@ -920,7 +974,7 @@ func (e *Encoder) compileStruct(typ *rtype, isPtr, root, withIndent bool) (*opco
|
|||
ret := (*opcode)(unsafe.Pointer(head))
|
||||
compiled.code = ret
|
||||
|
||||
if withIndent {
|
||||
if ctx.withIndent {
|
||||
delete(e.structTypeToCompiledIndentCode, typeptr)
|
||||
} else {
|
||||
delete(e.structTypeToCompiledCode, typeptr)
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
package json
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type encodeCompileContext struct {
|
||||
typ *rtype
|
||||
withIndent bool
|
||||
root bool
|
||||
opcodeIndex int
|
||||
ptrIndex int
|
||||
indent int
|
||||
|
||||
parent *encodeCompileContext
|
||||
}
|
||||
|
||||
func (c *encodeCompileContext) context() *encodeCompileContext {
|
||||
return &encodeCompileContext{
|
||||
typ: c.typ,
|
||||
withIndent: c.withIndent,
|
||||
root: c.root,
|
||||
opcodeIndex: c.opcodeIndex,
|
||||
ptrIndex: c.ptrIndex,
|
||||
indent: c.indent,
|
||||
parent: c,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *encodeCompileContext) withType(typ *rtype) *encodeCompileContext {
|
||||
ctx := c.context()
|
||||
ctx.typ = typ
|
||||
return ctx
|
||||
}
|
||||
|
||||
func (c *encodeCompileContext) incIndent() *encodeCompileContext {
|
||||
ctx := c.context()
|
||||
ctx.indent++
|
||||
return ctx
|
||||
}
|
||||
|
||||
func (c *encodeCompileContext) decIndent() *encodeCompileContext {
|
||||
ctx := c.context()
|
||||
ctx.indent--
|
||||
return ctx
|
||||
}
|
||||
|
||||
func (c *encodeCompileContext) incIndex() {
|
||||
c.incOpcodeIndex()
|
||||
c.incPtrIndex()
|
||||
}
|
||||
|
||||
func (c *encodeCompileContext) decIndex() {
|
||||
c.decOpcodeIndex()
|
||||
c.decPtrIndex()
|
||||
}
|
||||
|
||||
func (c *encodeCompileContext) incOpcodeIndex() {
|
||||
c.opcodeIndex++
|
||||
if c.parent != nil {
|
||||
c.parent.incOpcodeIndex()
|
||||
}
|
||||
}
|
||||
|
||||
func (c *encodeCompileContext) decOpcodeIndex() {
|
||||
c.opcodeIndex--
|
||||
if c.parent != nil {
|
||||
c.parent.decOpcodeIndex()
|
||||
}
|
||||
}
|
||||
|
||||
func (c *encodeCompileContext) incPtrIndex() {
|
||||
c.ptrIndex++
|
||||
if c.parent != nil {
|
||||
c.parent.incPtrIndex()
|
||||
}
|
||||
}
|
||||
|
||||
func (c *encodeCompileContext) decPtrIndex() {
|
||||
c.ptrIndex--
|
||||
if c.parent != nil {
|
||||
c.parent.decPtrIndex()
|
||||
}
|
||||
}
|
||||
|
||||
type encodeRuntimeContext struct {
|
||||
ptrs []uintptr
|
||||
keepRefs []unsafe.Pointer
|
||||
}
|
||||
|
||||
func (c *encodeRuntimeContext) init(p uintptr) {
|
||||
c.ptrs[0] = p
|
||||
c.keepRefs = c.keepRefs[:0]
|
||||
}
|
||||
|
||||
func (c *encodeRuntimeContext) ptr() uintptr {
|
||||
header := (*reflect.SliceHeader)(unsafe.Pointer(&c.ptrs))
|
||||
return header.Data
|
||||
}
|
756
encode_opcode.go
756
encode_opcode.go
|
@ -2,51 +2,61 @@ package json
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func copyOpcode(code *opcode) *opcode {
|
||||
codeMap := map[uintptr]*opcode{}
|
||||
return code.copy(codeMap)
|
||||
}
|
||||
|
||||
type opcodeHeader struct {
|
||||
op opType
|
||||
typ *rtype
|
||||
ptr uintptr
|
||||
indent int
|
||||
next *opcode
|
||||
}
|
||||
|
||||
func (h *opcodeHeader) copy(codeMap map[uintptr]*opcode) *opcodeHeader {
|
||||
return &opcodeHeader{
|
||||
op: h.op,
|
||||
typ: h.typ,
|
||||
ptr: h.ptr,
|
||||
indent: h.indent,
|
||||
next: h.next.copy(codeMap),
|
||||
}
|
||||
}
|
||||
var uintptrSize = unsafe.Sizeof(uintptr(0))
|
||||
|
||||
type opcode struct {
|
||||
*opcodeHeader
|
||||
op opType // operation type
|
||||
typ *rtype // go type
|
||||
displayIdx int // opcode index
|
||||
key []byte // struct field key
|
||||
displayKey string // key text to display
|
||||
isTaggedKey bool // whether tagged key
|
||||
anonymousKey bool // whether anonymous key
|
||||
root bool // whether root
|
||||
indent int // indent number
|
||||
|
||||
idx uintptr // offset to access ptr
|
||||
headIdx uintptr // offset to access slice/struct head
|
||||
elemIdx uintptr // offset to access array/slice/map elem
|
||||
length uintptr // offset to access slice/map length or array length
|
||||
mapIter uintptr // offset to access map iterator
|
||||
offset uintptr // offset size from struct header
|
||||
size uintptr // array/slice elem size
|
||||
|
||||
mapKey *opcode // map key
|
||||
mapValue *opcode // map value
|
||||
elem *opcode // array/slice elem
|
||||
end *opcode // array/slice/struct/map end
|
||||
nextField *opcode // next struct field
|
||||
next *opcode // next opcode
|
||||
jmp *compiledCode // for recursive call
|
||||
}
|
||||
|
||||
func newOpCode(op opType, typ *rtype, indent int, next *opcode) *opcode {
|
||||
func newOpCode(ctx *encodeCompileContext, op opType) *opcode {
|
||||
return newOpCodeWithNext(ctx, op, newEndOp(ctx))
|
||||
}
|
||||
|
||||
func opcodeOffset(idx int) uintptr {
|
||||
return uintptr(idx) * uintptrSize
|
||||
}
|
||||
|
||||
func newOpCodeWithNext(ctx *encodeCompileContext, op opType, next *opcode) *opcode {
|
||||
return &opcode{
|
||||
opcodeHeader: &opcodeHeader{
|
||||
op: op,
|
||||
typ: typ,
|
||||
indent: indent,
|
||||
next: next,
|
||||
},
|
||||
op: op,
|
||||
typ: ctx.typ,
|
||||
displayIdx: ctx.opcodeIndex,
|
||||
indent: ctx.indent,
|
||||
idx: opcodeOffset(ctx.ptrIndex),
|
||||
next: next,
|
||||
}
|
||||
}
|
||||
|
||||
func newEndOp(indent int) *opcode {
|
||||
return newOpCode(opEnd, nil, indent, nil)
|
||||
func newEndOp(ctx *encodeCompileContext) *opcode {
|
||||
return newOpCodeWithNext(ctx, opEnd, nil)
|
||||
}
|
||||
|
||||
func (c *opcode) beforeLastCode() *opcode {
|
||||
|
@ -54,12 +64,8 @@ func (c *opcode) beforeLastCode() *opcode {
|
|||
for {
|
||||
var nextCode *opcode
|
||||
switch code.op.codeType() {
|
||||
case codeArrayElem:
|
||||
nextCode = code.toArrayElemCode().end
|
||||
case codeSliceElem:
|
||||
nextCode = code.toSliceElemCode().end
|
||||
case codeMapKey:
|
||||
nextCode = code.toMapKeyCode().end
|
||||
case codeArrayElem, codeSliceElem, codeMapKey:
|
||||
nextCode = code.end
|
||||
default:
|
||||
nextCode = code.next
|
||||
}
|
||||
|
@ -71,270 +77,183 @@ func (c *opcode) beforeLastCode() *opcode {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (c *opcode) copy(codeMap map[uintptr]*opcode) *opcode {
|
||||
if c == nil {
|
||||
return nil
|
||||
func (c *opcode) totalLength() int {
|
||||
var idx int
|
||||
for code := c; code.op != opEnd; {
|
||||
idx = int(code.idx / uintptrSize)
|
||||
if code.op == opInterfaceEnd || code.op == opStructFieldRecursiveEnd {
|
||||
break
|
||||
}
|
||||
switch code.op.codeType() {
|
||||
case codeArrayElem, codeSliceElem, codeMapKey:
|
||||
code = code.end
|
||||
default:
|
||||
code = code.next
|
||||
}
|
||||
}
|
||||
addr := uintptr(unsafe.Pointer(c))
|
||||
if code, exists := codeMap[addr]; exists {
|
||||
return code
|
||||
}
|
||||
var code *opcode
|
||||
switch c.op.codeType() {
|
||||
case codeArrayHead:
|
||||
code = c.toArrayHeaderCode().copy(codeMap)
|
||||
case codeArrayElem:
|
||||
code = c.toArrayElemCode().copy(codeMap)
|
||||
case codeSliceHead:
|
||||
code = c.toSliceHeaderCode().copy(codeMap)
|
||||
case codeSliceElem:
|
||||
code = c.toSliceElemCode().copy(codeMap)
|
||||
case codeMapHead:
|
||||
code = c.toMapHeadCode().copy(codeMap)
|
||||
case codeMapKey:
|
||||
code = c.toMapKeyCode().copy(codeMap)
|
||||
case codeMapValue:
|
||||
code = c.toMapValueCode().copy(codeMap)
|
||||
case codeStructFieldRecursive:
|
||||
code = c.toRecursiveCode().copy(codeMap)
|
||||
case codeStructField:
|
||||
code = c.toStructFieldCode().copy(codeMap)
|
||||
default:
|
||||
code = &opcode{}
|
||||
codeMap[addr] = code
|
||||
return idx + 2 // opEnd + 1
|
||||
}
|
||||
|
||||
code.opcodeHeader = c.opcodeHeader.copy(codeMap)
|
||||
func (c *opcode) decOpcodeIndex() {
|
||||
for code := c; code.op != opEnd; {
|
||||
code.displayIdx--
|
||||
code.idx -= uintptrSize
|
||||
if code.headIdx > 0 {
|
||||
code.headIdx -= uintptrSize
|
||||
}
|
||||
if code.elemIdx > 0 {
|
||||
code.elemIdx -= uintptrSize
|
||||
}
|
||||
if code.mapIter > 0 {
|
||||
code.mapIter -= uintptrSize
|
||||
}
|
||||
if code.length > 0 && code.op.codeType() != codeArrayHead && code.op.codeType() != codeArrayElem {
|
||||
code.length -= uintptrSize
|
||||
}
|
||||
switch code.op.codeType() {
|
||||
case codeArrayElem, codeSliceElem, codeMapKey:
|
||||
code = code.end
|
||||
default:
|
||||
code = code.next
|
||||
}
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
func (c *opcode) dumpHead(code *opcode) string {
|
||||
var length uintptr
|
||||
if code.op.codeType() == codeArrayHead {
|
||||
length = code.length
|
||||
} else {
|
||||
length = code.length / uintptrSize
|
||||
}
|
||||
return fmt.Sprintf(
|
||||
`[%d]%s%s ([idx:%d][headIdx:%d][elemIdx:%d][length:%d])`,
|
||||
code.displayIdx,
|
||||
strings.Repeat("-", code.indent),
|
||||
code.op,
|
||||
code.idx/uintptrSize,
|
||||
code.headIdx/uintptrSize,
|
||||
code.elemIdx/uintptrSize,
|
||||
length,
|
||||
)
|
||||
}
|
||||
|
||||
func (c *opcode) dumpMapHead(code *opcode) string {
|
||||
return fmt.Sprintf(
|
||||
`[%d]%s%s ([idx:%d][headIdx:%d][elemIdx:%d][length:%d][mapIter:%d])`,
|
||||
code.displayIdx,
|
||||
strings.Repeat("-", code.indent),
|
||||
code.op,
|
||||
code.idx/uintptrSize,
|
||||
code.headIdx/uintptrSize,
|
||||
code.elemIdx/uintptrSize,
|
||||
code.length/uintptrSize,
|
||||
code.mapIter/uintptrSize,
|
||||
)
|
||||
}
|
||||
|
||||
func (c *opcode) dumpElem(code *opcode) string {
|
||||
var length uintptr
|
||||
if code.op.codeType() == codeArrayElem {
|
||||
length = code.length
|
||||
} else {
|
||||
length = code.length / uintptrSize
|
||||
}
|
||||
return fmt.Sprintf(
|
||||
`[%d]%s%s ([idx:%d][headIdx:%d][elemIdx:%d][length:%d][size:%d])`,
|
||||
code.displayIdx,
|
||||
strings.Repeat("-", code.indent),
|
||||
code.op,
|
||||
code.idx/uintptrSize,
|
||||
code.headIdx/uintptrSize,
|
||||
code.elemIdx/uintptrSize,
|
||||
length,
|
||||
code.size,
|
||||
)
|
||||
}
|
||||
|
||||
func (c *opcode) dumpField(code *opcode) string {
|
||||
return fmt.Sprintf(
|
||||
`[%d]%s%s ([idx:%d][key:%s][offset:%d][headIdx:%d])`,
|
||||
code.displayIdx,
|
||||
strings.Repeat("-", code.indent),
|
||||
code.op,
|
||||
code.idx/uintptrSize,
|
||||
code.displayKey,
|
||||
code.offset,
|
||||
code.headIdx/uintptrSize,
|
||||
)
|
||||
}
|
||||
|
||||
func (c *opcode) dumpKey(code *opcode) string {
|
||||
return fmt.Sprintf(
|
||||
`[%d]%s%s ([idx:%d][elemIdx:%d][length:%d][mapIter:%d])`,
|
||||
code.displayIdx,
|
||||
strings.Repeat("-", code.indent),
|
||||
code.op,
|
||||
code.idx/uintptrSize,
|
||||
code.elemIdx/uintptrSize,
|
||||
code.length/uintptrSize,
|
||||
code.mapIter/uintptrSize,
|
||||
)
|
||||
}
|
||||
|
||||
func (c *opcode) dumpValue(code *opcode) string {
|
||||
return fmt.Sprintf(
|
||||
`[%d]%s%s ([idx:%d][mapIter:%d])`,
|
||||
code.displayIdx,
|
||||
strings.Repeat("-", code.indent),
|
||||
code.op,
|
||||
code.idx/uintptrSize,
|
||||
code.mapIter/uintptrSize,
|
||||
)
|
||||
}
|
||||
|
||||
func (c *opcode) dump() string {
|
||||
codes := []string{}
|
||||
for code := c; code.op != opEnd; {
|
||||
indent := strings.Repeat(" ", code.indent)
|
||||
switch code.op.codeType() {
|
||||
case codeArrayElem:
|
||||
codes = append(codes, fmt.Sprintf("%s%s ( %p )", indent, code.op, unsafe.Pointer(code)))
|
||||
code = code.toArrayElemCode().end
|
||||
case codeSliceElem:
|
||||
codes = append(codes, fmt.Sprintf("%s%s ( %p )", indent, code.op, unsafe.Pointer(code)))
|
||||
code = code.toSliceElemCode().end
|
||||
case codeSliceHead:
|
||||
codes = append(codes, c.dumpHead(code))
|
||||
code = code.next
|
||||
case codeMapHead:
|
||||
codes = append(codes, c.dumpMapHead(code))
|
||||
code = code.next
|
||||
case codeArrayElem, codeSliceElem:
|
||||
codes = append(codes, c.dumpElem(code))
|
||||
code = code.end
|
||||
case codeMapKey:
|
||||
codes = append(codes, fmt.Sprintf("%s%s ( %p )", indent, code.op, unsafe.Pointer(code)))
|
||||
code = code.toMapKeyCode().end
|
||||
codes = append(codes, c.dumpKey(code))
|
||||
code = code.end
|
||||
case codeMapValue:
|
||||
codes = append(codes, c.dumpValue(code))
|
||||
code = code.next
|
||||
case codeStructField:
|
||||
sf := code.toStructFieldCode()
|
||||
key := sf.displayKey
|
||||
offset := sf.offset
|
||||
codes = append(codes, fmt.Sprintf("%s%s [%s:%d] ( %p )", indent, code.op, key, offset, unsafe.Pointer(code)))
|
||||
codes = append(codes, c.dumpField(code))
|
||||
code = code.next
|
||||
default:
|
||||
codes = append(codes, fmt.Sprintf("%s%s ( %p )", indent, code.op, unsafe.Pointer(code)))
|
||||
codes = append(codes, fmt.Sprintf(
|
||||
"[%d]%s%s ([idx:%d])",
|
||||
code.displayIdx,
|
||||
strings.Repeat("-", code.indent),
|
||||
code.op,
|
||||
code.idx/uintptrSize,
|
||||
))
|
||||
code = code.next
|
||||
}
|
||||
}
|
||||
return strings.Join(codes, "\n")
|
||||
}
|
||||
|
||||
func (c *opcode) toSliceHeaderCode() *sliceHeaderCode {
|
||||
return (*sliceHeaderCode)(unsafe.Pointer(c))
|
||||
}
|
||||
|
||||
func (c *opcode) toSliceElemCode() *sliceElemCode {
|
||||
return (*sliceElemCode)(unsafe.Pointer(c))
|
||||
}
|
||||
|
||||
func (c *opcode) toArrayHeaderCode() *arrayHeaderCode {
|
||||
return (*arrayHeaderCode)(unsafe.Pointer(c))
|
||||
}
|
||||
|
||||
func (c *opcode) toArrayElemCode() *arrayElemCode {
|
||||
return (*arrayElemCode)(unsafe.Pointer(c))
|
||||
}
|
||||
|
||||
func (c *opcode) toStructFieldCode() *structFieldCode {
|
||||
return (*structFieldCode)(unsafe.Pointer(c))
|
||||
}
|
||||
|
||||
func (c *opcode) toMapHeadCode() *mapHeaderCode {
|
||||
return (*mapHeaderCode)(unsafe.Pointer(c))
|
||||
}
|
||||
|
||||
func (c *opcode) toMapKeyCode() *mapKeyCode {
|
||||
return (*mapKeyCode)(unsafe.Pointer(c))
|
||||
}
|
||||
|
||||
func (c *opcode) toMapValueCode() *mapValueCode {
|
||||
return (*mapValueCode)(unsafe.Pointer(c))
|
||||
}
|
||||
|
||||
func (c *opcode) toInterfaceCode() *interfaceCode {
|
||||
return (*interfaceCode)(unsafe.Pointer(c))
|
||||
}
|
||||
|
||||
func (c *opcode) toRecursiveCode() *recursiveCode {
|
||||
return (*recursiveCode)(unsafe.Pointer(c))
|
||||
}
|
||||
|
||||
type sliceHeaderCode struct {
|
||||
*opcodeHeader
|
||||
elem *sliceElemCode
|
||||
end *opcode
|
||||
}
|
||||
|
||||
func newSliceHeaderCode(indent int) *sliceHeaderCode {
|
||||
return &sliceHeaderCode{
|
||||
opcodeHeader: &opcodeHeader{
|
||||
op: opSliceHead,
|
||||
indent: indent,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (c *sliceHeaderCode) copy(codeMap map[uintptr]*opcode) *opcode {
|
||||
if c == nil {
|
||||
return nil
|
||||
}
|
||||
addr := uintptr(unsafe.Pointer(c))
|
||||
if code, exists := codeMap[addr]; exists {
|
||||
return code
|
||||
}
|
||||
header := &sliceHeaderCode{}
|
||||
code := (*opcode)(unsafe.Pointer(header))
|
||||
codeMap[addr] = code
|
||||
|
||||
header.opcodeHeader = c.opcodeHeader.copy(codeMap)
|
||||
header.elem = (*sliceElemCode)(unsafe.Pointer(c.elem.copy(codeMap)))
|
||||
header.end = c.end.copy(codeMap)
|
||||
return code
|
||||
}
|
||||
|
||||
type sliceElemCode struct {
|
||||
*opcodeHeader
|
||||
idx uintptr
|
||||
len uintptr
|
||||
size uintptr
|
||||
data uintptr
|
||||
end *opcode
|
||||
}
|
||||
|
||||
func (c *sliceElemCode) set(header *reflect.SliceHeader) {
|
||||
c.idx = uintptr(0)
|
||||
c.len = uintptr(header.Len)
|
||||
c.data = header.Data
|
||||
}
|
||||
|
||||
func (c *sliceElemCode) copy(codeMap map[uintptr]*opcode) *opcode {
|
||||
if c == nil {
|
||||
return nil
|
||||
}
|
||||
addr := uintptr(unsafe.Pointer(c))
|
||||
if code, exists := codeMap[addr]; exists {
|
||||
return code
|
||||
}
|
||||
elem := &sliceElemCode{
|
||||
idx: c.idx,
|
||||
len: c.len,
|
||||
size: c.size,
|
||||
data: c.data,
|
||||
}
|
||||
code := (*opcode)(unsafe.Pointer(elem))
|
||||
codeMap[addr] = code
|
||||
|
||||
elem.opcodeHeader = c.opcodeHeader.copy(codeMap)
|
||||
elem.end = c.end.copy(codeMap)
|
||||
return code
|
||||
}
|
||||
|
||||
type arrayHeaderCode struct {
|
||||
*opcodeHeader
|
||||
len uintptr
|
||||
elem *arrayElemCode
|
||||
end *opcode
|
||||
}
|
||||
|
||||
func newArrayHeaderCode(indent, alen int) *arrayHeaderCode {
|
||||
return &arrayHeaderCode{
|
||||
opcodeHeader: &opcodeHeader{
|
||||
op: opArrayHead,
|
||||
indent: indent,
|
||||
},
|
||||
len: uintptr(alen),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *arrayHeaderCode) copy(codeMap map[uintptr]*opcode) *opcode {
|
||||
if c == nil {
|
||||
return nil
|
||||
}
|
||||
addr := uintptr(unsafe.Pointer(c))
|
||||
if code, exists := codeMap[addr]; exists {
|
||||
return code
|
||||
}
|
||||
header := &arrayHeaderCode{}
|
||||
code := (*opcode)(unsafe.Pointer(header))
|
||||
codeMap[addr] = code
|
||||
|
||||
header.opcodeHeader = c.opcodeHeader.copy(codeMap)
|
||||
header.len = c.len
|
||||
header.elem = (*arrayElemCode)(unsafe.Pointer(c.elem.copy(codeMap)))
|
||||
header.end = c.end.copy(codeMap)
|
||||
return code
|
||||
}
|
||||
|
||||
type arrayElemCode struct {
|
||||
*opcodeHeader
|
||||
idx uintptr
|
||||
len uintptr
|
||||
size uintptr
|
||||
end *opcode
|
||||
}
|
||||
|
||||
func (c *arrayElemCode) copy(codeMap map[uintptr]*opcode) *opcode {
|
||||
if c == nil {
|
||||
return nil
|
||||
}
|
||||
addr := uintptr(unsafe.Pointer(c))
|
||||
if code, exists := codeMap[addr]; exists {
|
||||
return code
|
||||
}
|
||||
elem := &arrayElemCode{
|
||||
idx: c.idx,
|
||||
len: c.len,
|
||||
size: c.size,
|
||||
}
|
||||
code := (*opcode)(unsafe.Pointer(elem))
|
||||
codeMap[addr] = code
|
||||
|
||||
elem.opcodeHeader = c.opcodeHeader.copy(codeMap)
|
||||
elem.end = c.end.copy(codeMap)
|
||||
return code
|
||||
}
|
||||
|
||||
type structFieldCode struct {
|
||||
*opcodeHeader
|
||||
key []byte
|
||||
displayKey string
|
||||
isTaggedKey bool
|
||||
offset uintptr
|
||||
anonymousKey bool
|
||||
nextField *opcode
|
||||
end *opcode
|
||||
}
|
||||
|
||||
func linkPrevToNextField(prev, cur *structFieldCode) {
|
||||
func linkPrevToNextField(prev, cur *opcode) {
|
||||
prev.nextField = cur.nextField
|
||||
code := prev.toOpcode()
|
||||
fcode := cur.toOpcode()
|
||||
code := prev
|
||||
fcode := cur
|
||||
for {
|
||||
var nextCode *opcode
|
||||
switch code.op.codeType() {
|
||||
case codeArrayElem:
|
||||
nextCode = code.toArrayElemCode().end
|
||||
case codeSliceElem:
|
||||
nextCode = code.toSliceElemCode().end
|
||||
case codeMapKey:
|
||||
nextCode = code.toMapKeyCode().end
|
||||
case codeArrayElem, codeSliceElem, codeMapKey:
|
||||
nextCode = code.end
|
||||
default:
|
||||
nextCode = code.next
|
||||
}
|
||||
|
@ -348,208 +267,133 @@ func linkPrevToNextField(prev, cur *structFieldCode) {
|
|||
}
|
||||
}
|
||||
|
||||
func (c *structFieldCode) toOpcode() *opcode {
|
||||
return (*opcode)(unsafe.Pointer(c))
|
||||
func newSliceHeaderCode(ctx *encodeCompileContext) *opcode {
|
||||
idx := opcodeOffset(ctx.ptrIndex)
|
||||
ctx.incPtrIndex()
|
||||
elemIdx := opcodeOffset(ctx.ptrIndex)
|
||||
ctx.incPtrIndex()
|
||||
length := opcodeOffset(ctx.ptrIndex)
|
||||
return &opcode{
|
||||
op: opSliceHead,
|
||||
displayIdx: ctx.opcodeIndex,
|
||||
idx: idx,
|
||||
headIdx: idx,
|
||||
elemIdx: elemIdx,
|
||||
length: length,
|
||||
indent: ctx.indent,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *structFieldCode) copy(codeMap map[uintptr]*opcode) *opcode {
|
||||
if c == nil {
|
||||
return nil
|
||||
func newSliceElemCode(ctx *encodeCompileContext, head *opcode, size uintptr) *opcode {
|
||||
return &opcode{
|
||||
op: opSliceElem,
|
||||
displayIdx: ctx.opcodeIndex,
|
||||
idx: opcodeOffset(ctx.ptrIndex),
|
||||
headIdx: head.idx,
|
||||
elemIdx: head.elemIdx,
|
||||
length: head.length,
|
||||
indent: ctx.indent,
|
||||
size: size,
|
||||
}
|
||||
addr := uintptr(unsafe.Pointer(c))
|
||||
if code, exists := codeMap[addr]; exists {
|
||||
return code
|
||||
}
|
||||
field := &structFieldCode{
|
||||
key: c.key,
|
||||
isTaggedKey: c.isTaggedKey,
|
||||
displayKey: c.displayKey,
|
||||
anonymousKey: c.anonymousKey,
|
||||
offset: c.offset,
|
||||
}
|
||||
code := (*opcode)(unsafe.Pointer(field))
|
||||
codeMap[addr] = code
|
||||
|
||||
field.opcodeHeader = c.opcodeHeader.copy(codeMap)
|
||||
field.nextField = c.nextField.copy(codeMap)
|
||||
field.end = c.end.copy(codeMap)
|
||||
return code
|
||||
}
|
||||
|
||||
type mapHeaderCode struct {
|
||||
*opcodeHeader
|
||||
key *mapKeyCode
|
||||
value *mapValueCode
|
||||
end *opcode
|
||||
func newArrayHeaderCode(ctx *encodeCompileContext, alen int) *opcode {
|
||||
idx := opcodeOffset(ctx.ptrIndex)
|
||||
ctx.incPtrIndex()
|
||||
elemIdx := opcodeOffset(ctx.ptrIndex)
|
||||
return &opcode{
|
||||
op: opArrayHead,
|
||||
displayIdx: ctx.opcodeIndex,
|
||||
idx: idx,
|
||||
headIdx: idx,
|
||||
elemIdx: elemIdx,
|
||||
indent: ctx.indent,
|
||||
length: uintptr(alen),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *mapHeaderCode) copy(codeMap map[uintptr]*opcode) *opcode {
|
||||
if c == nil {
|
||||
return nil
|
||||
func newArrayElemCode(ctx *encodeCompileContext, head *opcode, length int, size uintptr) *opcode {
|
||||
return &opcode{
|
||||
op: opArrayElem,
|
||||
displayIdx: ctx.opcodeIndex,
|
||||
idx: opcodeOffset(ctx.ptrIndex),
|
||||
elemIdx: head.elemIdx,
|
||||
headIdx: head.headIdx,
|
||||
length: uintptr(length),
|
||||
size: size,
|
||||
}
|
||||
addr := uintptr(unsafe.Pointer(c))
|
||||
if code, exists := codeMap[addr]; exists {
|
||||
return code
|
||||
}
|
||||
header := &mapHeaderCode{}
|
||||
code := (*opcode)(unsafe.Pointer(header))
|
||||
codeMap[addr] = code
|
||||
|
||||
header.opcodeHeader = c.opcodeHeader.copy(codeMap)
|
||||
header.key = (*mapKeyCode)(unsafe.Pointer(c.key.copy(codeMap)))
|
||||
header.value = (*mapValueCode)(unsafe.Pointer(c.value.copy(codeMap)))
|
||||
header.end = c.end.copy(codeMap)
|
||||
return code
|
||||
}
|
||||
|
||||
type mapKeyCode struct {
|
||||
*opcodeHeader
|
||||
idx int
|
||||
len int
|
||||
iter unsafe.Pointer
|
||||
end *opcode
|
||||
}
|
||||
|
||||
func (c *mapKeyCode) copy(codeMap map[uintptr]*opcode) *opcode {
|
||||
if c == nil {
|
||||
return nil
|
||||
}
|
||||
addr := uintptr(unsafe.Pointer(c))
|
||||
if code, exists := codeMap[addr]; exists {
|
||||
return code
|
||||
}
|
||||
key := &mapKeyCode{
|
||||
idx: c.idx,
|
||||
len: c.len,
|
||||
iter: c.iter,
|
||||
}
|
||||
code := (*opcode)(unsafe.Pointer(key))
|
||||
codeMap[addr] = code
|
||||
|
||||
key.opcodeHeader = c.opcodeHeader.copy(codeMap)
|
||||
key.end = c.end.copy(codeMap)
|
||||
return code
|
||||
}
|
||||
|
||||
func (c *mapKeyCode) set(len int, iter unsafe.Pointer) {
|
||||
c.idx = 0
|
||||
c.len = len
|
||||
c.iter = iter
|
||||
}
|
||||
|
||||
type mapValueCode struct {
|
||||
*opcodeHeader
|
||||
iter unsafe.Pointer
|
||||
}
|
||||
|
||||
func (c *mapValueCode) copy(codeMap map[uintptr]*opcode) *opcode {
|
||||
if c == nil {
|
||||
return nil
|
||||
}
|
||||
addr := uintptr(unsafe.Pointer(c))
|
||||
if code, exists := codeMap[addr]; exists {
|
||||
return code
|
||||
}
|
||||
value := &mapValueCode{
|
||||
iter: c.iter,
|
||||
}
|
||||
code := (*opcode)(unsafe.Pointer(value))
|
||||
codeMap[addr] = code
|
||||
|
||||
value.opcodeHeader = c.opcodeHeader.copy(codeMap)
|
||||
return code
|
||||
}
|
||||
|
||||
func (c *mapValueCode) set(iter unsafe.Pointer) {
|
||||
c.iter = iter
|
||||
}
|
||||
|
||||
func newMapHeaderCode(typ *rtype, withLoad bool, indent int) *mapHeaderCode {
|
||||
func newMapHeaderCode(ctx *encodeCompileContext, withLoad bool) *opcode {
|
||||
var op opType
|
||||
if withLoad {
|
||||
op = opMapHeadLoad
|
||||
} else {
|
||||
op = opMapHead
|
||||
}
|
||||
return &mapHeaderCode{
|
||||
opcodeHeader: &opcodeHeader{
|
||||
op: op,
|
||||
typ: typ,
|
||||
indent: indent,
|
||||
},
|
||||
idx := opcodeOffset(ctx.ptrIndex)
|
||||
ctx.incPtrIndex()
|
||||
elemIdx := opcodeOffset(ctx.ptrIndex)
|
||||
ctx.incPtrIndex()
|
||||
length := opcodeOffset(ctx.ptrIndex)
|
||||
ctx.incPtrIndex()
|
||||
mapIter := opcodeOffset(ctx.ptrIndex)
|
||||
return &opcode{
|
||||
op: op,
|
||||
typ: ctx.typ,
|
||||
displayIdx: ctx.opcodeIndex,
|
||||
idx: idx,
|
||||
elemIdx: elemIdx,
|
||||
length: length,
|
||||
mapIter: mapIter,
|
||||
indent: ctx.indent,
|
||||
}
|
||||
}
|
||||
|
||||
func newMapKeyCode(indent int) *mapKeyCode {
|
||||
return &mapKeyCode{
|
||||
opcodeHeader: &opcodeHeader{
|
||||
op: opMapKey,
|
||||
indent: indent,
|
||||
},
|
||||
func newMapKeyCode(ctx *encodeCompileContext, head *opcode) *opcode {
|
||||
return &opcode{
|
||||
op: opMapKey,
|
||||
displayIdx: ctx.opcodeIndex,
|
||||
idx: opcodeOffset(ctx.ptrIndex),
|
||||
elemIdx: head.elemIdx,
|
||||
length: head.length,
|
||||
mapIter: head.mapIter,
|
||||
indent: ctx.indent,
|
||||
}
|
||||
}
|
||||
|
||||
func newMapValueCode(indent int) *mapValueCode {
|
||||
return &mapValueCode{
|
||||
opcodeHeader: &opcodeHeader{
|
||||
op: opMapValue,
|
||||
indent: indent,
|
||||
},
|
||||
func newMapValueCode(ctx *encodeCompileContext, head *opcode) *opcode {
|
||||
return &opcode{
|
||||
op: opMapValue,
|
||||
displayIdx: ctx.opcodeIndex,
|
||||
idx: opcodeOffset(ctx.ptrIndex),
|
||||
elemIdx: head.elemIdx,
|
||||
length: head.length,
|
||||
mapIter: head.mapIter,
|
||||
indent: ctx.indent,
|
||||
}
|
||||
}
|
||||
|
||||
type interfaceCode struct {
|
||||
*opcodeHeader
|
||||
root bool
|
||||
func newInterfaceCode(ctx *encodeCompileContext) *opcode {
|
||||
return &opcode{
|
||||
op: opInterface,
|
||||
typ: ctx.typ,
|
||||
displayIdx: ctx.opcodeIndex,
|
||||
idx: opcodeOffset(ctx.ptrIndex),
|
||||
indent: ctx.indent,
|
||||
root: ctx.root,
|
||||
next: newEndOp(ctx),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *interfaceCode) copy(codeMap map[uintptr]*opcode) *opcode {
|
||||
if c == nil {
|
||||
return nil
|
||||
func newRecursiveCode(ctx *encodeCompileContext, jmp *compiledCode) *opcode {
|
||||
return &opcode{
|
||||
op: opStructFieldRecursive,
|
||||
typ: ctx.typ,
|
||||
displayIdx: ctx.opcodeIndex,
|
||||
idx: opcodeOffset(ctx.ptrIndex),
|
||||
indent: ctx.indent,
|
||||
next: newEndOp(ctx),
|
||||
jmp: jmp,
|
||||
}
|
||||
addr := uintptr(unsafe.Pointer(c))
|
||||
if code, exists := codeMap[addr]; exists {
|
||||
return code
|
||||
}
|
||||
iface := &interfaceCode{}
|
||||
code := (*opcode)(unsafe.Pointer(iface))
|
||||
codeMap[addr] = code
|
||||
|
||||
iface.opcodeHeader = c.opcodeHeader.copy(codeMap)
|
||||
return code
|
||||
}
|
||||
|
||||
type recursiveCode struct {
|
||||
*opcodeHeader
|
||||
jmp *compiledCode
|
||||
seenPtr uintptr
|
||||
}
|
||||
|
||||
func (c *recursiveCode) copy(codeMap map[uintptr]*opcode) *opcode {
|
||||
if c == nil {
|
||||
return nil
|
||||
}
|
||||
addr := uintptr(unsafe.Pointer(c))
|
||||
if code, exists := codeMap[addr]; exists {
|
||||
return code
|
||||
}
|
||||
recur := &recursiveCode{seenPtr: c.seenPtr}
|
||||
code := (*opcode)(unsafe.Pointer(recur))
|
||||
codeMap[addr] = code
|
||||
|
||||
recur.opcodeHeader = c.opcodeHeader.copy(codeMap)
|
||||
recur.jmp = &compiledCode{
|
||||
code: c.jmp.code.copy(codeMap),
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
func newRecursiveCode(recursive *recursiveCode) *opcode {
|
||||
code := copyOpcode(recursive.jmp.code)
|
||||
head := (*structFieldCode)(unsafe.Pointer(code))
|
||||
head.end.next = newEndOp(0)
|
||||
code.ptr = recursive.ptr
|
||||
|
||||
code.op = code.op.ptrHeadToHead()
|
||||
return code
|
||||
}
|
||||
|
|
1576
encode_optype.go
1576
encode_optype.go
File diff suppressed because it is too large
Load Diff
4208
encode_vm.go
4208
encode_vm.go
File diff suppressed because it is too large
Load Diff
|
@ -121,7 +121,6 @@ func TestIndent(t *testing.T) {
|
|||
}
|
||||
|
||||
// Tests of a large random structure.
|
||||
|
||||
func TestCompactBig(t *testing.T) {
|
||||
initBig()
|
||||
var buf bytes.Buffer
|
||||
|
@ -221,7 +220,9 @@ func trim(b []byte) []byte {
|
|||
|
||||
// Generate a random JSON object.
|
||||
|
||||
var jsonBig []byte
|
||||
var (
|
||||
jsonBig []byte
|
||||
)
|
||||
|
||||
func initBig() {
|
||||
if len(jsonBig) > 0 {
|
||||
|
|
Loading…
Reference in New Issue