forked from mirror/go-json
Fix interface operation
This commit is contained in:
parent
d59d465042
commit
75f34df1c6
|
@ -131,7 +131,7 @@ func (c *opcode) totalLength() int {
|
||||||
var idx int
|
var idx int
|
||||||
for code := c; code.op != opEnd; {
|
for code := c; code.op != opEnd; {
|
||||||
idx = int(code.idx / uintptrSize)
|
idx = int(code.idx / uintptrSize)
|
||||||
if code.op == opInterfaceEnd || code.op == opStructFieldRecursiveEnd {
|
if code.op == opStructFieldRecursiveEnd {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
switch code.op.codeType() {
|
switch code.op.codeType() {
|
||||||
|
|
63
encode_vm.go
63
encode_vm.go
|
@ -207,65 +207,46 @@ func (e *Encoder) run(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet) (
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ctx.seenPtr = append(ctx.seenPtr, ptr)
|
ctx.seenPtr = append(ctx.seenPtr, ptr)
|
||||||
v := e.ptrToInterface(code, ptr)
|
iface := (*interfaceHeader)(e.ptrToUnsafePtr(ptr))
|
||||||
ctx.keepRefs = append(ctx.keepRefs, unsafe.Pointer(&v))
|
if iface == nil || iface.ptr == nil {
|
||||||
rv := reflect.ValueOf(v)
|
|
||||||
if rv.IsNil() {
|
|
||||||
b = encodeNull(b)
|
b = encodeNull(b)
|
||||||
b = encodeComma(b)
|
b = encodeComma(b)
|
||||||
code = code.next
|
code = code.next
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
vv := rv.Interface()
|
ctx.keepRefs = append(ctx.keepRefs, unsafe.Pointer(iface))
|
||||||
header := (*interfaceHeader)(unsafe.Pointer(&vv))
|
ifaceCodeSet, err := e.compileToGetCodeSet(uintptr(unsafe.Pointer(iface.typ)))
|
||||||
if header.typ.Kind() == reflect.Ptr {
|
|
||||||
if rv.Elem().IsNil() {
|
|
||||||
b = encodeNull(b)
|
|
||||||
b = encodeComma(b)
|
|
||||||
code = code.next
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
c, err := e.compileHead(&encodeCompileContext{
|
|
||||||
typ: header.typ,
|
|
||||||
root: code.root,
|
|
||||||
indent: code.indent,
|
|
||||||
structTypeToCompiledCode: map[uintptr]*compiledCode{},
|
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
beforeLastCode := c.beforeLastCode()
|
|
||||||
lastCode := beforeLastCode.next
|
totalLength := uintptr(codeSet.codeLength)
|
||||||
lastCode.idx = beforeLastCode.idx + uintptrSize
|
nextTotalLength := uintptr(ifaceCodeSet.codeLength)
|
||||||
totalLength := uintptr(code.totalLength())
|
|
||||||
nextTotalLength := uintptr(c.totalLength())
|
|
||||||
curlen := uintptr(len(ctx.ptrs))
|
curlen := uintptr(len(ctx.ptrs))
|
||||||
offsetNum := ptrOffset / uintptrSize
|
offsetNum := ptrOffset / uintptrSize
|
||||||
oldOffset := ptrOffset
|
|
||||||
ptrOffset += totalLength * uintptrSize
|
|
||||||
|
|
||||||
newLen := offsetNum + totalLength + nextTotalLength
|
newLen := offsetNum + totalLength + nextTotalLength
|
||||||
if curlen < newLen {
|
if curlen < newLen {
|
||||||
ctx.ptrs = append(ctx.ptrs, make([]uintptr, newLen-curlen)...)
|
ctx.ptrs = append(ctx.ptrs, make([]uintptr, newLen-curlen)...)
|
||||||
}
|
}
|
||||||
ctxptr = ctx.ptr() + ptrOffset // assign new ctxptr
|
oldPtrs := ctx.ptrs
|
||||||
|
|
||||||
store(ctxptr, 0, uintptr(header.ptr))
|
newPtrs := ctx.ptrs[(ptrOffset+totalLength*uintptrSize)/uintptrSize:]
|
||||||
store(ctxptr, lastCode.idx, oldOffset)
|
newPtrs[0] = uintptr(iface.ptr)
|
||||||
|
|
||||||
// link lastCode ( opInterfaceEnd ) => code.next
|
ctx.ptrs = newPtrs
|
||||||
lastCode.op = opInterfaceEnd
|
|
||||||
lastCode.next = code.next
|
|
||||||
|
|
||||||
code = c
|
bb, err := e.runEscaped(ctx, b, ifaceCodeSet)
|
||||||
recursiveLevel++
|
if err != nil {
|
||||||
case opInterfaceEnd:
|
return nil, err
|
||||||
recursiveLevel--
|
}
|
||||||
// restore ctxptr
|
|
||||||
offset := load(ctxptr, code.idx)
|
ctx.ptrs = oldPtrs
|
||||||
ctxptr = ctx.ptr() + offset
|
ctxptr = ctx.ptr()
|
||||||
ptrOffset = offset
|
ctx.seenPtr = ctx.seenPtr[:len(ctx.seenPtr)-1]
|
||||||
|
|
||||||
|
b = bb
|
||||||
code = code.next
|
code = code.next
|
||||||
case opMarshalJSON:
|
case opMarshalJSON:
|
||||||
ptr := load(ctxptr, code.idx)
|
ptr := load(ctxptr, code.idx)
|
||||||
|
|
|
@ -12,8 +12,6 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func (e *Encoder) runEscapedIndent(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet) ([]byte, error) {
|
func (e *Encoder) runEscapedIndent(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet) ([]byte, error) {
|
||||||
recursiveLevel := 0
|
|
||||||
var seenPtr map[uintptr]struct{}
|
|
||||||
ptrOffset := uintptr(0)
|
ptrOffset := uintptr(0)
|
||||||
ctxptr := ctx.ptr()
|
ctxptr := ctx.ptr()
|
||||||
code := codeSet.code
|
code := codeSet.code
|
||||||
|
@ -164,83 +162,52 @@ func (e *Encoder) runEscapedIndent(ctx *encodeRuntimeContext, b []byte, codeSet
|
||||||
code = code.next
|
code = code.next
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if seenPtr == nil {
|
for _, seen := range ctx.seenPtr {
|
||||||
seenPtr = map[uintptr]struct{}{}
|
if ptr == seen {
|
||||||
}
|
|
||||||
if _, exists := seenPtr[ptr]; exists {
|
|
||||||
return nil, errUnsupportedValue(code, ptr)
|
return nil, errUnsupportedValue(code, ptr)
|
||||||
}
|
}
|
||||||
seenPtr[ptr] = struct{}{}
|
}
|
||||||
v := e.ptrToInterface(code, ptr)
|
ctx.seenPtr = append(ctx.seenPtr, ptr)
|
||||||
ctx.keepRefs = append(ctx.keepRefs, unsafe.Pointer(&v))
|
iface := (*interfaceHeader)(e.ptrToUnsafePtr(ptr))
|
||||||
rv := reflect.ValueOf(v)
|
if iface == nil || iface.ptr == nil {
|
||||||
if rv.IsNil() {
|
|
||||||
b = encodeNull(b)
|
b = encodeNull(b)
|
||||||
b = encodeIndentComma(b)
|
b = encodeIndentComma(b)
|
||||||
code = code.next
|
code = code.next
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
vv := rv.Interface()
|
ctx.keepRefs = append(ctx.keepRefs, unsafe.Pointer(iface))
|
||||||
header := (*interfaceHeader)(unsafe.Pointer(&vv))
|
ifaceCodeSet, err := e.compileToGetCodeSet(uintptr(unsafe.Pointer(iface.typ)))
|
||||||
typ := header.typ
|
|
||||||
if typ.Kind() == reflect.Ptr {
|
|
||||||
typ = typ.Elem()
|
|
||||||
}
|
|
||||||
var c *opcode
|
|
||||||
if typ.Kind() == reflect.Map {
|
|
||||||
code, err := e.compileMap(&encodeCompileContext{
|
|
||||||
typ: typ,
|
|
||||||
root: code.root,
|
|
||||||
indent: code.indent,
|
|
||||||
structTypeToCompiledCode: map[uintptr]*compiledCode{},
|
|
||||||
}, false)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
c = code
|
|
||||||
} else {
|
totalLength := uintptr(codeSet.codeLength)
|
||||||
code, err := e.compile(&encodeCompileContext{
|
nextTotalLength := uintptr(ifaceCodeSet.codeLength)
|
||||||
typ: typ,
|
|
||||||
root: code.root,
|
|
||||||
indent: code.indent,
|
|
||||||
structTypeToCompiledCode: map[uintptr]*compiledCode{},
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
c = code
|
|
||||||
}
|
|
||||||
beforeLastCode := c.beforeLastCode()
|
|
||||||
lastCode := beforeLastCode.next
|
|
||||||
lastCode.idx = beforeLastCode.idx + uintptrSize
|
|
||||||
totalLength := uintptr(code.totalLength())
|
|
||||||
nextTotalLength := uintptr(c.totalLength())
|
|
||||||
curlen := uintptr(len(ctx.ptrs))
|
curlen := uintptr(len(ctx.ptrs))
|
||||||
offsetNum := ptrOffset / uintptrSize
|
offsetNum := ptrOffset / uintptrSize
|
||||||
oldOffset := ptrOffset
|
|
||||||
ptrOffset += totalLength * uintptrSize
|
|
||||||
|
|
||||||
newLen := offsetNum + totalLength + nextTotalLength
|
newLen := offsetNum + totalLength + nextTotalLength
|
||||||
if curlen < newLen {
|
if curlen < newLen {
|
||||||
ctx.ptrs = append(ctx.ptrs, make([]uintptr, newLen-curlen)...)
|
ctx.ptrs = append(ctx.ptrs, make([]uintptr, newLen-curlen)...)
|
||||||
}
|
}
|
||||||
ctxptr = ctx.ptr() + ptrOffset // assign new ctxptr
|
oldPtrs := ctx.ptrs
|
||||||
|
|
||||||
store(ctxptr, 0, uintptr(header.ptr))
|
newPtrs := ctx.ptrs[(ptrOffset+totalLength*uintptrSize)/uintptrSize:]
|
||||||
store(ctxptr, lastCode.idx, oldOffset)
|
newPtrs[0] = uintptr(iface.ptr)
|
||||||
|
|
||||||
// link lastCode ( opInterfaceEnd ) => code.next
|
ctx.ptrs = newPtrs
|
||||||
lastCode.op = opInterfaceEnd
|
|
||||||
lastCode.next = code.next
|
|
||||||
|
|
||||||
code = c
|
bb, err := e.runEscaped(ctx, b, ifaceCodeSet)
|
||||||
recursiveLevel++
|
if err != nil {
|
||||||
case opInterfaceEnd:
|
return nil, err
|
||||||
recursiveLevel--
|
}
|
||||||
// restore ctxptr
|
|
||||||
offset := load(ctxptr, code.idx)
|
ctx.ptrs = oldPtrs
|
||||||
ctxptr = ctx.ptr() + offset
|
ctxptr = ctx.ptr()
|
||||||
ptrOffset = offset
|
ctx.seenPtr = ctx.seenPtr[:len(ctx.seenPtr)-1]
|
||||||
|
|
||||||
|
b = bb
|
||||||
code = code.next
|
code = code.next
|
||||||
case opMarshalJSON:
|
case opMarshalJSON:
|
||||||
ptr := load(ctxptr, code.idx)
|
ptr := load(ctxptr, code.idx)
|
||||||
|
|
|
@ -12,8 +12,6 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func (e *Encoder) runIndent(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet) ([]byte, error) {
|
func (e *Encoder) runIndent(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet) ([]byte, error) {
|
||||||
recursiveLevel := 0
|
|
||||||
var seenPtr map[uintptr]struct{}
|
|
||||||
ptrOffset := uintptr(0)
|
ptrOffset := uintptr(0)
|
||||||
ctxptr := ctx.ptr()
|
ctxptr := ctx.ptr()
|
||||||
code := codeSet.code
|
code := codeSet.code
|
||||||
|
@ -164,83 +162,52 @@ func (e *Encoder) runIndent(ctx *encodeRuntimeContext, b []byte, codeSet *opcode
|
||||||
code = code.next
|
code = code.next
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if seenPtr == nil {
|
for _, seen := range ctx.seenPtr {
|
||||||
seenPtr = map[uintptr]struct{}{}
|
if ptr == seen {
|
||||||
}
|
|
||||||
if _, exists := seenPtr[ptr]; exists {
|
|
||||||
return nil, errUnsupportedValue(code, ptr)
|
return nil, errUnsupportedValue(code, ptr)
|
||||||
}
|
}
|
||||||
seenPtr[ptr] = struct{}{}
|
}
|
||||||
v := e.ptrToInterface(code, ptr)
|
ctx.seenPtr = append(ctx.seenPtr, ptr)
|
||||||
ctx.keepRefs = append(ctx.keepRefs, unsafe.Pointer(&v))
|
iface := (*interfaceHeader)(e.ptrToUnsafePtr(ptr))
|
||||||
rv := reflect.ValueOf(v)
|
if iface == nil || iface.ptr == nil {
|
||||||
if rv.IsNil() {
|
|
||||||
b = encodeNull(b)
|
b = encodeNull(b)
|
||||||
b = encodeIndentComma(b)
|
b = encodeIndentComma(b)
|
||||||
code = code.next
|
code = code.next
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
vv := rv.Interface()
|
ctx.keepRefs = append(ctx.keepRefs, unsafe.Pointer(iface))
|
||||||
header := (*interfaceHeader)(unsafe.Pointer(&vv))
|
ifaceCodeSet, err := e.compileToGetCodeSet(uintptr(unsafe.Pointer(iface.typ)))
|
||||||
typ := header.typ
|
|
||||||
if typ.Kind() == reflect.Ptr {
|
|
||||||
typ = typ.Elem()
|
|
||||||
}
|
|
||||||
var c *opcode
|
|
||||||
if typ.Kind() == reflect.Map {
|
|
||||||
code, err := e.compileMap(&encodeCompileContext{
|
|
||||||
typ: typ,
|
|
||||||
root: code.root,
|
|
||||||
indent: code.indent,
|
|
||||||
structTypeToCompiledCode: map[uintptr]*compiledCode{},
|
|
||||||
}, false)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
c = code
|
|
||||||
} else {
|
totalLength := uintptr(codeSet.codeLength)
|
||||||
code, err := e.compile(&encodeCompileContext{
|
nextTotalLength := uintptr(ifaceCodeSet.codeLength)
|
||||||
typ: typ,
|
|
||||||
root: code.root,
|
|
||||||
indent: code.indent,
|
|
||||||
structTypeToCompiledCode: map[uintptr]*compiledCode{},
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
c = code
|
|
||||||
}
|
|
||||||
beforeLastCode := c.beforeLastCode()
|
|
||||||
lastCode := beforeLastCode.next
|
|
||||||
lastCode.idx = beforeLastCode.idx + uintptrSize
|
|
||||||
totalLength := uintptr(code.totalLength())
|
|
||||||
nextTotalLength := uintptr(c.totalLength())
|
|
||||||
curlen := uintptr(len(ctx.ptrs))
|
curlen := uintptr(len(ctx.ptrs))
|
||||||
offsetNum := ptrOffset / uintptrSize
|
offsetNum := ptrOffset / uintptrSize
|
||||||
oldOffset := ptrOffset
|
|
||||||
ptrOffset += totalLength * uintptrSize
|
|
||||||
|
|
||||||
newLen := offsetNum + totalLength + nextTotalLength
|
newLen := offsetNum + totalLength + nextTotalLength
|
||||||
if curlen < newLen {
|
if curlen < newLen {
|
||||||
ctx.ptrs = append(ctx.ptrs, make([]uintptr, newLen-curlen)...)
|
ctx.ptrs = append(ctx.ptrs, make([]uintptr, newLen-curlen)...)
|
||||||
}
|
}
|
||||||
ctxptr = ctx.ptr() + ptrOffset // assign new ctxptr
|
oldPtrs := ctx.ptrs
|
||||||
|
|
||||||
store(ctxptr, 0, uintptr(header.ptr))
|
newPtrs := ctx.ptrs[(ptrOffset+totalLength*uintptrSize)/uintptrSize:]
|
||||||
store(ctxptr, lastCode.idx, oldOffset)
|
newPtrs[0] = uintptr(iface.ptr)
|
||||||
|
|
||||||
// link lastCode ( opInterfaceEnd ) => code.next
|
ctx.ptrs = newPtrs
|
||||||
lastCode.op = opInterfaceEnd
|
|
||||||
lastCode.next = code.next
|
|
||||||
|
|
||||||
code = c
|
bb, err := e.runEscaped(ctx, b, ifaceCodeSet)
|
||||||
recursiveLevel++
|
if err != nil {
|
||||||
case opInterfaceEnd:
|
return nil, err
|
||||||
recursiveLevel--
|
}
|
||||||
// restore ctxptr
|
|
||||||
offset := load(ctxptr, code.idx)
|
ctx.ptrs = oldPtrs
|
||||||
ctxptr = ctx.ptr() + offset
|
ctxptr = ctx.ptr()
|
||||||
ptrOffset = offset
|
ctx.seenPtr = ctx.seenPtr[:len(ctx.seenPtr)-1]
|
||||||
|
|
||||||
|
b = bb
|
||||||
code = code.next
|
code = code.next
|
||||||
case opMarshalJSON:
|
case opMarshalJSON:
|
||||||
ptr := load(ctxptr, code.idx)
|
ptr := load(ctxptr, code.idx)
|
||||||
|
|
Loading…
Reference in New Issue