mirror of https://github.com/goccy/go-json.git
Fix encoding of not empty interface type
This commit is contained in:
parent
5c527ab463
commit
92d8dcd13b
|
@ -7,6 +7,7 @@ import (
|
|||
"unsafe"
|
||||
|
||||
"github.com/goccy/go-json/internal/encoder"
|
||||
"github.com/goccy/go-json/internal/runtime"
|
||||
)
|
||||
|
||||
func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]byte, error) {
|
||||
|
@ -185,16 +186,27 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b
|
|||
}
|
||||
}
|
||||
ctx.SeenPtr = append(ctx.SeenPtr, p)
|
||||
iface := (*emptyInterface)(ptrToUnsafePtr(p))
|
||||
if iface.ptr == nil {
|
||||
var (
|
||||
typ *runtime.Type
|
||||
ifacePtr unsafe.Pointer
|
||||
)
|
||||
if code.Flags&encoder.NonEmptyInterfaceFlags != 0 {
|
||||
iface := (*nonEmptyInterface)(ptrToUnsafePtr(p))
|
||||
ifacePtr = iface.ptr
|
||||
typ = iface.itab.typ
|
||||
} else {
|
||||
iface := (*emptyInterface)(ptrToUnsafePtr(p))
|
||||
ifacePtr = iface.ptr
|
||||
typ = iface.typ
|
||||
}
|
||||
if ifacePtr == nil {
|
||||
b = appendNull(ctx, b)
|
||||
b = appendComma(ctx, b)
|
||||
code = code.Next
|
||||
break
|
||||
}
|
||||
|
||||
ctx.KeepRefs = append(ctx.KeepRefs, unsafe.Pointer(iface))
|
||||
ifaceCodeSet, err := encoder.CompileToGetCodeSet(uintptr(unsafe.Pointer(iface.typ)))
|
||||
ctx.KeepRefs = append(ctx.KeepRefs, unsafe.Pointer(p))
|
||||
ifaceCodeSet, err := encoder.CompileToGetCodeSet(uintptr(unsafe.Pointer(typ)))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -223,7 +235,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b
|
|||
ctxptr = ctx.Ptr() + ptrOffset // assign new ctxptr
|
||||
|
||||
end := ifaceCodeSet.EndCode
|
||||
store(ctxptr, c.Idx, uintptr(iface.ptr))
|
||||
store(ctxptr, c.Idx, uintptr(ifacePtr))
|
||||
store(ctxptr, end.Idx, oldOffset)
|
||||
store(ctxptr, end.ElemIdx, uintptr(unsafe.Pointer(code.Next)))
|
||||
storeIndent(ctxptr, end, uintptr(oldBaseIndent))
|
||||
|
|
|
@ -13,15 +13,16 @@ const uintptrSize = 4 << (^uintptr(0) >> 63)
|
|||
type OpFlags uint16
|
||||
|
||||
const (
|
||||
AnonymousHeadFlags OpFlags = 1 << 0
|
||||
AnonymousKeyFlags OpFlags = 1 << 1
|
||||
IndirectFlags OpFlags = 1 << 2
|
||||
IsTaggedKeyFlags OpFlags = 1 << 3
|
||||
NilCheckFlags OpFlags = 1 << 4
|
||||
AddrForMarshalerFlags OpFlags = 1 << 5
|
||||
IsNextOpPtrTypeFlags OpFlags = 1 << 6
|
||||
IsNilableTypeFlags OpFlags = 1 << 7
|
||||
MarshalerContextFlags OpFlags = 1 << 8
|
||||
AnonymousHeadFlags OpFlags = 1 << 0
|
||||
AnonymousKeyFlags OpFlags = 1 << 1
|
||||
IndirectFlags OpFlags = 1 << 2
|
||||
IsTaggedKeyFlags OpFlags = 1 << 3
|
||||
NilCheckFlags OpFlags = 1 << 4
|
||||
AddrForMarshalerFlags OpFlags = 1 << 5
|
||||
IsNextOpPtrTypeFlags OpFlags = 1 << 6
|
||||
IsNilableTypeFlags OpFlags = 1 << 7
|
||||
MarshalerContextFlags OpFlags = 1 << 8
|
||||
NonEmptyInterfaceFlags OpFlags = 1 << 9
|
||||
)
|
||||
|
||||
type Opcode struct {
|
||||
|
@ -743,6 +744,10 @@ func newMapEndCode(ctx *compileContext, head *Opcode) *Opcode {
|
|||
}
|
||||
|
||||
func newInterfaceCode(ctx *compileContext) *Opcode {
|
||||
var flag OpFlags
|
||||
if ctx.typ.NumMethod() > 0 {
|
||||
flag |= NonEmptyInterfaceFlags
|
||||
}
|
||||
return &Opcode{
|
||||
Op: OpInterface,
|
||||
Idx: opcodeOffset(ctx.ptrIndex),
|
||||
|
@ -750,6 +755,7 @@ func newInterfaceCode(ctx *compileContext) *Opcode {
|
|||
Type: ctx.typ,
|
||||
DisplayIdx: ctx.opcodeIndex,
|
||||
Indent: ctx.indent,
|
||||
Flags: flag,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -33,6 +33,15 @@ type emptyInterface struct {
|
|||
ptr unsafe.Pointer
|
||||
}
|
||||
|
||||
type nonEmptyInterface struct {
|
||||
itab *struct {
|
||||
ityp *runtime.Type // static interface type
|
||||
typ *runtime.Type // dynamic concrete type
|
||||
// unused fields...
|
||||
}
|
||||
ptr unsafe.Pointer
|
||||
}
|
||||
|
||||
func errUnimplementedOp(op encoder.OpType) error {
|
||||
return fmt.Errorf("encoder: opcode %s has not been implemented", op)
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"unsafe"
|
||||
|
||||
"github.com/goccy/go-json/internal/encoder"
|
||||
"github.com/goccy/go-json/internal/runtime"
|
||||
)
|
||||
|
||||
func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]byte, error) {
|
||||
|
@ -185,16 +186,27 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b
|
|||
}
|
||||
}
|
||||
ctx.SeenPtr = append(ctx.SeenPtr, p)
|
||||
iface := (*emptyInterface)(ptrToUnsafePtr(p))
|
||||
if iface.ptr == nil {
|
||||
var (
|
||||
typ *runtime.Type
|
||||
ifacePtr unsafe.Pointer
|
||||
)
|
||||
if code.Flags&encoder.NonEmptyInterfaceFlags != 0 {
|
||||
iface := (*nonEmptyInterface)(ptrToUnsafePtr(p))
|
||||
ifacePtr = iface.ptr
|
||||
typ = iface.itab.typ
|
||||
} else {
|
||||
iface := (*emptyInterface)(ptrToUnsafePtr(p))
|
||||
ifacePtr = iface.ptr
|
||||
typ = iface.typ
|
||||
}
|
||||
if ifacePtr == nil {
|
||||
b = appendNull(ctx, b)
|
||||
b = appendComma(ctx, b)
|
||||
code = code.Next
|
||||
break
|
||||
}
|
||||
|
||||
ctx.KeepRefs = append(ctx.KeepRefs, unsafe.Pointer(iface))
|
||||
ifaceCodeSet, err := encoder.CompileToGetCodeSet(uintptr(unsafe.Pointer(iface.typ)))
|
||||
ctx.KeepRefs = append(ctx.KeepRefs, unsafe.Pointer(p))
|
||||
ifaceCodeSet, err := encoder.CompileToGetCodeSet(uintptr(unsafe.Pointer(typ)))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -223,7 +235,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b
|
|||
ctxptr = ctx.Ptr() + ptrOffset // assign new ctxptr
|
||||
|
||||
end := ifaceCodeSet.EndCode
|
||||
store(ctxptr, c.Idx, uintptr(iface.ptr))
|
||||
store(ctxptr, c.Idx, uintptr(ifacePtr))
|
||||
store(ctxptr, end.Idx, oldOffset)
|
||||
store(ctxptr, end.ElemIdx, uintptr(unsafe.Pointer(code.Next)))
|
||||
storeIndent(ctxptr, end, uintptr(oldBaseIndent))
|
||||
|
|
|
@ -26,6 +26,15 @@ type emptyInterface struct {
|
|||
ptr unsafe.Pointer
|
||||
}
|
||||
|
||||
type nonEmptyInterface struct {
|
||||
itab *struct {
|
||||
ityp *runtime.Type // static interface type
|
||||
typ *runtime.Type // dynamic concrete type
|
||||
// unused fields...
|
||||
}
|
||||
ptr unsafe.Pointer
|
||||
}
|
||||
|
||||
func errUnimplementedOp(op encoder.OpType) error {
|
||||
return fmt.Errorf("encoder: opcode %s has not been implemented", op)
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"unsafe"
|
||||
|
||||
"github.com/goccy/go-json/internal/encoder"
|
||||
"github.com/goccy/go-json/internal/runtime"
|
||||
)
|
||||
|
||||
func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]byte, error) {
|
||||
|
@ -185,16 +186,27 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b
|
|||
}
|
||||
}
|
||||
ctx.SeenPtr = append(ctx.SeenPtr, p)
|
||||
iface := (*emptyInterface)(ptrToUnsafePtr(p))
|
||||
if iface.ptr == nil {
|
||||
var (
|
||||
typ *runtime.Type
|
||||
ifacePtr unsafe.Pointer
|
||||
)
|
||||
if code.Flags&encoder.NonEmptyInterfaceFlags != 0 {
|
||||
iface := (*nonEmptyInterface)(ptrToUnsafePtr(p))
|
||||
ifacePtr = iface.ptr
|
||||
typ = iface.itab.typ
|
||||
} else {
|
||||
iface := (*emptyInterface)(ptrToUnsafePtr(p))
|
||||
ifacePtr = iface.ptr
|
||||
typ = iface.typ
|
||||
}
|
||||
if ifacePtr == nil {
|
||||
b = appendNull(ctx, b)
|
||||
b = appendComma(ctx, b)
|
||||
code = code.Next
|
||||
break
|
||||
}
|
||||
|
||||
ctx.KeepRefs = append(ctx.KeepRefs, unsafe.Pointer(iface))
|
||||
ifaceCodeSet, err := encoder.CompileToGetCodeSet(uintptr(unsafe.Pointer(iface.typ)))
|
||||
ctx.KeepRefs = append(ctx.KeepRefs, unsafe.Pointer(p))
|
||||
ifaceCodeSet, err := encoder.CompileToGetCodeSet(uintptr(unsafe.Pointer(typ)))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -223,7 +235,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b
|
|||
ctxptr = ctx.Ptr() + ptrOffset // assign new ctxptr
|
||||
|
||||
end := ifaceCodeSet.EndCode
|
||||
store(ctxptr, c.Idx, uintptr(iface.ptr))
|
||||
store(ctxptr, c.Idx, uintptr(ifacePtr))
|
||||
store(ctxptr, end.Idx, oldOffset)
|
||||
store(ctxptr, end.ElemIdx, uintptr(unsafe.Pointer(code.Next)))
|
||||
storeIndent(ctxptr, end, uintptr(oldBaseIndent))
|
||||
|
|
|
@ -28,6 +28,15 @@ type emptyInterface struct {
|
|||
ptr unsafe.Pointer
|
||||
}
|
||||
|
||||
type nonEmptyInterface struct {
|
||||
itab *struct {
|
||||
ityp *runtime.Type // static interface type
|
||||
typ *runtime.Type // dynamic concrete type
|
||||
// unused fields...
|
||||
}
|
||||
ptr unsafe.Pointer
|
||||
}
|
||||
|
||||
func errUnimplementedOp(op encoder.OpType) error {
|
||||
return fmt.Errorf("encoder (indent): opcode %s has not been implemented", op)
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"unsafe"
|
||||
|
||||
"github.com/goccy/go-json/internal/encoder"
|
||||
"github.com/goccy/go-json/internal/runtime"
|
||||
)
|
||||
|
||||
func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]byte, error) {
|
||||
|
@ -185,16 +186,27 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b
|
|||
}
|
||||
}
|
||||
ctx.SeenPtr = append(ctx.SeenPtr, p)
|
||||
iface := (*emptyInterface)(ptrToUnsafePtr(p))
|
||||
if iface.ptr == nil {
|
||||
var (
|
||||
typ *runtime.Type
|
||||
ifacePtr unsafe.Pointer
|
||||
)
|
||||
if code.Flags&encoder.NonEmptyInterfaceFlags != 0 {
|
||||
iface := (*nonEmptyInterface)(ptrToUnsafePtr(p))
|
||||
ifacePtr = iface.ptr
|
||||
typ = iface.itab.typ
|
||||
} else {
|
||||
iface := (*emptyInterface)(ptrToUnsafePtr(p))
|
||||
ifacePtr = iface.ptr
|
||||
typ = iface.typ
|
||||
}
|
||||
if ifacePtr == nil {
|
||||
b = appendNull(ctx, b)
|
||||
b = appendComma(ctx, b)
|
||||
code = code.Next
|
||||
break
|
||||
}
|
||||
|
||||
ctx.KeepRefs = append(ctx.KeepRefs, unsafe.Pointer(iface))
|
||||
ifaceCodeSet, err := encoder.CompileToGetCodeSet(uintptr(unsafe.Pointer(iface.typ)))
|
||||
ctx.KeepRefs = append(ctx.KeepRefs, unsafe.Pointer(p))
|
||||
ifaceCodeSet, err := encoder.CompileToGetCodeSet(uintptr(unsafe.Pointer(typ)))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -223,7 +235,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b
|
|||
ctxptr = ctx.Ptr() + ptrOffset // assign new ctxptr
|
||||
|
||||
end := ifaceCodeSet.EndCode
|
||||
store(ctxptr, c.Idx, uintptr(iface.ptr))
|
||||
store(ctxptr, c.Idx, uintptr(ifacePtr))
|
||||
store(ctxptr, end.Idx, oldOffset)
|
||||
store(ctxptr, end.ElemIdx, uintptr(unsafe.Pointer(code.Next)))
|
||||
storeIndent(ctxptr, end, uintptr(oldBaseIndent))
|
||||
|
|
|
@ -35,6 +35,15 @@ type emptyInterface struct {
|
|||
ptr unsafe.Pointer
|
||||
}
|
||||
|
||||
type nonEmptyInterface struct {
|
||||
itab *struct {
|
||||
ityp *runtime.Type // static interface type
|
||||
typ *runtime.Type // dynamic concrete type
|
||||
// unused fields...
|
||||
}
|
||||
ptr unsafe.Pointer
|
||||
}
|
||||
|
||||
func errUnimplementedOp(op encoder.OpType) error {
|
||||
return fmt.Errorf("encoder (indent): opcode %s has not been implemented", op)
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"unsafe"
|
||||
|
||||
"github.com/goccy/go-json/internal/encoder"
|
||||
"github.com/goccy/go-json/internal/runtime"
|
||||
)
|
||||
|
||||
func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]byte, error) {
|
||||
|
@ -185,16 +186,27 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b
|
|||
}
|
||||
}
|
||||
ctx.SeenPtr = append(ctx.SeenPtr, p)
|
||||
iface := (*emptyInterface)(ptrToUnsafePtr(p))
|
||||
if iface.ptr == nil {
|
||||
var (
|
||||
typ *runtime.Type
|
||||
ifacePtr unsafe.Pointer
|
||||
)
|
||||
if code.Flags&encoder.NonEmptyInterfaceFlags != 0 {
|
||||
iface := (*nonEmptyInterface)(ptrToUnsafePtr(p))
|
||||
ifacePtr = iface.ptr
|
||||
typ = iface.itab.typ
|
||||
} else {
|
||||
iface := (*emptyInterface)(ptrToUnsafePtr(p))
|
||||
ifacePtr = iface.ptr
|
||||
typ = iface.typ
|
||||
}
|
||||
if ifacePtr == nil {
|
||||
b = appendNull(ctx, b)
|
||||
b = appendComma(ctx, b)
|
||||
code = code.Next
|
||||
break
|
||||
}
|
||||
|
||||
ctx.KeepRefs = append(ctx.KeepRefs, unsafe.Pointer(iface))
|
||||
ifaceCodeSet, err := encoder.CompileToGetCodeSet(uintptr(unsafe.Pointer(iface.typ)))
|
||||
ctx.KeepRefs = append(ctx.KeepRefs, unsafe.Pointer(p))
|
||||
ifaceCodeSet, err := encoder.CompileToGetCodeSet(uintptr(unsafe.Pointer(typ)))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -223,7 +235,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b
|
|||
ctxptr = ctx.Ptr() + ptrOffset // assign new ctxptr
|
||||
|
||||
end := ifaceCodeSet.EndCode
|
||||
store(ctxptr, c.Idx, uintptr(iface.ptr))
|
||||
store(ctxptr, c.Idx, uintptr(ifacePtr))
|
||||
store(ctxptr, end.Idx, oldOffset)
|
||||
store(ctxptr, end.ElemIdx, uintptr(unsafe.Pointer(code.Next)))
|
||||
storeIndent(ctxptr, end, uintptr(oldBaseIndent))
|
||||
|
|
Loading…
Reference in New Issue