forked from mirror/go-json
Fix encoding engine
This commit is contained in:
parent
72bc598dd4
commit
3aa921e884
|
@ -166,7 +166,7 @@ func (e *Encoder) encode(v interface{}) error {
|
||||||
p := uintptr(header.ptr)
|
p := uintptr(header.ptr)
|
||||||
ctx.init(p)
|
ctx.init(p)
|
||||||
seenPtr := map[uintptr]struct{}{}
|
seenPtr := map[uintptr]struct{}{}
|
||||||
err := e.run(ctx, seenPtr, code)
|
err := e.run(ctx, 0, seenPtr, code)
|
||||||
if e.enabledIndent {
|
if e.enabledIndent {
|
||||||
codeSet.codeIndent.Put(code)
|
codeSet.codeIndent.Put(code)
|
||||||
} else {
|
} else {
|
||||||
|
@ -228,7 +228,7 @@ func (e *Encoder) encode(v interface{}) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
seenPtr := map[uintptr]struct{}{}
|
seenPtr := map[uintptr]struct{}{}
|
||||||
if err := e.run(ctx, seenPtr, c); err != nil {
|
if err := e.run(ctx, 0, seenPtr, c); err != nil {
|
||||||
codeSet.ctx.Put(ctx)
|
codeSet.ctx.Put(ctx)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -133,7 +133,7 @@ func (e *Encoder) compileKey(ctx *encodeCompileContext) (*opcode, error) {
|
||||||
|
|
||||||
func (e *Encoder) compilePtr(ctx *encodeCompileContext) (*opcode, error) {
|
func (e *Encoder) compilePtr(ctx *encodeCompileContext) (*opcode, error) {
|
||||||
ptrOpcodeIndex := ctx.opcodeIndex
|
ptrOpcodeIndex := ctx.opcodeIndex
|
||||||
ctx.incOpcodeIndex()
|
ctx.incIndex()
|
||||||
code, err := e.compile(ctx.withType(ctx.typ.Elem()))
|
code, err := e.compile(ctx.withType(ctx.typ.Elem()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -142,7 +142,7 @@ func (e *Encoder) compilePtr(ctx *encodeCompileContext) (*opcode, error) {
|
||||||
if code.op != ptrHeadOp {
|
if code.op != ptrHeadOp {
|
||||||
code.op = ptrHeadOp
|
code.op = ptrHeadOp
|
||||||
code.decOpcodeIndex()
|
code.decOpcodeIndex()
|
||||||
ctx.decOpcodeIndex()
|
ctx.decIndex()
|
||||||
return code, nil
|
return code, nil
|
||||||
}
|
}
|
||||||
c := ctx.context()
|
c := ctx.context()
|
||||||
|
@ -152,121 +152,121 @@ func (e *Encoder) compilePtr(ctx *encodeCompileContext) (*opcode, error) {
|
||||||
|
|
||||||
func (e *Encoder) compileMarshalJSON(ctx *encodeCompileContext) (*opcode, error) {
|
func (e *Encoder) compileMarshalJSON(ctx *encodeCompileContext) (*opcode, error) {
|
||||||
code := newOpCode(ctx, opMarshalJSON)
|
code := newOpCode(ctx, opMarshalJSON)
|
||||||
ctx.incOpcodeIndex()
|
ctx.incIndex()
|
||||||
return code, nil
|
return code, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Encoder) compileMarshalJSONPtr(ctx *encodeCompileContext) (*opcode, error) {
|
func (e *Encoder) compileMarshalJSONPtr(ctx *encodeCompileContext) (*opcode, error) {
|
||||||
code := newOpCode(ctx.withType(rtype_ptrTo(ctx.typ)), opMarshalJSON)
|
code := newOpCode(ctx.withType(rtype_ptrTo(ctx.typ)), opMarshalJSON)
|
||||||
ctx.incOpcodeIndex()
|
ctx.incIndex()
|
||||||
return code, nil
|
return code, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Encoder) compileMarshalText(ctx *encodeCompileContext) (*opcode, error) {
|
func (e *Encoder) compileMarshalText(ctx *encodeCompileContext) (*opcode, error) {
|
||||||
code := newOpCode(ctx, opMarshalText)
|
code := newOpCode(ctx, opMarshalText)
|
||||||
ctx.incOpcodeIndex()
|
ctx.incIndex()
|
||||||
return code, nil
|
return code, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Encoder) compileMarshalTextPtr(ctx *encodeCompileContext) (*opcode, error) {
|
func (e *Encoder) compileMarshalTextPtr(ctx *encodeCompileContext) (*opcode, error) {
|
||||||
code := newOpCode(ctx.withType(rtype_ptrTo(ctx.typ)), opMarshalText)
|
code := newOpCode(ctx.withType(rtype_ptrTo(ctx.typ)), opMarshalText)
|
||||||
ctx.incOpcodeIndex()
|
ctx.incIndex()
|
||||||
return code, nil
|
return code, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Encoder) compileInt(ctx *encodeCompileContext) (*opcode, error) {
|
func (e *Encoder) compileInt(ctx *encodeCompileContext) (*opcode, error) {
|
||||||
code := newOpCode(ctx, opInt)
|
code := newOpCode(ctx, opInt)
|
||||||
ctx.incOpcodeIndex()
|
ctx.incIndex()
|
||||||
return code, nil
|
return code, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Encoder) compileInt8(ctx *encodeCompileContext) (*opcode, error) {
|
func (e *Encoder) compileInt8(ctx *encodeCompileContext) (*opcode, error) {
|
||||||
code := newOpCode(ctx, opInt8)
|
code := newOpCode(ctx, opInt8)
|
||||||
ctx.incOpcodeIndex()
|
ctx.incIndex()
|
||||||
return code, nil
|
return code, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Encoder) compileInt16(ctx *encodeCompileContext) (*opcode, error) {
|
func (e *Encoder) compileInt16(ctx *encodeCompileContext) (*opcode, error) {
|
||||||
code := newOpCode(ctx, opInt16)
|
code := newOpCode(ctx, opInt16)
|
||||||
ctx.incOpcodeIndex()
|
ctx.incIndex()
|
||||||
return code, nil
|
return code, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Encoder) compileInt32(ctx *encodeCompileContext) (*opcode, error) {
|
func (e *Encoder) compileInt32(ctx *encodeCompileContext) (*opcode, error) {
|
||||||
code := newOpCode(ctx, opInt32)
|
code := newOpCode(ctx, opInt32)
|
||||||
ctx.incOpcodeIndex()
|
ctx.incIndex()
|
||||||
return code, nil
|
return code, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Encoder) compileInt64(ctx *encodeCompileContext) (*opcode, error) {
|
func (e *Encoder) compileInt64(ctx *encodeCompileContext) (*opcode, error) {
|
||||||
code := newOpCode(ctx, opInt64)
|
code := newOpCode(ctx, opInt64)
|
||||||
ctx.incOpcodeIndex()
|
ctx.incIndex()
|
||||||
return code, nil
|
return code, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Encoder) compileUint(ctx *encodeCompileContext) (*opcode, error) {
|
func (e *Encoder) compileUint(ctx *encodeCompileContext) (*opcode, error) {
|
||||||
code := newOpCode(ctx, opUint)
|
code := newOpCode(ctx, opUint)
|
||||||
ctx.incOpcodeIndex()
|
ctx.incIndex()
|
||||||
return code, nil
|
return code, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Encoder) compileUint8(ctx *encodeCompileContext) (*opcode, error) {
|
func (e *Encoder) compileUint8(ctx *encodeCompileContext) (*opcode, error) {
|
||||||
code := newOpCode(ctx, opUint8)
|
code := newOpCode(ctx, opUint8)
|
||||||
ctx.incOpcodeIndex()
|
ctx.incIndex()
|
||||||
return code, nil
|
return code, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Encoder) compileUint16(ctx *encodeCompileContext) (*opcode, error) {
|
func (e *Encoder) compileUint16(ctx *encodeCompileContext) (*opcode, error) {
|
||||||
code := newOpCode(ctx, opUint16)
|
code := newOpCode(ctx, opUint16)
|
||||||
ctx.incOpcodeIndex()
|
ctx.incIndex()
|
||||||
return code, nil
|
return code, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Encoder) compileUint32(ctx *encodeCompileContext) (*opcode, error) {
|
func (e *Encoder) compileUint32(ctx *encodeCompileContext) (*opcode, error) {
|
||||||
code := newOpCode(ctx, opUint32)
|
code := newOpCode(ctx, opUint32)
|
||||||
ctx.incOpcodeIndex()
|
ctx.incIndex()
|
||||||
return code, nil
|
return code, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Encoder) compileUint64(ctx *encodeCompileContext) (*opcode, error) {
|
func (e *Encoder) compileUint64(ctx *encodeCompileContext) (*opcode, error) {
|
||||||
code := newOpCode(ctx, opUint64)
|
code := newOpCode(ctx, opUint64)
|
||||||
ctx.incOpcodeIndex()
|
ctx.incIndex()
|
||||||
return code, nil
|
return code, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Encoder) compileFloat32(ctx *encodeCompileContext) (*opcode, error) {
|
func (e *Encoder) compileFloat32(ctx *encodeCompileContext) (*opcode, error) {
|
||||||
code := newOpCode(ctx, opFloat32)
|
code := newOpCode(ctx, opFloat32)
|
||||||
ctx.incOpcodeIndex()
|
ctx.incIndex()
|
||||||
return code, nil
|
return code, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Encoder) compileFloat64(ctx *encodeCompileContext) (*opcode, error) {
|
func (e *Encoder) compileFloat64(ctx *encodeCompileContext) (*opcode, error) {
|
||||||
code := newOpCode(ctx, opFloat64)
|
code := newOpCode(ctx, opFloat64)
|
||||||
ctx.incOpcodeIndex()
|
ctx.incIndex()
|
||||||
return code, nil
|
return code, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Encoder) compileString(ctx *encodeCompileContext) (*opcode, error) {
|
func (e *Encoder) compileString(ctx *encodeCompileContext) (*opcode, error) {
|
||||||
code := newOpCode(ctx, opString)
|
code := newOpCode(ctx, opString)
|
||||||
ctx.incOpcodeIndex()
|
ctx.incIndex()
|
||||||
return code, nil
|
return code, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Encoder) compileBool(ctx *encodeCompileContext) (*opcode, error) {
|
func (e *Encoder) compileBool(ctx *encodeCompileContext) (*opcode, error) {
|
||||||
code := newOpCode(ctx, opBool)
|
code := newOpCode(ctx, opBool)
|
||||||
ctx.incOpcodeIndex()
|
ctx.incIndex()
|
||||||
return code, nil
|
return code, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Encoder) compileBytes(ctx *encodeCompileContext) (*opcode, error) {
|
func (e *Encoder) compileBytes(ctx *encodeCompileContext) (*opcode, error) {
|
||||||
code := newOpCode(ctx, opBytes)
|
code := newOpCode(ctx, opBytes)
|
||||||
ctx.incOpcodeIndex()
|
ctx.incIndex()
|
||||||
return code, nil
|
return code, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Encoder) compileInterface(ctx *encodeCompileContext) (*opcode, error) {
|
func (e *Encoder) compileInterface(ctx *encodeCompileContext) (*opcode, error) {
|
||||||
code := newInterfaceCode(ctx)
|
code := newInterfaceCode(ctx)
|
||||||
ctx.incOpcodeIndex()
|
ctx.incIndex()
|
||||||
return code, nil
|
return code, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -276,7 +276,7 @@ func (e *Encoder) compileSlice(ctx *encodeCompileContext) (*opcode, error) {
|
||||||
size := elem.Size()
|
size := elem.Size()
|
||||||
|
|
||||||
header := newSliceHeaderCode(ctx)
|
header := newSliceHeaderCode(ctx)
|
||||||
ctx.incOpcodeIndex()
|
ctx.incIndex()
|
||||||
|
|
||||||
code, err := e.compile(ctx.withType(ctx.typ.Elem()).incIndent())
|
code, err := e.compile(ctx.withType(ctx.typ.Elem()).incIndent())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -287,11 +287,11 @@ func (e *Encoder) compileSlice(ctx *encodeCompileContext) (*opcode, error) {
|
||||||
// ^ |
|
// ^ |
|
||||||
// |________|
|
// |________|
|
||||||
|
|
||||||
elemCode := newSliceElemCode(ctx, size)
|
elemCode := newSliceElemCode(ctx, header, size)
|
||||||
ctx.incOpcodeIndex()
|
ctx.incIndex()
|
||||||
|
|
||||||
end := newOpCode(ctx, opSliceEnd)
|
end := newOpCode(ctx, opSliceEnd)
|
||||||
ctx.incOpcodeIndex()
|
ctx.incIndex()
|
||||||
if ctx.withIndent {
|
if ctx.withIndent {
|
||||||
if ctx.root {
|
if ctx.root {
|
||||||
header.op = opRootSliceHeadIndent
|
header.op = opRootSliceHeadIndent
|
||||||
|
@ -320,7 +320,7 @@ func (e *Encoder) compileArray(ctx *encodeCompileContext) (*opcode, error) {
|
||||||
size := elem.Size()
|
size := elem.Size()
|
||||||
|
|
||||||
header := newArrayHeaderCode(ctx, alen)
|
header := newArrayHeaderCode(ctx, alen)
|
||||||
ctx.incOpcodeIndex()
|
ctx.incIndex()
|
||||||
|
|
||||||
code, err := e.compile(ctx.withType(elem).incIndent())
|
code, err := e.compile(ctx.withType(elem).incIndent())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -330,11 +330,11 @@ func (e *Encoder) compileArray(ctx *encodeCompileContext) (*opcode, error) {
|
||||||
// ^ |
|
// ^ |
|
||||||
// |________|
|
// |________|
|
||||||
|
|
||||||
elemCode := newArrayElemCode(ctx, alen, size)
|
elemCode := newArrayElemCode(ctx, header, alen, size)
|
||||||
ctx.incOpcodeIndex()
|
ctx.incIndex()
|
||||||
|
|
||||||
end := newOpCode(ctx, opArrayEnd)
|
end := newOpCode(ctx, opArrayEnd)
|
||||||
ctx.incOpcodeIndex()
|
ctx.incIndex()
|
||||||
|
|
||||||
if ctx.withIndent {
|
if ctx.withIndent {
|
||||||
header.op = opArrayHeadIndent
|
header.op = opArrayHeadIndent
|
||||||
|
@ -373,7 +373,7 @@ func (e *Encoder) compileMap(ctx *encodeCompileContext, withLoad bool) (*opcode,
|
||||||
// |_______________________|
|
// |_______________________|
|
||||||
ctx = ctx.incIndent()
|
ctx = ctx.incIndent()
|
||||||
header := newMapHeaderCode(ctx, withLoad)
|
header := newMapHeaderCode(ctx, withLoad)
|
||||||
ctx.incOpcodeIndex()
|
ctx.incIndex()
|
||||||
|
|
||||||
typ := ctx.typ
|
typ := ctx.typ
|
||||||
keyType := ctx.typ.Key()
|
keyType := ctx.typ.Key()
|
||||||
|
@ -382,8 +382,8 @@ func (e *Encoder) compileMap(ctx *encodeCompileContext, withLoad bool) (*opcode,
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
value := newMapValueCode(ctx)
|
value := newMapValueCode(ctx, header)
|
||||||
ctx.incOpcodeIndex()
|
ctx.incIndex()
|
||||||
|
|
||||||
valueType := typ.Elem()
|
valueType := typ.Elem()
|
||||||
valueCode, err := e.compile(ctx.withType(valueType))
|
valueCode, err := e.compile(ctx.withType(valueType))
|
||||||
|
@ -391,15 +391,15 @@ func (e *Encoder) compileMap(ctx *encodeCompileContext, withLoad bool) (*opcode,
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
key := newMapKeyCode(ctx)
|
key := newMapKeyCode(ctx, header)
|
||||||
ctx.incOpcodeIndex()
|
ctx.incIndex()
|
||||||
|
|
||||||
ctx = ctx.decIndent()
|
ctx = ctx.decIndent()
|
||||||
|
|
||||||
header.mapKey = key
|
header.mapKey = key
|
||||||
header.mapValue = value
|
header.mapValue = value
|
||||||
end := newOpCode(ctx, opMapEnd)
|
end := newOpCode(ctx, opMapEnd)
|
||||||
ctx.incOpcodeIndex()
|
ctx.incIndex()
|
||||||
|
|
||||||
if ctx.withIndent {
|
if ctx.withIndent {
|
||||||
if header.op == opMapHead {
|
if header.op == opMapHead {
|
||||||
|
@ -578,7 +578,7 @@ func (e *Encoder) optimizeStructField(op opType, tag *structTag, withIndent bool
|
||||||
|
|
||||||
func (e *Encoder) recursiveCode(ctx *encodeCompileContext, jmp *compiledCode) *opcode {
|
func (e *Encoder) recursiveCode(ctx *encodeCompileContext, jmp *compiledCode) *opcode {
|
||||||
code := newRecursiveCode(ctx, jmp)
|
code := newRecursiveCode(ctx, jmp)
|
||||||
ctx.incOpcodeIndex()
|
ctx.incIndex()
|
||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -667,7 +667,7 @@ func (e *Encoder) structField(ctx *encodeCompileContext, fieldCode *opcode, valu
|
||||||
opStructFieldStringTagIndent:
|
opStructFieldStringTagIndent:
|
||||||
return valueCode.beforeLastCode()
|
return valueCode.beforeLastCode()
|
||||||
}
|
}
|
||||||
ctx.decOpcodeIndex()
|
ctx.decIndex()
|
||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -876,7 +876,8 @@ func (e *Encoder) compileStruct(ctx *encodeCompileContext, isPtr bool) (*opcode,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fieldOpcodeIndex := ctx.opcodeIndex
|
fieldOpcodeIndex := ctx.opcodeIndex
|
||||||
ctx.incOpcodeIndex()
|
fieldPtrIndex := ctx.ptrIndex
|
||||||
|
ctx.incIndex()
|
||||||
valueCode, err := e.compile(ctx.withType(fieldType))
|
valueCode, err := e.compile(ctx.withType(fieldType))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -902,7 +903,7 @@ func (e *Encoder) compileStruct(ctx *encodeCompileContext, isPtr bool) (*opcode,
|
||||||
fieldCode := &opcode{
|
fieldCode := &opcode{
|
||||||
typ: valueCode.typ,
|
typ: valueCode.typ,
|
||||||
displayIdx: fieldOpcodeIndex,
|
displayIdx: fieldOpcodeIndex,
|
||||||
idx: opcodeOffset(fieldOpcodeIndex),
|
idx: opcodeOffset(fieldPtrIndex),
|
||||||
next: valueCode,
|
next: valueCode,
|
||||||
indent: ctx.indent,
|
indent: ctx.indent,
|
||||||
anonymousKey: field.Anonymous,
|
anonymousKey: field.Anonymous,
|
||||||
|
@ -912,14 +913,15 @@ func (e *Encoder) compileStruct(ctx *encodeCompileContext, isPtr bool) (*opcode,
|
||||||
offset: field.Offset,
|
offset: field.Offset,
|
||||||
}
|
}
|
||||||
if fieldIdx == 0 {
|
if fieldIdx == 0 {
|
||||||
|
fieldCode.headIdx = fieldCode.idx
|
||||||
code = e.structHeader(ctx, fieldCode, valueCode, tag)
|
code = e.structHeader(ctx, fieldCode, valueCode, tag)
|
||||||
head = fieldCode
|
head = fieldCode
|
||||||
prevField = fieldCode
|
prevField = fieldCode
|
||||||
} else {
|
} else {
|
||||||
fcode := (*opcode)(unsafe.Pointer(fieldCode))
|
fieldCode.headIdx = head.headIdx
|
||||||
code.next = fcode
|
code.next = fieldCode
|
||||||
code = e.structField(ctx, fieldCode, valueCode, tag)
|
code = e.structField(ctx, fieldCode, valueCode, tag)
|
||||||
prevField.nextField = fcode
|
prevField.nextField = fieldCode
|
||||||
prevField = fieldCode
|
prevField = fieldCode
|
||||||
}
|
}
|
||||||
fieldIdx++
|
fieldIdx++
|
||||||
|
@ -939,11 +941,12 @@ func (e *Encoder) compileStruct(ctx *encodeCompileContext, isPtr bool) (*opcode,
|
||||||
op: opStructFieldHead,
|
op: opStructFieldHead,
|
||||||
typ: typ,
|
typ: typ,
|
||||||
displayIdx: ctx.opcodeIndex,
|
displayIdx: ctx.opcodeIndex,
|
||||||
idx: opcodeOffset(ctx.opcodeIndex),
|
idx: opcodeOffset(ctx.ptrIndex),
|
||||||
|
headIdx: opcodeOffset(ctx.ptrIndex),
|
||||||
indent: ctx.indent,
|
indent: ctx.indent,
|
||||||
nextField: structEndCode,
|
nextField: structEndCode,
|
||||||
}
|
}
|
||||||
ctx.incOpcodeIndex()
|
ctx.incIndex()
|
||||||
if ctx.withIndent {
|
if ctx.withIndent {
|
||||||
head.op = opStructFieldHeadIndent
|
head.op = opStructFieldHeadIndent
|
||||||
}
|
}
|
||||||
|
@ -952,7 +955,7 @@ func (e *Encoder) compileStruct(ctx *encodeCompileContext, isPtr bool) (*opcode,
|
||||||
|
|
||||||
structEndCode.displayIdx = ctx.opcodeIndex
|
structEndCode.displayIdx = ctx.opcodeIndex
|
||||||
structEndCode.idx = opcodeOffset(ctx.opcodeIndex)
|
structEndCode.idx = opcodeOffset(ctx.opcodeIndex)
|
||||||
ctx.incOpcodeIndex()
|
ctx.incIndex()
|
||||||
|
|
||||||
if ctx.withIndent {
|
if ctx.withIndent {
|
||||||
structEndCode.op = opStructEndIndent
|
structEndCode.op = opStructEndIndent
|
||||||
|
|
|
@ -46,9 +46,18 @@ func (c *encodeCompileContext) decIndent() *encodeCompileContext {
|
||||||
return ctx
|
return ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *encodeCompileContext) incIndex() {
|
||||||
|
c.incOpcodeIndex()
|
||||||
|
c.incPtrIndex()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *encodeCompileContext) decIndex() {
|
||||||
|
c.decOpcodeIndex()
|
||||||
|
c.decPtrIndex()
|
||||||
|
}
|
||||||
|
|
||||||
func (c *encodeCompileContext) incOpcodeIndex() {
|
func (c *encodeCompileContext) incOpcodeIndex() {
|
||||||
c.opcodeIndex++
|
c.opcodeIndex++
|
||||||
c.ptrIndex++
|
|
||||||
if c.parent != nil {
|
if c.parent != nil {
|
||||||
c.parent.incOpcodeIndex()
|
c.parent.incOpcodeIndex()
|
||||||
}
|
}
|
||||||
|
@ -56,12 +65,25 @@ func (c *encodeCompileContext) incOpcodeIndex() {
|
||||||
|
|
||||||
func (c *encodeCompileContext) decOpcodeIndex() {
|
func (c *encodeCompileContext) decOpcodeIndex() {
|
||||||
c.opcodeIndex--
|
c.opcodeIndex--
|
||||||
c.ptrIndex--
|
|
||||||
if c.parent != nil {
|
if c.parent != nil {
|
||||||
c.parent.decOpcodeIndex()
|
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 {
|
type encodeRuntimeContext struct {
|
||||||
ptrs []uintptr
|
ptrs []uintptr
|
||||||
}
|
}
|
||||||
|
|
153
encode_opcode.go
153
encode_opcode.go
|
@ -50,7 +50,7 @@ func newOpCodeWithNext(ctx *encodeCompileContext, op opType, next *opcode) *opco
|
||||||
typ: ctx.typ,
|
typ: ctx.typ,
|
||||||
displayIdx: ctx.opcodeIndex,
|
displayIdx: ctx.opcodeIndex,
|
||||||
indent: ctx.indent,
|
indent: ctx.indent,
|
||||||
idx: opcodeOffset(ctx.opcodeIndex),
|
idx: opcodeOffset(ctx.ptrIndex),
|
||||||
next: next,
|
next: next,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -94,7 +94,7 @@ func (c *opcode) totalLength() int {
|
||||||
func (c *opcode) decOpcodeIndex() {
|
func (c *opcode) decOpcodeIndex() {
|
||||||
for code := c; code.op != opEnd; {
|
for code := c; code.op != opEnd; {
|
||||||
code.displayIdx--
|
code.displayIdx--
|
||||||
code.idx -= 8
|
code.idx -= uintptrSize
|
||||||
switch code.op.codeType() {
|
switch code.op.codeType() {
|
||||||
case codeArrayElem, codeSliceElem, codeMapKey:
|
case codeArrayElem, codeSliceElem, codeMapKey:
|
||||||
code = code.end
|
code = code.end
|
||||||
|
@ -104,40 +104,93 @@ func (c *opcode) decOpcodeIndex() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *opcode) dumpElem(code *opcode) string {
|
func (c *opcode) dumpHead(code *opcode) string {
|
||||||
|
var length uintptr
|
||||||
|
if code.op.codeType() == codeArrayElem {
|
||||||
|
length = code.length
|
||||||
|
} else {
|
||||||
|
length = code.length / uintptrSize
|
||||||
|
}
|
||||||
return fmt.Sprintf(
|
return fmt.Sprintf(
|
||||||
`[%d]%s%s ([headIdx:%d][elemIdx:%d][length:%d][size:%d])`,
|
`[%d]%s%s ([idx:%d][headIdx:%d][elemIdx:%d][length:%d])`,
|
||||||
code.displayIdx,
|
code.displayIdx,
|
||||||
strings.Repeat("-", code.indent),
|
strings.Repeat("-", code.indent),
|
||||||
code.op,
|
code.op,
|
||||||
code.headIdx,
|
code.idx/uintptrSize,
|
||||||
code.elemIdx,
|
code.headIdx/uintptrSize,
|
||||||
code.length,
|
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,
|
code.size,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *opcode) dumpField(code *opcode) string {
|
func (c *opcode) dumpField(code *opcode) string {
|
||||||
return fmt.Sprintf(
|
return fmt.Sprintf(
|
||||||
`[%d]%s%s ([key:%s][offset:%d][headIdx:%d])`,
|
`[%d]%s%s ([idx:%d][key:%s][offset:%d][headIdx:%d])`,
|
||||||
code.displayIdx,
|
code.displayIdx,
|
||||||
strings.Repeat("-", code.indent),
|
strings.Repeat("-", code.indent),
|
||||||
code.op,
|
code.op,
|
||||||
|
code.idx/uintptrSize,
|
||||||
code.displayKey,
|
code.displayKey,
|
||||||
code.offset,
|
code.offset,
|
||||||
code.headIdx,
|
code.headIdx/uintptrSize,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *opcode) dumpKey(code *opcode) string {
|
func (c *opcode) dumpKey(code *opcode) string {
|
||||||
return fmt.Sprintf(
|
return fmt.Sprintf(
|
||||||
`[%d]%s%s ([elemIdx:%d][length:%d][mapIter:%d])`,
|
`[%d]%s%s ([idx:%d][elemIdx:%d][length:%d][mapIter:%d])`,
|
||||||
code.displayIdx,
|
code.displayIdx,
|
||||||
strings.Repeat("-", code.indent),
|
strings.Repeat("-", code.indent),
|
||||||
code.op,
|
code.op,
|
||||||
code.elemIdx,
|
code.idx/uintptrSize,
|
||||||
code.length,
|
code.elemIdx/uintptrSize,
|
||||||
code.mapIter,
|
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,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,21 +198,31 @@ func (c *opcode) dump() string {
|
||||||
codes := []string{}
|
codes := []string{}
|
||||||
for code := c; code.op != opEnd; {
|
for code := c; code.op != opEnd; {
|
||||||
switch code.op.codeType() {
|
switch code.op.codeType() {
|
||||||
|
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:
|
case codeArrayElem, codeSliceElem:
|
||||||
codes = append(codes, c.dumpElem(code))
|
codes = append(codes, c.dumpElem(code))
|
||||||
code = code.end
|
code = code.end
|
||||||
case codeMapKey:
|
case codeMapKey:
|
||||||
codes = append(codes, c.dumpKey(code))
|
codes = append(codes, c.dumpKey(code))
|
||||||
code = code.end
|
code = code.end
|
||||||
|
case codeMapValue:
|
||||||
|
codes = append(codes, c.dumpValue(code))
|
||||||
|
code = code.next
|
||||||
case codeStructField:
|
case codeStructField:
|
||||||
codes = append(codes, c.dumpField(code))
|
codes = append(codes, c.dumpField(code))
|
||||||
code = code.next
|
code = code.next
|
||||||
default:
|
default:
|
||||||
codes = append(codes, fmt.Sprintf(
|
codes = append(codes, fmt.Sprintf(
|
||||||
"[%d]%s%s",
|
"[%d]%s%s ([idx:%d])",
|
||||||
code.displayIdx,
|
code.displayIdx,
|
||||||
strings.Repeat("-", code.indent),
|
strings.Repeat("-", code.indent),
|
||||||
code.op,
|
code.op,
|
||||||
|
code.idx/uintptrSize,
|
||||||
))
|
))
|
||||||
code = code.next
|
code = code.next
|
||||||
}
|
}
|
||||||
|
@ -190,40 +253,58 @@ func linkPrevToNextField(prev, cur *opcode) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func newSliceHeaderCode(ctx *encodeCompileContext) *opcode {
|
func newSliceHeaderCode(ctx *encodeCompileContext) *opcode {
|
||||||
|
idx := opcodeOffset(ctx.ptrIndex)
|
||||||
|
ctx.incPtrIndex()
|
||||||
|
elemIdx := opcodeOffset(ctx.ptrIndex)
|
||||||
|
ctx.incPtrIndex()
|
||||||
|
length := opcodeOffset(ctx.ptrIndex)
|
||||||
return &opcode{
|
return &opcode{
|
||||||
op: opSliceHead,
|
op: opSliceHead,
|
||||||
displayIdx: ctx.opcodeIndex,
|
displayIdx: ctx.opcodeIndex,
|
||||||
idx: opcodeOffset(ctx.opcodeIndex),
|
idx: idx,
|
||||||
|
headIdx: idx,
|
||||||
|
elemIdx: elemIdx,
|
||||||
|
length: length,
|
||||||
indent: ctx.indent,
|
indent: ctx.indent,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func newSliceElemCode(ctx *encodeCompileContext, size uintptr) *opcode {
|
func newSliceElemCode(ctx *encodeCompileContext, head *opcode, size uintptr) *opcode {
|
||||||
return &opcode{
|
return &opcode{
|
||||||
op: opSliceElem,
|
op: opSliceElem,
|
||||||
displayIdx: ctx.opcodeIndex,
|
displayIdx: ctx.opcodeIndex,
|
||||||
idx: opcodeOffset(ctx.opcodeIndex),
|
idx: opcodeOffset(ctx.ptrIndex),
|
||||||
|
headIdx: head.idx,
|
||||||
|
elemIdx: head.elemIdx,
|
||||||
|
length: head.length,
|
||||||
indent: ctx.indent,
|
indent: ctx.indent,
|
||||||
size: size,
|
size: size,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func newArrayHeaderCode(ctx *encodeCompileContext, alen int) *opcode {
|
func newArrayHeaderCode(ctx *encodeCompileContext, alen int) *opcode {
|
||||||
|
idx := opcodeOffset(ctx.ptrIndex)
|
||||||
|
ctx.incPtrIndex()
|
||||||
|
elemIdx := opcodeOffset(ctx.ptrIndex)
|
||||||
return &opcode{
|
return &opcode{
|
||||||
op: opArrayHead,
|
op: opArrayHead,
|
||||||
displayIdx: ctx.opcodeIndex,
|
displayIdx: ctx.opcodeIndex,
|
||||||
idx: opcodeOffset(ctx.opcodeIndex),
|
idx: idx,
|
||||||
|
headIdx: idx,
|
||||||
|
elemIdx: elemIdx,
|
||||||
indent: ctx.indent,
|
indent: ctx.indent,
|
||||||
length: uintptr(alen),
|
length: uintptr(alen),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func newArrayElemCode(ctx *encodeCompileContext, alen int, size uintptr) *opcode {
|
func newArrayElemCode(ctx *encodeCompileContext, head *opcode, length int, size uintptr) *opcode {
|
||||||
return &opcode{
|
return &opcode{
|
||||||
op: opArrayElem,
|
op: opArrayElem,
|
||||||
displayIdx: ctx.opcodeIndex,
|
displayIdx: ctx.opcodeIndex,
|
||||||
idx: opcodeOffset(ctx.opcodeIndex),
|
idx: opcodeOffset(ctx.ptrIndex),
|
||||||
length: uintptr(alen),
|
elemIdx: head.elemIdx,
|
||||||
|
headIdx: head.headIdx,
|
||||||
|
length: uintptr(length),
|
||||||
size: size,
|
size: size,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -235,29 +316,45 @@ func newMapHeaderCode(ctx *encodeCompileContext, withLoad bool) *opcode {
|
||||||
} else {
|
} else {
|
||||||
op = opMapHead
|
op = opMapHead
|
||||||
}
|
}
|
||||||
|
idx := opcodeOffset(ctx.ptrIndex)
|
||||||
|
ctx.incPtrIndex()
|
||||||
|
elemIdx := opcodeOffset(ctx.ptrIndex)
|
||||||
|
ctx.incPtrIndex()
|
||||||
|
length := opcodeOffset(ctx.ptrIndex)
|
||||||
|
ctx.incPtrIndex()
|
||||||
|
mapIter := opcodeOffset(ctx.ptrIndex)
|
||||||
return &opcode{
|
return &opcode{
|
||||||
op: op,
|
op: op,
|
||||||
typ: ctx.typ,
|
typ: ctx.typ,
|
||||||
displayIdx: ctx.opcodeIndex,
|
displayIdx: ctx.opcodeIndex,
|
||||||
idx: opcodeOffset(ctx.opcodeIndex),
|
idx: idx,
|
||||||
|
elemIdx: elemIdx,
|
||||||
|
length: length,
|
||||||
|
mapIter: mapIter,
|
||||||
indent: ctx.indent,
|
indent: ctx.indent,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func newMapKeyCode(ctx *encodeCompileContext) *opcode {
|
func newMapKeyCode(ctx *encodeCompileContext, head *opcode) *opcode {
|
||||||
return &opcode{
|
return &opcode{
|
||||||
op: opMapKey,
|
op: opMapKey,
|
||||||
displayIdx: ctx.opcodeIndex,
|
displayIdx: ctx.opcodeIndex,
|
||||||
idx: opcodeOffset(ctx.opcodeIndex),
|
idx: opcodeOffset(ctx.ptrIndex),
|
||||||
|
elemIdx: head.elemIdx,
|
||||||
|
length: head.length,
|
||||||
|
mapIter: head.mapIter,
|
||||||
indent: ctx.indent,
|
indent: ctx.indent,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func newMapValueCode(ctx *encodeCompileContext) *opcode {
|
func newMapValueCode(ctx *encodeCompileContext, head *opcode) *opcode {
|
||||||
return &opcode{
|
return &opcode{
|
||||||
op: opMapValue,
|
op: opMapValue,
|
||||||
displayIdx: ctx.opcodeIndex,
|
displayIdx: ctx.opcodeIndex,
|
||||||
idx: opcodeOffset(ctx.opcodeIndex),
|
idx: opcodeOffset(ctx.ptrIndex),
|
||||||
|
elemIdx: head.elemIdx,
|
||||||
|
length: head.length,
|
||||||
|
mapIter: head.mapIter,
|
||||||
indent: ctx.indent,
|
indent: ctx.indent,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -267,7 +364,7 @@ func newInterfaceCode(ctx *encodeCompileContext) *opcode {
|
||||||
op: opInterface,
|
op: opInterface,
|
||||||
typ: ctx.typ,
|
typ: ctx.typ,
|
||||||
displayIdx: ctx.opcodeIndex,
|
displayIdx: ctx.opcodeIndex,
|
||||||
idx: opcodeOffset(ctx.opcodeIndex),
|
idx: opcodeOffset(ctx.ptrIndex),
|
||||||
indent: ctx.indent,
|
indent: ctx.indent,
|
||||||
next: newEndOp(ctx),
|
next: newEndOp(ctx),
|
||||||
root: ctx.root,
|
root: ctx.root,
|
||||||
|
@ -279,7 +376,7 @@ func newRecursiveCode(ctx *encodeCompileContext, jmp *compiledCode) *opcode {
|
||||||
op: opStructFieldRecursive,
|
op: opStructFieldRecursive,
|
||||||
typ: ctx.typ,
|
typ: ctx.typ,
|
||||||
displayIdx: ctx.opcodeIndex,
|
displayIdx: ctx.opcodeIndex,
|
||||||
idx: opcodeOffset(ctx.opcodeIndex),
|
idx: opcodeOffset(ctx.ptrIndex),
|
||||||
indent: ctx.indent,
|
indent: ctx.indent,
|
||||||
next: newEndOp(ctx),
|
next: newEndOp(ctx),
|
||||||
jmp: jmp,
|
jmp: jmp,
|
||||||
|
|
96
encode_vm.go
96
encode_vm.go
|
@ -11,6 +11,8 @@ import (
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const startDetectingCyclesAfter = 1000
|
||||||
|
|
||||||
func load(base uintptr, idx uintptr) uintptr {
|
func load(base uintptr, idx uintptr) uintptr {
|
||||||
return *(*uintptr)(unsafe.Pointer(base + idx))
|
return *(*uintptr)(unsafe.Pointer(base + idx))
|
||||||
}
|
}
|
||||||
|
@ -19,7 +21,7 @@ func store(base uintptr, idx uintptr, p uintptr) {
|
||||||
*(*uintptr)(unsafe.Pointer(base + idx)) = p
|
*(*uintptr)(unsafe.Pointer(base + idx)) = p
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Encoder) run(ctx *encodeRuntimeContext, seenPtr map[uintptr]struct{}, code *opcode) error {
|
func (e *Encoder) run(ctx *encodeRuntimeContext, recursiveLevel int, seenPtr map[uintptr]struct{}, code *opcode) error {
|
||||||
ctxptr := ctx.ptr()
|
ctxptr := ctx.ptr()
|
||||||
for {
|
for {
|
||||||
switch code.op {
|
switch code.op {
|
||||||
|
@ -144,7 +146,7 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, seenPtr map[uintptr]struct{}, c
|
||||||
ptrs: make([]uintptr, c.totalLength()),
|
ptrs: make([]uintptr, c.totalLength()),
|
||||||
}
|
}
|
||||||
ctx.init(uintptr(header.ptr))
|
ctx.init(uintptr(header.ptr))
|
||||||
if err := e.run(ctx, seenPtr, c); err != nil {
|
if err := e.run(ctx, recursiveLevel+1, seenPtr, c); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
code = code.next
|
code = code.next
|
||||||
|
@ -236,9 +238,10 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, seenPtr map[uintptr]struct{}, c
|
||||||
if idx < length {
|
if idx < length {
|
||||||
e.encodeByte(',')
|
e.encodeByte(',')
|
||||||
store(ctxptr, code.elemIdx, idx)
|
store(ctxptr, code.elemIdx, idx)
|
||||||
code = code.next
|
|
||||||
data := load(ctxptr, code.headIdx)
|
data := load(ctxptr, code.headIdx)
|
||||||
store(ctxptr, code.idx, data+idx*code.size)
|
size := code.size
|
||||||
|
code = code.next
|
||||||
|
store(ctxptr, code.idx, data+idx*size)
|
||||||
} else {
|
} else {
|
||||||
e.encodeByte(']')
|
e.encodeByte(']')
|
||||||
code = code.end.next
|
code = code.end.next
|
||||||
|
@ -295,9 +298,10 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, seenPtr map[uintptr]struct{}, c
|
||||||
e.encodeBytes([]byte{',', '\n'})
|
e.encodeBytes([]byte{',', '\n'})
|
||||||
e.encodeIndent(code.indent + 1)
|
e.encodeIndent(code.indent + 1)
|
||||||
store(ctxptr, code.elemIdx, idx)
|
store(ctxptr, code.elemIdx, idx)
|
||||||
code = code.next
|
|
||||||
data := load(ctxptr, code.headIdx)
|
data := load(ctxptr, code.headIdx)
|
||||||
store(ctxptr, code.idx, data+idx*code.size)
|
size := code.size
|
||||||
|
code = code.next
|
||||||
|
store(ctxptr, code.idx, data+idx*size)
|
||||||
} else {
|
} else {
|
||||||
e.encodeByte('\n')
|
e.encodeByte('\n')
|
||||||
e.encodeIndent(code.indent)
|
e.encodeIndent(code.indent)
|
||||||
|
@ -329,6 +333,7 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, seenPtr map[uintptr]struct{}, c
|
||||||
} else {
|
} else {
|
||||||
e.encodeByte('[')
|
e.encodeByte('[')
|
||||||
if code.length > 0 {
|
if code.length > 0 {
|
||||||
|
store(ctxptr, code.elemIdx, 0)
|
||||||
code = code.next
|
code = code.next
|
||||||
store(ctxptr, code.idx, p)
|
store(ctxptr, code.idx, p)
|
||||||
} else {
|
} else {
|
||||||
|
@ -343,8 +348,9 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, seenPtr map[uintptr]struct{}, c
|
||||||
e.encodeByte(',')
|
e.encodeByte(',')
|
||||||
store(ctxptr, code.elemIdx, idx)
|
store(ctxptr, code.elemIdx, idx)
|
||||||
p := load(ctxptr, code.headIdx)
|
p := load(ctxptr, code.headIdx)
|
||||||
|
size := code.size
|
||||||
code = code.next
|
code = code.next
|
||||||
store(ctxptr, code.idx, p+idx*code.size)
|
store(ctxptr, code.idx, p+idx*size)
|
||||||
} else {
|
} else {
|
||||||
e.encodeByte(']')
|
e.encodeByte(']')
|
||||||
code = code.end.next
|
code = code.end.next
|
||||||
|
@ -359,6 +365,7 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, seenPtr map[uintptr]struct{}, c
|
||||||
e.encodeBytes([]byte{'[', '\n'})
|
e.encodeBytes([]byte{'[', '\n'})
|
||||||
if code.length > 0 {
|
if code.length > 0 {
|
||||||
e.encodeIndent(code.indent + 1)
|
e.encodeIndent(code.indent + 1)
|
||||||
|
store(ctxptr, code.elemIdx, 0)
|
||||||
code = code.next
|
code = code.next
|
||||||
store(ctxptr, code.idx, p)
|
store(ctxptr, code.idx, p)
|
||||||
} else {
|
} else {
|
||||||
|
@ -375,8 +382,9 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, seenPtr map[uintptr]struct{}, c
|
||||||
e.encodeIndent(code.indent + 1)
|
e.encodeIndent(code.indent + 1)
|
||||||
store(ctxptr, code.elemIdx, idx)
|
store(ctxptr, code.elemIdx, idx)
|
||||||
p := load(ctxptr, code.headIdx)
|
p := load(ctxptr, code.headIdx)
|
||||||
|
size := code.size
|
||||||
code = code.next
|
code = code.next
|
||||||
store(ctxptr, code.idx, p+idx*code.size)
|
store(ctxptr, code.idx, p+idx*size)
|
||||||
} else {
|
} else {
|
||||||
e.encodeByte('\n')
|
e.encodeByte('\n')
|
||||||
e.encodeIndent(code.indent)
|
e.encodeIndent(code.indent)
|
||||||
|
@ -393,9 +401,9 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, seenPtr map[uintptr]struct{}, c
|
||||||
mlen := maplen(unsafe.Pointer(ptr))
|
mlen := maplen(unsafe.Pointer(ptr))
|
||||||
if mlen > 0 {
|
if mlen > 0 {
|
||||||
iter := mapiterinit(code.typ, unsafe.Pointer(ptr))
|
iter := mapiterinit(code.typ, unsafe.Pointer(ptr))
|
||||||
store(ctxptr, code.mapKey.length, uintptr(mlen))
|
store(ctxptr, code.elemIdx, 0)
|
||||||
store(ctxptr, code.mapKey.mapIter, uintptr(iter))
|
store(ctxptr, code.length, uintptr(mlen))
|
||||||
store(ctxptr, code.mapValue.mapIter, uintptr(iter))
|
store(ctxptr, code.mapIter, uintptr(iter))
|
||||||
key := mapiterkey(iter)
|
key := mapiterkey(iter)
|
||||||
store(ctxptr, code.next.idx, uintptr(key))
|
store(ctxptr, code.next.idx, uintptr(key))
|
||||||
code = code.next
|
code = code.next
|
||||||
|
@ -416,9 +424,9 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, seenPtr map[uintptr]struct{}, c
|
||||||
mlen := maplen(unsafe.Pointer(ptr))
|
mlen := maplen(unsafe.Pointer(ptr))
|
||||||
if mlen > 0 {
|
if mlen > 0 {
|
||||||
iter := mapiterinit(code.typ, unsafe.Pointer(ptr))
|
iter := mapiterinit(code.typ, unsafe.Pointer(ptr))
|
||||||
store(ctxptr, code.mapKey.length, uintptr(mlen))
|
store(ctxptr, code.elemIdx, 0)
|
||||||
store(ctxptr, code.mapKey.mapIter, uintptr(iter))
|
store(ctxptr, code.length, uintptr(mlen))
|
||||||
store(ctxptr, code.mapValue.mapIter, uintptr(iter))
|
store(ctxptr, code.mapIter, uintptr(iter))
|
||||||
key := mapiterkey(iter)
|
key := mapiterkey(iter)
|
||||||
store(ctxptr, code.next.idx, uintptr(key))
|
store(ctxptr, code.next.idx, uintptr(key))
|
||||||
code = code.next
|
code = code.next
|
||||||
|
@ -460,9 +468,9 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, seenPtr map[uintptr]struct{}, c
|
||||||
if mlen > 0 {
|
if mlen > 0 {
|
||||||
e.encodeBytes([]byte{'{', '\n'})
|
e.encodeBytes([]byte{'{', '\n'})
|
||||||
iter := mapiterinit(code.typ, unsafe.Pointer(ptr))
|
iter := mapiterinit(code.typ, unsafe.Pointer(ptr))
|
||||||
store(ctxptr, code.mapKey.length, uintptr(mlen))
|
store(ctxptr, code.elemIdx, 0)
|
||||||
store(ctxptr, code.mapKey.mapIter, uintptr(iter))
|
store(ctxptr, code.length, uintptr(mlen))
|
||||||
store(ctxptr, code.mapValue.mapIter, uintptr(iter))
|
store(ctxptr, code.mapIter, uintptr(iter))
|
||||||
key := mapiterkey(iter)
|
key := mapiterkey(iter)
|
||||||
store(ctxptr, code.next.idx, uintptr(key))
|
store(ctxptr, code.next.idx, uintptr(key))
|
||||||
code = code.next
|
code = code.next
|
||||||
|
@ -486,9 +494,9 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, seenPtr map[uintptr]struct{}, c
|
||||||
if mlen > 0 {
|
if mlen > 0 {
|
||||||
e.encodeBytes([]byte{'{', '\n'})
|
e.encodeBytes([]byte{'{', '\n'})
|
||||||
iter := mapiterinit(code.typ, unsafe.Pointer(ptr))
|
iter := mapiterinit(code.typ, unsafe.Pointer(ptr))
|
||||||
store(ctxptr, code.mapKey.length, uintptr(mlen))
|
store(ctxptr, code.elemIdx, 0)
|
||||||
store(ctxptr, code.mapKey.mapIter, uintptr(iter))
|
store(ctxptr, code.length, uintptr(mlen))
|
||||||
store(ctxptr, code.mapValue.mapIter, uintptr(iter))
|
store(ctxptr, code.mapIter, uintptr(iter))
|
||||||
key := mapiterkey(iter)
|
key := mapiterkey(iter)
|
||||||
store(ctxptr, code.next.idx, uintptr(key))
|
store(ctxptr, code.next.idx, uintptr(key))
|
||||||
code = code.next
|
code = code.next
|
||||||
|
@ -510,9 +518,9 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, seenPtr map[uintptr]struct{}, c
|
||||||
if mlen > 0 {
|
if mlen > 0 {
|
||||||
e.encodeBytes([]byte{'{', '\n'})
|
e.encodeBytes([]byte{'{', '\n'})
|
||||||
iter := mapiterinit(code.typ, unsafe.Pointer(ptr))
|
iter := mapiterinit(code.typ, unsafe.Pointer(ptr))
|
||||||
store(ctxptr, code.mapKey.length, uintptr(mlen))
|
store(ctxptr, code.elemIdx, 0)
|
||||||
store(ctxptr, code.mapKey.mapIter, uintptr(iter))
|
store(ctxptr, code.length, uintptr(mlen))
|
||||||
store(ctxptr, code.mapValue.mapIter, uintptr(iter))
|
store(ctxptr, code.mapIter, uintptr(iter))
|
||||||
key := mapiterkey(iter)
|
key := mapiterkey(iter)
|
||||||
store(ctxptr, code.next.idx, uintptr(key))
|
store(ctxptr, code.next.idx, uintptr(key))
|
||||||
code = code.next
|
code = code.next
|
||||||
|
@ -569,17 +577,20 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, seenPtr map[uintptr]struct{}, c
|
||||||
case opStructFieldRecursive:
|
case opStructFieldRecursive:
|
||||||
ptr := load(ctxptr, code.idx)
|
ptr := load(ctxptr, code.idx)
|
||||||
if ptr != 0 {
|
if ptr != 0 {
|
||||||
if _, exists := seenPtr[ptr]; exists {
|
if recursiveLevel > startDetectingCyclesAfter {
|
||||||
v := *(*interface{})(unsafe.Pointer(&interfaceHeader{
|
if _, exists := seenPtr[ptr]; exists {
|
||||||
typ: code.typ,
|
v := *(*interface{})(unsafe.Pointer(&interfaceHeader{
|
||||||
ptr: unsafe.Pointer(ptr),
|
typ: code.typ,
|
||||||
}))
|
ptr: unsafe.Pointer(ptr),
|
||||||
return &UnsupportedValueError{
|
}))
|
||||||
Value: reflect.ValueOf(v),
|
return &UnsupportedValueError{
|
||||||
Str: fmt.Sprintf("encountered a cycle via %s", code.typ),
|
Value: reflect.ValueOf(v),
|
||||||
|
Str: fmt.Sprintf("encountered a cycle via %s", code.typ),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
seenPtr[ptr] = struct{}{}
|
||||||
c := *(code.jmp.code)
|
c := *(code.jmp.code)
|
||||||
ctx := &encodeRuntimeContext{
|
ctx := &encodeRuntimeContext{
|
||||||
ptrs: make([]uintptr, c.totalLength()),
|
ptrs: make([]uintptr, c.totalLength()),
|
||||||
|
@ -587,7 +598,7 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, seenPtr map[uintptr]struct{}, c
|
||||||
ctx.init(ptr)
|
ctx.init(ptr)
|
||||||
c.end.next = newEndOp(&encodeCompileContext{})
|
c.end.next = newEndOp(&encodeCompileContext{})
|
||||||
c.op = c.op.ptrHeadToHead()
|
c.op = c.op.ptrHeadToHead()
|
||||||
if err := e.run(ctx, seenPtr, &c); err != nil {
|
if err := e.run(ctx, recursiveLevel+1, seenPtr, &c); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
code = code.next
|
code = code.next
|
||||||
|
@ -611,8 +622,9 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, seenPtr map[uintptr]struct{}, c
|
||||||
if !code.anonymousKey {
|
if !code.anonymousKey {
|
||||||
e.encodeBytes(code.key)
|
e.encodeBytes(code.key)
|
||||||
}
|
}
|
||||||
|
p := ptr + code.offset
|
||||||
code = code.next
|
code = code.next
|
||||||
store(ctxptr, code.idx, ptr+code.offset)
|
store(ctxptr, code.idx, p)
|
||||||
}
|
}
|
||||||
case opStructFieldAnonymousHead:
|
case opStructFieldAnonymousHead:
|
||||||
ptr := load(ctxptr, code.idx)
|
ptr := load(ctxptr, code.idx)
|
||||||
|
@ -4063,40 +4075,45 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, seenPtr map[uintptr]struct{}, c
|
||||||
}
|
}
|
||||||
e.encodeBytes(code.key)
|
e.encodeBytes(code.key)
|
||||||
ptr := load(ctxptr, code.headIdx)
|
ptr := load(ctxptr, code.headIdx)
|
||||||
|
p := ptr + code.offset
|
||||||
code = code.next
|
code = code.next
|
||||||
store(ctxptr, code.idx, ptr+code.offset)
|
store(ctxptr, code.idx, p)
|
||||||
case opStructFieldSlice:
|
case opStructFieldSlice:
|
||||||
if e.buf[len(e.buf)-1] != '{' {
|
if e.buf[len(e.buf)-1] != '{' {
|
||||||
e.encodeByte(',')
|
e.encodeByte(',')
|
||||||
}
|
}
|
||||||
e.encodeBytes(code.key)
|
e.encodeBytes(code.key)
|
||||||
ptr := load(ctxptr, code.headIdx)
|
ptr := load(ctxptr, code.headIdx)
|
||||||
|
p := ptr + code.offset
|
||||||
code = code.next
|
code = code.next
|
||||||
store(ctxptr, code.idx, ptr+code.offset)
|
store(ctxptr, code.idx, p)
|
||||||
case opStructFieldMap:
|
case opStructFieldMap:
|
||||||
if e.buf[len(e.buf)-1] != '{' {
|
if e.buf[len(e.buf)-1] != '{' {
|
||||||
e.encodeByte(',')
|
e.encodeByte(',')
|
||||||
}
|
}
|
||||||
e.encodeBytes(code.key)
|
e.encodeBytes(code.key)
|
||||||
ptr := load(ctxptr, code.headIdx)
|
ptr := load(ctxptr, code.headIdx)
|
||||||
|
p := ptr + code.offset
|
||||||
code = code.next
|
code = code.next
|
||||||
store(ctxptr, code.idx, ptr+code.offset)
|
store(ctxptr, code.idx, p)
|
||||||
case opStructFieldMapLoad:
|
case opStructFieldMapLoad:
|
||||||
if e.buf[len(e.buf)-1] != '{' {
|
if e.buf[len(e.buf)-1] != '{' {
|
||||||
e.encodeByte(',')
|
e.encodeByte(',')
|
||||||
}
|
}
|
||||||
e.encodeBytes(code.key)
|
e.encodeBytes(code.key)
|
||||||
ptr := load(ctxptr, code.headIdx)
|
ptr := load(ctxptr, code.headIdx)
|
||||||
|
p := ptr + code.offset
|
||||||
code = code.next
|
code = code.next
|
||||||
store(ctxptr, code.idx, ptr+code.offset)
|
store(ctxptr, code.idx, p)
|
||||||
case opStructFieldStruct:
|
case opStructFieldStruct:
|
||||||
if e.buf[len(e.buf)-1] != '{' {
|
if e.buf[len(e.buf)-1] != '{' {
|
||||||
e.encodeByte(',')
|
e.encodeByte(',')
|
||||||
}
|
}
|
||||||
e.encodeBytes(code.key)
|
e.encodeBytes(code.key)
|
||||||
ptr := load(ctxptr, code.headIdx)
|
ptr := load(ctxptr, code.headIdx)
|
||||||
|
p := ptr + code.offset
|
||||||
code = code.next
|
code = code.next
|
||||||
store(ctxptr, code.idx, ptr+code.offset)
|
store(ctxptr, code.idx, p)
|
||||||
case opStructFieldIndent:
|
case opStructFieldIndent:
|
||||||
if e.buf[len(e.buf)-2] != '{' || e.buf[len(e.buf)-1] == '}' {
|
if e.buf[len(e.buf)-2] != '{' || e.buf[len(e.buf)-1] == '}' {
|
||||||
e.encodeBytes([]byte{',', '\n'})
|
e.encodeBytes([]byte{',', '\n'})
|
||||||
|
@ -4105,8 +4122,9 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, seenPtr map[uintptr]struct{}, c
|
||||||
e.encodeBytes(code.key)
|
e.encodeBytes(code.key)
|
||||||
e.encodeByte(' ')
|
e.encodeByte(' ')
|
||||||
ptr := load(ctxptr, code.headIdx)
|
ptr := load(ctxptr, code.headIdx)
|
||||||
|
p := ptr + code.offset
|
||||||
code = code.next
|
code = code.next
|
||||||
store(ctxptr, code.idx, ptr+code.offset)
|
store(ctxptr, code.idx, p)
|
||||||
case opStructFieldIntIndent:
|
case opStructFieldIntIndent:
|
||||||
if e.buf[len(e.buf)-2] != '{' || e.buf[len(e.buf)-1] == '}' {
|
if e.buf[len(e.buf)-2] != '{' || e.buf[len(e.buf)-1] == '}' {
|
||||||
e.encodeBytes([]byte{',', '\n'})
|
e.encodeBytes([]byte{',', '\n'})
|
||||||
|
|
10
json_test.go
10
json_test.go
|
@ -121,7 +121,6 @@ func TestIndent(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tests of a large random structure.
|
// Tests of a large random structure.
|
||||||
|
|
||||||
func TestCompactBig(t *testing.T) {
|
func TestCompactBig(t *testing.T) {
|
||||||
initBig()
|
initBig()
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
|
@ -221,7 +220,10 @@ func trim(b []byte) []byte {
|
||||||
|
|
||||||
// Generate a random JSON object.
|
// Generate a random JSON object.
|
||||||
|
|
||||||
var jsonBig []byte
|
var (
|
||||||
|
jsonBig []byte
|
||||||
|
jsonVal interface{}
|
||||||
|
)
|
||||||
|
|
||||||
func initBig() {
|
func initBig() {
|
||||||
if len(jsonBig) > 0 {
|
if len(jsonBig) > 0 {
|
||||||
|
@ -231,8 +233,8 @@ func initBig() {
|
||||||
if testing.Short() {
|
if testing.Short() {
|
||||||
n = 100
|
n = 100
|
||||||
}
|
}
|
||||||
v := genValue(n)
|
jsonVal = genValue(n)
|
||||||
b, err := json.Marshal(v)
|
b, err := json.Marshal(jsonVal)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue