mirror of https://github.com/goccy/go-json.git
Refactor vm sources for encoding ( use same source )
This commit is contained in:
parent
fc968c75ee
commit
f696453c1b
|
@ -1450,7 +1450,6 @@ func compileStruct(ctx *compileContext, isPtr bool) (*Opcode, error) {
|
|||
}
|
||||
fieldIdx++
|
||||
}
|
||||
ctx = ctx.decIndent()
|
||||
|
||||
structEndCode := &Opcode{
|
||||
Op: OpStructEnd,
|
||||
|
@ -1459,6 +1458,8 @@ func compileStruct(ctx *compileContext, isPtr bool) (*Opcode, error) {
|
|||
Next: newEndOp(ctx),
|
||||
}
|
||||
|
||||
ctx = ctx.decIndent()
|
||||
|
||||
// no struct field
|
||||
if head == nil {
|
||||
head = &Opcode{
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
package vm
|
||||
|
||||
import (
|
||||
// HACK: compile order
|
||||
// `vm`, `vm_escaped`, `vm_indent`, `vm_escaped_indent`, `vm_debug` packages uses a lot of memory to compile,
|
||||
// so forcibly make dependencies and avoid compiling in concurrent.
|
||||
// dependency order: vm => vm_escaped => vm_indent => vm_escaped_indent => vm_debug
|
||||
_ "github.com/goccy/go-json/internal/encoder/vm_escaped"
|
||||
)
|
|
@ -2,12 +2,41 @@ package vm
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"unsafe"
|
||||
|
||||
"github.com/goccy/go-json/internal/encoder"
|
||||
"github.com/goccy/go-json/internal/runtime"
|
||||
)
|
||||
|
||||
const uintptrSize = 4 << (^uintptr(0) >> 63)
|
||||
|
||||
var (
|
||||
appendInt = encoder.AppendInt
|
||||
appendUint = encoder.AppendUint
|
||||
appendFloat32 = encoder.AppendFloat32
|
||||
appendFloat64 = encoder.AppendFloat64
|
||||
appendString = encoder.AppendString
|
||||
appendByteSlice = encoder.AppendByteSlice
|
||||
appendNumber = encoder.AppendNumber
|
||||
errUnsupportedValue = encoder.ErrUnsupportedValue
|
||||
errUnsupportedFloat = encoder.ErrUnsupportedFloat
|
||||
mapiterinit = encoder.MapIterInit
|
||||
mapiterkey = encoder.MapIterKey
|
||||
mapitervalue = encoder.MapIterValue
|
||||
mapiternext = encoder.MapIterNext
|
||||
maplen = encoder.MapLen
|
||||
)
|
||||
|
||||
type emptyInterface struct {
|
||||
typ *runtime.Type
|
||||
ptr unsafe.Pointer
|
||||
}
|
||||
|
||||
func errUnimplementedOp(op encoder.OpType) error {
|
||||
return fmt.Errorf("encoder: opcode %s has not been implemented", op)
|
||||
}
|
||||
|
||||
func load(base uintptr, idx uintptr) uintptr {
|
||||
addr := base + idx
|
||||
return **(**uintptr)(unsafe.Pointer(&addr))
|
||||
|
@ -76,6 +105,57 @@ func appendComma(b []byte) []byte {
|
|||
return append(b, ',')
|
||||
}
|
||||
|
||||
func appendColon(b []byte) []byte {
|
||||
last := len(b) - 1
|
||||
b[last] = ':'
|
||||
return b
|
||||
}
|
||||
|
||||
func appendMapKeyValue(ctx *encoder.RuntimeContext, code *encoder.Opcode, b, key, value []byte) []byte {
|
||||
b = append(b, key...)
|
||||
b[len(b)-1] = ':'
|
||||
return append(b, value...)
|
||||
}
|
||||
|
||||
func appendMapEnd(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
|
||||
b[len(b)-1] = '}'
|
||||
b = append(b, ',')
|
||||
return b
|
||||
}
|
||||
|
||||
func appendInterface(ctx *encoder.RuntimeContext, codeSet *encoder.OpcodeSet, opt encoder.Option, code *encoder.Opcode, b []byte, iface *emptyInterface, ptrOffset uintptr) ([]byte, error) {
|
||||
ctx.KeepRefs = append(ctx.KeepRefs, unsafe.Pointer(iface))
|
||||
ifaceCodeSet, err := encoder.CompileToGetCodeSet(uintptr(unsafe.Pointer(iface.typ)))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
totalLength := uintptr(codeSet.CodeLength)
|
||||
nextTotalLength := uintptr(ifaceCodeSet.CodeLength)
|
||||
|
||||
curlen := uintptr(len(ctx.Ptrs))
|
||||
offsetNum := ptrOffset / uintptrSize
|
||||
|
||||
newLen := offsetNum + totalLength + nextTotalLength
|
||||
if curlen < newLen {
|
||||
ctx.Ptrs = append(ctx.Ptrs, make([]uintptr, newLen-curlen)...)
|
||||
}
|
||||
oldPtrs := ctx.Ptrs
|
||||
|
||||
newPtrs := ctx.Ptrs[(ptrOffset+totalLength*uintptrSize)/uintptrSize:]
|
||||
newPtrs[0] = uintptr(iface.ptr)
|
||||
|
||||
ctx.Ptrs = newPtrs
|
||||
|
||||
bb, err := Run(ctx, b, ifaceCodeSet, opt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ctx.Ptrs = oldPtrs
|
||||
return bb, nil
|
||||
}
|
||||
|
||||
func appendMarshalJSON(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte, v interface{}) ([]byte, error) {
|
||||
return encoder.AppendMarshalJSON(ctx, code, b, v, false)
|
||||
}
|
||||
|
@ -84,14 +164,38 @@ func appendMarshalText(code *encoder.Opcode, b []byte, v interface{}) ([]byte, e
|
|||
return encoder.AppendMarshalText(code, b, v, false)
|
||||
}
|
||||
|
||||
func appendStructKey(_ *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
|
||||
return append(b, code.Key...)
|
||||
func appendArrayHead(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte {
|
||||
return append(b, '[')
|
||||
}
|
||||
|
||||
func appendArrayEnd(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
|
||||
last := len(b) - 1
|
||||
b[last] = ']'
|
||||
return append(b, ',')
|
||||
}
|
||||
|
||||
func appendEmptyArray(b []byte) []byte {
|
||||
return append(b, '[', ']', ',')
|
||||
}
|
||||
|
||||
func appendEmptyObject(b []byte) []byte {
|
||||
return append(b, '{', '}', ',')
|
||||
}
|
||||
|
||||
func appendObjectEnd(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte {
|
||||
last := len(b) - 1
|
||||
b[last] = '}'
|
||||
return append(b, ',')
|
||||
}
|
||||
|
||||
func appendStructHead(b []byte) []byte {
|
||||
return append(b, '{')
|
||||
}
|
||||
|
||||
func appendStructKey(_ *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
|
||||
return append(b, code.Key...)
|
||||
}
|
||||
|
||||
func appendStructEnd(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte {
|
||||
return append(b, '}', ',')
|
||||
}
|
||||
|
@ -104,3 +208,8 @@ func appendStructEndSkipLast(ctx *encoder.RuntimeContext, code *encoder.Opcode,
|
|||
}
|
||||
return appendStructEnd(ctx, code, b)
|
||||
}
|
||||
|
||||
func restoreIndent(ctx *encoder.RuntimeContext, code *encoder.Opcode, ctxptr uintptr) {}
|
||||
func storeIndent(ctxptr uintptr, code *encoder.Opcode, indent uintptr) {}
|
||||
func appendMapKeyIndent(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte { return b }
|
||||
func appendArrayElemIndent(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte { return b }
|
||||
|
|
|
@ -1,45 +1,13 @@
|
|||
package vm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"sort"
|
||||
"unsafe"
|
||||
|
||||
"github.com/goccy/go-json/internal/encoder"
|
||||
"github.com/goccy/go-json/internal/runtime"
|
||||
|
||||
// HACK: compile order
|
||||
// `vm`, `vm_escaped`, `vm_indent`, `vm_escaped_indent`, `vm_debug` packages uses a lot of memory to compile,
|
||||
// so forcibly make dependencies and avoid compiling in concurrent.
|
||||
// dependency order: vm => vm_escaped => vm_indent => vm_escaped_indent => vm_debug
|
||||
_ "github.com/goccy/go-json/internal/encoder/vm_escaped"
|
||||
)
|
||||
|
||||
const uintptrSize = 4 << (^uintptr(0) >> 63)
|
||||
|
||||
var (
|
||||
appendInt = encoder.AppendInt
|
||||
appendUint = encoder.AppendUint
|
||||
appendFloat32 = encoder.AppendFloat32
|
||||
appendFloat64 = encoder.AppendFloat64
|
||||
appendString = encoder.AppendString
|
||||
appendByteSlice = encoder.AppendByteSlice
|
||||
appendNumber = encoder.AppendNumber
|
||||
errUnsupportedValue = encoder.ErrUnsupportedValue
|
||||
errUnsupportedFloat = encoder.ErrUnsupportedFloat
|
||||
mapiterinit = encoder.MapIterInit
|
||||
mapiterkey = encoder.MapIterKey
|
||||
mapitervalue = encoder.MapIterValue
|
||||
mapiternext = encoder.MapIterNext
|
||||
maplen = encoder.MapLen
|
||||
)
|
||||
|
||||
type emptyInterface struct {
|
||||
typ *runtime.Type
|
||||
ptr unsafe.Pointer
|
||||
}
|
||||
|
||||
func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt encoder.Option) ([]byte, error) {
|
||||
recursiveLevel := 0
|
||||
ptrOffset := uintptr(0)
|
||||
|
@ -49,7 +17,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
for {
|
||||
switch code.Op {
|
||||
default:
|
||||
return nil, fmt.Errorf("encoder: opcode %s has not been implemented", code.Op)
|
||||
return nil, errUnimplementedOp(code.Op)
|
||||
case encoder.OpPtr:
|
||||
p := load(ctxptr, code.Idx)
|
||||
code = code.Next
|
||||
|
@ -121,7 +89,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
case encoder.OpFloat64:
|
||||
v := ptrToFloat64(load(ctxptr, code.Idx))
|
||||
if math.IsInf(v, 0) || math.IsNaN(v) {
|
||||
return nil, encoder.ErrUnsupportedFloat(v)
|
||||
return nil, errUnsupportedFloat(v)
|
||||
}
|
||||
b = appendFloat64(b, v)
|
||||
b = appendComma(b)
|
||||
|
@ -216,35 +184,10 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
code = code.Next
|
||||
break
|
||||
}
|
||||
ctx.KeepRefs = append(ctx.KeepRefs, unsafe.Pointer(iface))
|
||||
ifaceCodeSet, err := encoder.CompileToGetCodeSet(uintptr(unsafe.Pointer(iface.typ)))
|
||||
bb, err := appendInterface(ctx, codeSet, opt, code, b, iface, ptrOffset)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
totalLength := uintptr(codeSet.CodeLength)
|
||||
nextTotalLength := uintptr(ifaceCodeSet.CodeLength)
|
||||
|
||||
curlen := uintptr(len(ctx.Ptrs))
|
||||
offsetNum := ptrOffset / uintptrSize
|
||||
|
||||
newLen := offsetNum + totalLength + nextTotalLength
|
||||
if curlen < newLen {
|
||||
ctx.Ptrs = append(ctx.Ptrs, make([]uintptr, newLen-curlen)...)
|
||||
}
|
||||
oldPtrs := ctx.Ptrs
|
||||
|
||||
newPtrs := ctx.Ptrs[(ptrOffset+totalLength*uintptrSize)/uintptrSize:]
|
||||
newPtrs[0] = uintptr(iface.ptr)
|
||||
|
||||
ctx.Ptrs = newPtrs
|
||||
|
||||
bb, err := Run(ctx, b, ifaceCodeSet, opt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ctx.Ptrs = oldPtrs
|
||||
ctxptr = ctx.Ptr()
|
||||
ctx.SeenPtr = ctx.SeenPtr[:len(ctx.SeenPtr)-1]
|
||||
|
||||
|
@ -327,11 +270,11 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
store(ctxptr, code.Length, uintptr(slice.Len))
|
||||
store(ctxptr, code.Idx, uintptr(slice.Data))
|
||||
if slice.Len > 0 {
|
||||
b = append(b, '[')
|
||||
b = appendArrayHead(ctx, code, b)
|
||||
code = code.Next
|
||||
store(ctxptr, code.Idx, uintptr(slice.Data))
|
||||
} else {
|
||||
b = append(b, '[', ']', ',')
|
||||
b = appendEmptyArray(b)
|
||||
code = code.End.Next
|
||||
}
|
||||
case encoder.OpSliceElem:
|
||||
|
@ -339,15 +282,14 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
length := load(ctxptr, code.Length)
|
||||
idx++
|
||||
if idx < length {
|
||||
b = appendArrayElemIndent(ctx, code, b)
|
||||
store(ctxptr, code.ElemIdx, idx)
|
||||
data := load(ctxptr, code.HeadIdx)
|
||||
size := code.Size
|
||||
code = code.Next
|
||||
store(ctxptr, code.Idx, data+idx*size)
|
||||
} else {
|
||||
last := len(b) - 1
|
||||
b[last] = ']'
|
||||
b = appendComma(b)
|
||||
b = appendArrayEnd(ctx, code, b)
|
||||
code = code.End.Next
|
||||
}
|
||||
case encoder.OpArrayPtr:
|
||||
|
@ -369,27 +311,26 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
break
|
||||
}
|
||||
if code.Length > 0 {
|
||||
b = append(b, '[')
|
||||
b = appendArrayHead(ctx, code, b)
|
||||
store(ctxptr, code.ElemIdx, 0)
|
||||
code = code.Next
|
||||
store(ctxptr, code.Idx, p)
|
||||
} else {
|
||||
b = append(b, '[', ']', ',')
|
||||
b = appendEmptyArray(b)
|
||||
code = code.End.Next
|
||||
}
|
||||
case encoder.OpArrayElem:
|
||||
idx := load(ctxptr, code.ElemIdx)
|
||||
idx++
|
||||
if idx < code.Length {
|
||||
b = appendArrayElemIndent(ctx, code, b)
|
||||
store(ctxptr, code.ElemIdx, idx)
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
size := code.Size
|
||||
code = code.Next
|
||||
store(ctxptr, code.Idx, p+idx*size)
|
||||
} else {
|
||||
last := len(b) - 1
|
||||
b[last] = ']'
|
||||
b = appendComma(b)
|
||||
b = appendArrayEnd(ctx, code, b)
|
||||
code = code.End.Next
|
||||
}
|
||||
case encoder.OpMapPtr:
|
||||
|
@ -413,11 +354,11 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
uptr := ptrToUnsafePtr(p)
|
||||
mlen := maplen(uptr)
|
||||
if mlen <= 0 {
|
||||
b = append(b, '{', '}', ',')
|
||||
b = appendEmptyObject(b)
|
||||
code = code.End.Next
|
||||
break
|
||||
}
|
||||
b = append(b, '{')
|
||||
b = appendStructHead(b)
|
||||
iter := mapiterinit(code.Type, uptr)
|
||||
ctx.KeepRefs = append(ctx.KeepRefs, iter)
|
||||
store(ctxptr, code.ElemIdx, 0)
|
||||
|
@ -428,6 +369,8 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
mapCtx.Pos = append(mapCtx.Pos, len(b))
|
||||
ctx.KeepRefs = append(ctx.KeepRefs, unsafe.Pointer(mapCtx))
|
||||
store(ctxptr, code.End.MapPos, uintptr(unsafe.Pointer(mapCtx)))
|
||||
} else {
|
||||
b = appendMapKeyIndent(ctx, code.Next, b)
|
||||
}
|
||||
key := mapiterkey(iter)
|
||||
store(ctxptr, code.Next.Idx, uintptr(key))
|
||||
|
@ -438,16 +381,15 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
idx++
|
||||
if (opt & encoder.UnorderedMapOption) != 0 {
|
||||
if idx < length {
|
||||
b = appendMapKeyIndent(ctx, code, b)
|
||||
store(ctxptr, code.ElemIdx, idx)
|
||||
ptr := load(ctxptr, code.MapIter)
|
||||
iter := ptrToUnsafePtr(ptr)
|
||||
store(ctxptr, code.ElemIdx, idx)
|
||||
key := mapiterkey(iter)
|
||||
store(ctxptr, code.Next.Idx, uintptr(key))
|
||||
code = code.Next
|
||||
} else {
|
||||
last := len(b) - 1
|
||||
b[last] = '}'
|
||||
b = appendComma(b)
|
||||
b = appendObjectEnd(ctx, code, b)
|
||||
code = code.End.Next
|
||||
}
|
||||
} else {
|
||||
|
@ -467,8 +409,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
}
|
||||
case encoder.OpMapValue:
|
||||
if (opt & encoder.UnorderedMapOption) != 0 {
|
||||
last := len(b) - 1
|
||||
b[last] = ':'
|
||||
b = appendColon(b)
|
||||
} else {
|
||||
ptr := load(ctxptr, code.End.MapPos)
|
||||
mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(ptr))
|
||||
|
@ -503,12 +444,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
sort.Sort(mapCtx.Slice)
|
||||
buf := mapCtx.Buf
|
||||
for _, item := range mapCtx.Slice.Items {
|
||||
buf = append(buf, item.Key...)
|
||||
buf[len(buf)-1] = ':'
|
||||
buf = append(buf, item.Value...)
|
||||
buf = appendMapKeyValue(ctx, code, buf, item.Key, item.Value)
|
||||
}
|
||||
buf[len(buf)-1] = '}'
|
||||
buf = append(buf, ',')
|
||||
buf = appendMapEnd(ctx, code, buf)
|
||||
b = b[:pos[0]]
|
||||
b = append(b, buf...)
|
||||
mapCtx.Buf = buf
|
||||
|
@ -539,6 +477,8 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
offsetNum := ptrOffset / uintptrSize
|
||||
oldOffset := ptrOffset
|
||||
ptrOffset += code.Jmp.CurLen * uintptrSize
|
||||
oldBaseIndent := ctx.BaseIndent
|
||||
ctx.BaseIndent += code.Indent - 1
|
||||
|
||||
newLen := offsetNum + code.Jmp.CurLen + code.Jmp.NextLen
|
||||
if curlen < newLen {
|
||||
|
@ -549,12 +489,14 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
store(ctxptr, c.Idx, ptr)
|
||||
store(ctxptr, c.End.Next.Idx, oldOffset)
|
||||
store(ctxptr, c.End.Next.ElemIdx, uintptr(unsafe.Pointer(code.Next)))
|
||||
storeIndent(ctxptr, c, uintptr(oldBaseIndent))
|
||||
code = c
|
||||
recursiveLevel++
|
||||
case encoder.OpRecursiveEnd:
|
||||
recursiveLevel--
|
||||
|
||||
// restore ctxptr
|
||||
restoreIndent(ctx, code, ctxptr)
|
||||
offset := load(ctxptr, code.Idx)
|
||||
ctx.SeenPtr = ctx.SeenPtr[:len(ctx.SeenPtr)-1]
|
||||
|
||||
|
@ -587,7 +529,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
if !code.AnonymousHead {
|
||||
b = appendStructHead(b)
|
||||
}
|
||||
if !code.AnonymousKey {
|
||||
if !code.AnonymousKey && len(code.Key) > 0 {
|
||||
b = appendStructKey(ctx, code, b)
|
||||
}
|
||||
p += code.Offset
|
||||
|
@ -1883,8 +1825,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
b = appendStructHead(b)
|
||||
}
|
||||
b = appendStructKey(ctx, code, b)
|
||||
s := ptrToString(p + code.Offset)
|
||||
b = appendString(b, string(appendString([]byte{}, s)))
|
||||
b = appendString(b, string(appendString([]byte{}, ptrToString(p+code.Offset))))
|
||||
b = appendComma(b)
|
||||
code = code.Next
|
||||
case encoder.OpStructPtrHeadOmitEmptyStringString:
|
||||
|
@ -2404,11 +2345,11 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
b = appendStructHead(b)
|
||||
}
|
||||
v := ptrToBytes(p + code.Offset)
|
||||
if v == nil {
|
||||
if len(v) == 0 {
|
||||
code = code.NextField
|
||||
} else {
|
||||
b = appendStructKey(ctx, code, b)
|
||||
b = appendByteSlice(b, ptrToBytes(p))
|
||||
b = appendByteSlice(b, v)
|
||||
b = appendComma(b)
|
||||
code = code.Next
|
||||
}
|
||||
|
@ -3500,9 +3441,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
}
|
||||
code = code.Next
|
||||
case encoder.OpStructFieldIntPtr:
|
||||
b = appendStructKey(ctx, code, b)
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
p = ptrToNPtr(p+code.Offset, code.PtrNum)
|
||||
b = appendStructKey(ctx, code, b)
|
||||
if p == 0 {
|
||||
b = appendNull(b)
|
||||
} else {
|
||||
|
@ -3580,9 +3521,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
}
|
||||
code = code.Next
|
||||
case encoder.OpStructFieldUintPtr:
|
||||
b = appendStructKey(ctx, code, b)
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
p = ptrToNPtr(p+code.Offset, code.PtrNum)
|
||||
b = appendStructKey(ctx, code, b)
|
||||
if p == 0 {
|
||||
b = appendNull(b)
|
||||
} else {
|
||||
|
@ -3658,9 +3599,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
}
|
||||
code = code.Next
|
||||
case encoder.OpStructFieldFloat32Ptr:
|
||||
b = appendStructKey(ctx, code, b)
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
p = ptrToNPtr(p+code.Offset, code.PtrNum)
|
||||
b = appendStructKey(ctx, code, b)
|
||||
if p == 0 {
|
||||
b = appendNull(b)
|
||||
} else {
|
||||
|
@ -3750,9 +3691,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
}
|
||||
code = code.Next
|
||||
case encoder.OpStructFieldFloat64Ptr:
|
||||
b = appendStructKey(ctx, code, b)
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
p = ptrToNPtr(p+code.Offset, code.PtrNum)
|
||||
b = appendStructKey(ctx, code, b)
|
||||
if p == 0 {
|
||||
b = appendNull(b)
|
||||
b = appendComma(b)
|
||||
|
@ -3828,8 +3769,8 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
code = code.Next
|
||||
case encoder.OpStructFieldStringString:
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
b = appendStructKey(ctx, code, b)
|
||||
s := ptrToString(p + code.Offset)
|
||||
b = appendStructKey(ctx, code, b)
|
||||
b = appendString(b, string(appendString([]byte{}, s)))
|
||||
b = appendComma(b)
|
||||
code = code.Next
|
||||
|
@ -3843,9 +3784,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
}
|
||||
code = code.Next
|
||||
case encoder.OpStructFieldStringPtr:
|
||||
b = appendStructKey(ctx, code, b)
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
p = ptrToNPtr(p+code.Offset, code.PtrNum)
|
||||
b = appendStructKey(ctx, code, b)
|
||||
if p == 0 {
|
||||
b = appendNull(b)
|
||||
} else {
|
||||
|
@ -3863,9 +3804,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
}
|
||||
code = code.Next
|
||||
case encoder.OpStructFieldStringPtrString:
|
||||
b = appendStructKey(ctx, code, b)
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
p = ptrToNPtr(p+code.Offset, code.PtrNum)
|
||||
b = appendStructKey(ctx, code, b)
|
||||
if p == 0 {
|
||||
b = appendNull(b)
|
||||
} else {
|
||||
|
@ -3917,9 +3858,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
}
|
||||
code = code.Next
|
||||
case encoder.OpStructFieldBoolPtr:
|
||||
b = appendStructKey(ctx, code, b)
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
p = ptrToNPtr(p+code.Offset, code.PtrNum)
|
||||
b = appendStructKey(ctx, code, b)
|
||||
if p == 0 {
|
||||
b = appendNull(b)
|
||||
} else {
|
||||
|
@ -3937,9 +3878,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
}
|
||||
code = code.Next
|
||||
case encoder.OpStructFieldBoolPtrString:
|
||||
b = appendStructKey(ctx, code, b)
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
p = ptrToNPtr(p+code.Offset, code.PtrNum)
|
||||
b = appendStructKey(ctx, code, b)
|
||||
if p == 0 {
|
||||
b = appendNull(b)
|
||||
} else {
|
||||
|
@ -3976,9 +3917,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
}
|
||||
code = code.Next
|
||||
case encoder.OpStructFieldBytesPtr:
|
||||
b = appendStructKey(ctx, code, b)
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
p = ptrToNPtr(p+code.Offset, code.PtrNum)
|
||||
b = appendStructKey(ctx, code, b)
|
||||
if p == 0 {
|
||||
b = appendNull(b)
|
||||
} else {
|
||||
|
@ -4042,9 +3983,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
}
|
||||
code = code.Next
|
||||
case encoder.OpStructFieldNumberPtr:
|
||||
b = appendStructKey(ctx, code, b)
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
p = ptrToNPtr(p+code.Offset, code.PtrNum)
|
||||
b = appendStructKey(ctx, code, b)
|
||||
if p == 0 {
|
||||
b = appendNull(b)
|
||||
} else {
|
||||
|
@ -4069,9 +4010,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
}
|
||||
code = code.Next
|
||||
case encoder.OpStructFieldNumberPtrString:
|
||||
b = appendStructKey(ctx, code, b)
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
p = ptrToNPtr(p+code.Offset, code.PtrNum)
|
||||
b = appendStructKey(ctx, code, b)
|
||||
if p == 0 {
|
||||
b = appendNull(b)
|
||||
} else {
|
||||
|
@ -4234,9 +4175,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
code = code.Next
|
||||
store(ctxptr, code.Idx, p)
|
||||
case encoder.OpStructFieldOmitEmptyArray:
|
||||
b = appendStructKey(ctx, code, b)
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
p += code.Offset
|
||||
b = appendStructKey(ctx, code, b)
|
||||
code = code.Next
|
||||
store(ctxptr, code.Idx, p)
|
||||
case encoder.OpStructFieldArrayPtr:
|
||||
|
@ -4332,17 +4273,21 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
p += code.Offset
|
||||
code = code.Next
|
||||
store(ctxptr, code.Idx, p)
|
||||
case encoder.OpStructEnd:
|
||||
last := len(b) - 1
|
||||
if b[last] == ',' {
|
||||
b[last] = '}'
|
||||
case encoder.OpStructFieldOmitEmptyStruct:
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
p += code.Offset
|
||||
if ptrToPtr(p) == 0 && code.IsNextOpPtrType {
|
||||
code = code.NextField
|
||||
} else {
|
||||
b = append(b, '}')
|
||||
b = appendStructKey(ctx, code, b)
|
||||
code = code.Next
|
||||
store(ctxptr, code.Idx, p)
|
||||
}
|
||||
b = appendComma(b)
|
||||
code = code.Next
|
||||
case encoder.OpStructAnonymousEnd:
|
||||
code = code.Next
|
||||
case encoder.OpStructEnd:
|
||||
b = appendStructEndSkipLast(ctx, code, b)
|
||||
code = code.Next
|
||||
case encoder.OpStructEndInt:
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
b = appendStructKey(ctx, code, b)
|
||||
|
@ -4607,11 +4552,11 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
code = code.Next
|
||||
case encoder.OpStructEndFloat64:
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
b = appendStructKey(ctx, code, b)
|
||||
v := ptrToFloat64(p + code.Offset)
|
||||
if math.IsInf(v, 0) || math.IsNaN(v) {
|
||||
return nil, errUnsupportedFloat(v)
|
||||
}
|
||||
b = appendStructKey(ctx, code, b)
|
||||
b = appendFloat64(b, v)
|
||||
b = appendStructEnd(ctx, code, b)
|
||||
code = code.Next
|
||||
|
@ -4787,8 +4732,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
if p == 0 {
|
||||
b = appendNull(b)
|
||||
} else {
|
||||
v := ptrToString(p)
|
||||
b = appendString(b, string(appendString([]byte{}, v)))
|
||||
b = appendString(b, string(appendString([]byte{}, ptrToString(p))))
|
||||
}
|
||||
b = appendStructEnd(ctx, code, b)
|
||||
code = code.Next
|
||||
|
@ -4797,8 +4741,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
p = ptrToNPtr(p+code.Offset, code.PtrNum)
|
||||
if p != 0 {
|
||||
b = appendStructKey(ctx, code, b)
|
||||
v := ptrToString(p)
|
||||
b = appendString(b, string(appendString([]byte{}, v)))
|
||||
b = appendString(b, string(appendString([]byte{}, ptrToString(p))))
|
||||
b = appendStructEnd(ctx, code, b)
|
||||
} else {
|
||||
b = appendStructEndSkipLast(ctx, code, b)
|
||||
|
|
|
@ -2,12 +2,41 @@ package vm_debug
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"unsafe"
|
||||
|
||||
"github.com/goccy/go-json/internal/encoder"
|
||||
"github.com/goccy/go-json/internal/runtime"
|
||||
)
|
||||
|
||||
const uintptrSize = 4 << (^uintptr(0) >> 63)
|
||||
|
||||
var (
|
||||
appendInt = encoder.AppendInt
|
||||
appendUint = encoder.AppendUint
|
||||
appendFloat32 = encoder.AppendFloat32
|
||||
appendFloat64 = encoder.AppendFloat64
|
||||
appendString = encoder.AppendString
|
||||
appendByteSlice = encoder.AppendByteSlice
|
||||
appendNumber = encoder.AppendNumber
|
||||
errUnsupportedValue = encoder.ErrUnsupportedValue
|
||||
errUnsupportedFloat = encoder.ErrUnsupportedFloat
|
||||
mapiterinit = encoder.MapIterInit
|
||||
mapiterkey = encoder.MapIterKey
|
||||
mapitervalue = encoder.MapIterValue
|
||||
mapiternext = encoder.MapIterNext
|
||||
maplen = encoder.MapLen
|
||||
)
|
||||
|
||||
type emptyInterface struct {
|
||||
typ *runtime.Type
|
||||
ptr unsafe.Pointer
|
||||
}
|
||||
|
||||
func errUnimplementedOp(op encoder.OpType) error {
|
||||
return fmt.Errorf("encoder (debug): opcode %s has not been implemented", op)
|
||||
}
|
||||
|
||||
func load(base uintptr, idx uintptr) uintptr {
|
||||
addr := base + idx
|
||||
return **(**uintptr)(unsafe.Pointer(&addr))
|
||||
|
@ -76,6 +105,57 @@ func appendComma(b []byte) []byte {
|
|||
return append(b, ',')
|
||||
}
|
||||
|
||||
func appendColon(b []byte) []byte {
|
||||
last := len(b) - 1
|
||||
b[last] = ':'
|
||||
return b
|
||||
}
|
||||
|
||||
func appendMapKeyValue(ctx *encoder.RuntimeContext, code *encoder.Opcode, b, key, value []byte) []byte {
|
||||
b = append(b, key...)
|
||||
b[len(b)-1] = ':'
|
||||
return append(b, value...)
|
||||
}
|
||||
|
||||
func appendMapEnd(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
|
||||
b[len(b)-1] = '}'
|
||||
b = append(b, ',')
|
||||
return b
|
||||
}
|
||||
|
||||
func appendInterface(ctx *encoder.RuntimeContext, codeSet *encoder.OpcodeSet, opt encoder.Option, code *encoder.Opcode, b []byte, iface *emptyInterface, ptrOffset uintptr) ([]byte, error) {
|
||||
ctx.KeepRefs = append(ctx.KeepRefs, unsafe.Pointer(iface))
|
||||
ifaceCodeSet, err := encoder.CompileToGetCodeSet(uintptr(unsafe.Pointer(iface.typ)))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
totalLength := uintptr(codeSet.CodeLength)
|
||||
nextTotalLength := uintptr(ifaceCodeSet.CodeLength)
|
||||
|
||||
curlen := uintptr(len(ctx.Ptrs))
|
||||
offsetNum := ptrOffset / uintptrSize
|
||||
|
||||
newLen := offsetNum + totalLength + nextTotalLength
|
||||
if curlen < newLen {
|
||||
ctx.Ptrs = append(ctx.Ptrs, make([]uintptr, newLen-curlen)...)
|
||||
}
|
||||
oldPtrs := ctx.Ptrs
|
||||
|
||||
newPtrs := ctx.Ptrs[(ptrOffset+totalLength*uintptrSize)/uintptrSize:]
|
||||
newPtrs[0] = uintptr(iface.ptr)
|
||||
|
||||
ctx.Ptrs = newPtrs
|
||||
|
||||
bb, err := Run(ctx, b, ifaceCodeSet, opt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ctx.Ptrs = oldPtrs
|
||||
return bb, nil
|
||||
}
|
||||
|
||||
func appendMarshalJSON(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte, v interface{}) ([]byte, error) {
|
||||
return encoder.AppendMarshalJSON(ctx, code, b, v, false)
|
||||
}
|
||||
|
@ -84,14 +164,38 @@ func appendMarshalText(code *encoder.Opcode, b []byte, v interface{}) ([]byte, e
|
|||
return encoder.AppendMarshalText(code, b, v, false)
|
||||
}
|
||||
|
||||
func appendStructKey(_ *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
|
||||
return append(b, code.Key...)
|
||||
func appendArrayHead(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte {
|
||||
return append(b, '[')
|
||||
}
|
||||
|
||||
func appendArrayEnd(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
|
||||
last := len(b) - 1
|
||||
b[last] = ']'
|
||||
return append(b, ',')
|
||||
}
|
||||
|
||||
func appendEmptyArray(b []byte) []byte {
|
||||
return append(b, '[', ']', ',')
|
||||
}
|
||||
|
||||
func appendEmptyObject(b []byte) []byte {
|
||||
return append(b, '{', '}', ',')
|
||||
}
|
||||
|
||||
func appendObjectEnd(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte {
|
||||
last := len(b) - 1
|
||||
b[last] = '}'
|
||||
return append(b, ',')
|
||||
}
|
||||
|
||||
func appendStructHead(b []byte) []byte {
|
||||
return append(b, '{')
|
||||
}
|
||||
|
||||
func appendStructKey(_ *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
|
||||
return append(b, code.Key...)
|
||||
}
|
||||
|
||||
func appendStructEnd(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte {
|
||||
return append(b, '}', ',')
|
||||
}
|
||||
|
@ -104,3 +208,8 @@ func appendStructEndSkipLast(ctx *encoder.RuntimeContext, code *encoder.Opcode,
|
|||
}
|
||||
return appendStructEnd(ctx, code, b)
|
||||
}
|
||||
|
||||
func restoreIndent(ctx *encoder.RuntimeContext, code *encoder.Opcode, ctxptr uintptr) {}
|
||||
func storeIndent(ctxptr uintptr, code *encoder.Opcode, indent uintptr) {}
|
||||
func appendMapKeyIndent(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte { return b }
|
||||
func appendArrayElemIndent(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte { return b }
|
||||
|
|
|
@ -7,33 +7,8 @@ import (
|
|||
"unsafe"
|
||||
|
||||
"github.com/goccy/go-json/internal/encoder"
|
||||
"github.com/goccy/go-json/internal/runtime"
|
||||
)
|
||||
|
||||
const uintptrSize = 4 << (^uintptr(0) >> 63)
|
||||
|
||||
var (
|
||||
appendInt = encoder.AppendInt
|
||||
appendUint = encoder.AppendUint
|
||||
appendFloat32 = encoder.AppendFloat32
|
||||
appendFloat64 = encoder.AppendFloat64
|
||||
appendString = encoder.AppendString
|
||||
appendByteSlice = encoder.AppendByteSlice
|
||||
appendNumber = encoder.AppendNumber
|
||||
errUnsupportedValue = encoder.ErrUnsupportedValue
|
||||
errUnsupportedFloat = encoder.ErrUnsupportedFloat
|
||||
mapiterinit = encoder.MapIterInit
|
||||
mapiterkey = encoder.MapIterKey
|
||||
mapitervalue = encoder.MapIterValue
|
||||
mapiternext = encoder.MapIterNext
|
||||
maplen = encoder.MapLen
|
||||
)
|
||||
|
||||
type emptyInterface struct {
|
||||
typ *runtime.Type
|
||||
ptr unsafe.Pointer
|
||||
}
|
||||
|
||||
func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt encoder.Option) ([]byte, error) {
|
||||
recursiveLevel := 0
|
||||
ptrOffset := uintptr(0)
|
||||
|
@ -62,7 +37,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
for {
|
||||
switch code.Op {
|
||||
default:
|
||||
return nil, fmt.Errorf("encoder: opcode %s has not been implemented", code.Op)
|
||||
return nil, errUnimplementedOp(code.Op)
|
||||
case encoder.OpPtr:
|
||||
p := load(ctxptr, code.Idx)
|
||||
code = code.Next
|
||||
|
@ -134,7 +109,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
case encoder.OpFloat64:
|
||||
v := ptrToFloat64(load(ctxptr, code.Idx))
|
||||
if math.IsInf(v, 0) || math.IsNaN(v) {
|
||||
return nil, encoder.ErrUnsupportedFloat(v)
|
||||
return nil, errUnsupportedFloat(v)
|
||||
}
|
||||
b = appendFloat64(b, v)
|
||||
b = appendComma(b)
|
||||
|
@ -229,35 +204,10 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
code = code.Next
|
||||
break
|
||||
}
|
||||
ctx.KeepRefs = append(ctx.KeepRefs, unsafe.Pointer(iface))
|
||||
ifaceCodeSet, err := encoder.CompileToGetCodeSet(uintptr(unsafe.Pointer(iface.typ)))
|
||||
bb, err := appendInterface(ctx, codeSet, opt, code, b, iface, ptrOffset)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
totalLength := uintptr(codeSet.CodeLength)
|
||||
nextTotalLength := uintptr(ifaceCodeSet.CodeLength)
|
||||
|
||||
curlen := uintptr(len(ctx.Ptrs))
|
||||
offsetNum := ptrOffset / uintptrSize
|
||||
|
||||
newLen := offsetNum + totalLength + nextTotalLength
|
||||
if curlen < newLen {
|
||||
ctx.Ptrs = append(ctx.Ptrs, make([]uintptr, newLen-curlen)...)
|
||||
}
|
||||
oldPtrs := ctx.Ptrs
|
||||
|
||||
newPtrs := ctx.Ptrs[(ptrOffset+totalLength*uintptrSize)/uintptrSize:]
|
||||
newPtrs[0] = uintptr(iface.ptr)
|
||||
|
||||
ctx.Ptrs = newPtrs
|
||||
|
||||
bb, err := Run(ctx, b, ifaceCodeSet, opt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ctx.Ptrs = oldPtrs
|
||||
ctxptr = ctx.Ptr()
|
||||
ctx.SeenPtr = ctx.SeenPtr[:len(ctx.SeenPtr)-1]
|
||||
|
||||
|
@ -340,11 +290,11 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
store(ctxptr, code.Length, uintptr(slice.Len))
|
||||
store(ctxptr, code.Idx, uintptr(slice.Data))
|
||||
if slice.Len > 0 {
|
||||
b = append(b, '[')
|
||||
b = appendArrayHead(ctx, code, b)
|
||||
code = code.Next
|
||||
store(ctxptr, code.Idx, uintptr(slice.Data))
|
||||
} else {
|
||||
b = append(b, '[', ']', ',')
|
||||
b = appendEmptyArray(b)
|
||||
code = code.End.Next
|
||||
}
|
||||
case encoder.OpSliceElem:
|
||||
|
@ -352,15 +302,14 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
length := load(ctxptr, code.Length)
|
||||
idx++
|
||||
if idx < length {
|
||||
b = appendArrayElemIndent(ctx, code, b)
|
||||
store(ctxptr, code.ElemIdx, idx)
|
||||
data := load(ctxptr, code.HeadIdx)
|
||||
size := code.Size
|
||||
code = code.Next
|
||||
store(ctxptr, code.Idx, data+idx*size)
|
||||
} else {
|
||||
last := len(b) - 1
|
||||
b[last] = ']'
|
||||
b = appendComma(b)
|
||||
b = appendArrayEnd(ctx, code, b)
|
||||
code = code.End.Next
|
||||
}
|
||||
case encoder.OpArrayPtr:
|
||||
|
@ -382,27 +331,26 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
break
|
||||
}
|
||||
if code.Length > 0 {
|
||||
b = append(b, '[')
|
||||
b = appendArrayHead(ctx, code, b)
|
||||
store(ctxptr, code.ElemIdx, 0)
|
||||
code = code.Next
|
||||
store(ctxptr, code.Idx, p)
|
||||
} else {
|
||||
b = append(b, '[', ']', ',')
|
||||
b = appendEmptyArray(b)
|
||||
code = code.End.Next
|
||||
}
|
||||
case encoder.OpArrayElem:
|
||||
idx := load(ctxptr, code.ElemIdx)
|
||||
idx++
|
||||
if idx < code.Length {
|
||||
b = appendArrayElemIndent(ctx, code, b)
|
||||
store(ctxptr, code.ElemIdx, idx)
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
size := code.Size
|
||||
code = code.Next
|
||||
store(ctxptr, code.Idx, p+idx*size)
|
||||
} else {
|
||||
last := len(b) - 1
|
||||
b[last] = ']'
|
||||
b = appendComma(b)
|
||||
b = appendArrayEnd(ctx, code, b)
|
||||
code = code.End.Next
|
||||
}
|
||||
case encoder.OpMapPtr:
|
||||
|
@ -426,11 +374,11 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
uptr := ptrToUnsafePtr(p)
|
||||
mlen := maplen(uptr)
|
||||
if mlen <= 0 {
|
||||
b = append(b, '{', '}', ',')
|
||||
b = appendEmptyObject(b)
|
||||
code = code.End.Next
|
||||
break
|
||||
}
|
||||
b = append(b, '{')
|
||||
b = appendStructHead(b)
|
||||
iter := mapiterinit(code.Type, uptr)
|
||||
ctx.KeepRefs = append(ctx.KeepRefs, iter)
|
||||
store(ctxptr, code.ElemIdx, 0)
|
||||
|
@ -441,6 +389,8 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
mapCtx.Pos = append(mapCtx.Pos, len(b))
|
||||
ctx.KeepRefs = append(ctx.KeepRefs, unsafe.Pointer(mapCtx))
|
||||
store(ctxptr, code.End.MapPos, uintptr(unsafe.Pointer(mapCtx)))
|
||||
} else {
|
||||
b = appendMapKeyIndent(ctx, code.Next, b)
|
||||
}
|
||||
key := mapiterkey(iter)
|
||||
store(ctxptr, code.Next.Idx, uintptr(key))
|
||||
|
@ -451,16 +401,15 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
idx++
|
||||
if (opt & encoder.UnorderedMapOption) != 0 {
|
||||
if idx < length {
|
||||
b = appendMapKeyIndent(ctx, code, b)
|
||||
store(ctxptr, code.ElemIdx, idx)
|
||||
ptr := load(ctxptr, code.MapIter)
|
||||
iter := ptrToUnsafePtr(ptr)
|
||||
store(ctxptr, code.ElemIdx, idx)
|
||||
key := mapiterkey(iter)
|
||||
store(ctxptr, code.Next.Idx, uintptr(key))
|
||||
code = code.Next
|
||||
} else {
|
||||
last := len(b) - 1
|
||||
b[last] = '}'
|
||||
b = appendComma(b)
|
||||
b = appendObjectEnd(ctx, code, b)
|
||||
code = code.End.Next
|
||||
}
|
||||
} else {
|
||||
|
@ -480,8 +429,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
}
|
||||
case encoder.OpMapValue:
|
||||
if (opt & encoder.UnorderedMapOption) != 0 {
|
||||
last := len(b) - 1
|
||||
b[last] = ':'
|
||||
b = appendColon(b)
|
||||
} else {
|
||||
ptr := load(ctxptr, code.End.MapPos)
|
||||
mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(ptr))
|
||||
|
@ -516,12 +464,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
sort.Sort(mapCtx.Slice)
|
||||
buf := mapCtx.Buf
|
||||
for _, item := range mapCtx.Slice.Items {
|
||||
buf = append(buf, item.Key...)
|
||||
buf[len(buf)-1] = ':'
|
||||
buf = append(buf, item.Value...)
|
||||
buf = appendMapKeyValue(ctx, code, buf, item.Key, item.Value)
|
||||
}
|
||||
buf[len(buf)-1] = '}'
|
||||
buf = append(buf, ',')
|
||||
buf = appendMapEnd(ctx, code, buf)
|
||||
b = b[:pos[0]]
|
||||
b = append(b, buf...)
|
||||
mapCtx.Buf = buf
|
||||
|
@ -552,6 +497,8 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
offsetNum := ptrOffset / uintptrSize
|
||||
oldOffset := ptrOffset
|
||||
ptrOffset += code.Jmp.CurLen * uintptrSize
|
||||
oldBaseIndent := ctx.BaseIndent
|
||||
ctx.BaseIndent += code.Indent - 1
|
||||
|
||||
newLen := offsetNum + code.Jmp.CurLen + code.Jmp.NextLen
|
||||
if curlen < newLen {
|
||||
|
@ -562,12 +509,14 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
store(ctxptr, c.Idx, ptr)
|
||||
store(ctxptr, c.End.Next.Idx, oldOffset)
|
||||
store(ctxptr, c.End.Next.ElemIdx, uintptr(unsafe.Pointer(code.Next)))
|
||||
storeIndent(ctxptr, c, uintptr(oldBaseIndent))
|
||||
code = c
|
||||
recursiveLevel++
|
||||
case encoder.OpRecursiveEnd:
|
||||
recursiveLevel--
|
||||
|
||||
// restore ctxptr
|
||||
restoreIndent(ctx, code, ctxptr)
|
||||
offset := load(ctxptr, code.Idx)
|
||||
ctx.SeenPtr = ctx.SeenPtr[:len(ctx.SeenPtr)-1]
|
||||
|
||||
|
@ -600,7 +549,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
if !code.AnonymousHead {
|
||||
b = appendStructHead(b)
|
||||
}
|
||||
if !code.AnonymousKey {
|
||||
if !code.AnonymousKey && len(code.Key) > 0 {
|
||||
b = appendStructKey(ctx, code, b)
|
||||
}
|
||||
p += code.Offset
|
||||
|
@ -1896,8 +1845,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
b = appendStructHead(b)
|
||||
}
|
||||
b = appendStructKey(ctx, code, b)
|
||||
s := ptrToString(p + code.Offset)
|
||||
b = appendString(b, string(appendString([]byte{}, s)))
|
||||
b = appendString(b, string(appendString([]byte{}, ptrToString(p+code.Offset))))
|
||||
b = appendComma(b)
|
||||
code = code.Next
|
||||
case encoder.OpStructPtrHeadOmitEmptyStringString:
|
||||
|
@ -2417,11 +2365,11 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
b = appendStructHead(b)
|
||||
}
|
||||
v := ptrToBytes(p + code.Offset)
|
||||
if v == nil {
|
||||
if len(v) == 0 {
|
||||
code = code.NextField
|
||||
} else {
|
||||
b = appendStructKey(ctx, code, b)
|
||||
b = appendByteSlice(b, ptrToBytes(p))
|
||||
b = appendByteSlice(b, v)
|
||||
b = appendComma(b)
|
||||
code = code.Next
|
||||
}
|
||||
|
@ -3513,9 +3461,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
}
|
||||
code = code.Next
|
||||
case encoder.OpStructFieldIntPtr:
|
||||
b = appendStructKey(ctx, code, b)
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
p = ptrToNPtr(p+code.Offset, code.PtrNum)
|
||||
b = appendStructKey(ctx, code, b)
|
||||
if p == 0 {
|
||||
b = appendNull(b)
|
||||
} else {
|
||||
|
@ -3593,9 +3541,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
}
|
||||
code = code.Next
|
||||
case encoder.OpStructFieldUintPtr:
|
||||
b = appendStructKey(ctx, code, b)
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
p = ptrToNPtr(p+code.Offset, code.PtrNum)
|
||||
b = appendStructKey(ctx, code, b)
|
||||
if p == 0 {
|
||||
b = appendNull(b)
|
||||
} else {
|
||||
|
@ -3671,9 +3619,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
}
|
||||
code = code.Next
|
||||
case encoder.OpStructFieldFloat32Ptr:
|
||||
b = appendStructKey(ctx, code, b)
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
p = ptrToNPtr(p+code.Offset, code.PtrNum)
|
||||
b = appendStructKey(ctx, code, b)
|
||||
if p == 0 {
|
||||
b = appendNull(b)
|
||||
} else {
|
||||
|
@ -3763,9 +3711,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
}
|
||||
code = code.Next
|
||||
case encoder.OpStructFieldFloat64Ptr:
|
||||
b = appendStructKey(ctx, code, b)
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
p = ptrToNPtr(p+code.Offset, code.PtrNum)
|
||||
b = appendStructKey(ctx, code, b)
|
||||
if p == 0 {
|
||||
b = appendNull(b)
|
||||
b = appendComma(b)
|
||||
|
@ -3841,8 +3789,8 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
code = code.Next
|
||||
case encoder.OpStructFieldStringString:
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
b = appendStructKey(ctx, code, b)
|
||||
s := ptrToString(p + code.Offset)
|
||||
b = appendStructKey(ctx, code, b)
|
||||
b = appendString(b, string(appendString([]byte{}, s)))
|
||||
b = appendComma(b)
|
||||
code = code.Next
|
||||
|
@ -3856,9 +3804,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
}
|
||||
code = code.Next
|
||||
case encoder.OpStructFieldStringPtr:
|
||||
b = appendStructKey(ctx, code, b)
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
p = ptrToNPtr(p+code.Offset, code.PtrNum)
|
||||
b = appendStructKey(ctx, code, b)
|
||||
if p == 0 {
|
||||
b = appendNull(b)
|
||||
} else {
|
||||
|
@ -3876,9 +3824,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
}
|
||||
code = code.Next
|
||||
case encoder.OpStructFieldStringPtrString:
|
||||
b = appendStructKey(ctx, code, b)
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
p = ptrToNPtr(p+code.Offset, code.PtrNum)
|
||||
b = appendStructKey(ctx, code, b)
|
||||
if p == 0 {
|
||||
b = appendNull(b)
|
||||
} else {
|
||||
|
@ -3930,9 +3878,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
}
|
||||
code = code.Next
|
||||
case encoder.OpStructFieldBoolPtr:
|
||||
b = appendStructKey(ctx, code, b)
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
p = ptrToNPtr(p+code.Offset, code.PtrNum)
|
||||
b = appendStructKey(ctx, code, b)
|
||||
if p == 0 {
|
||||
b = appendNull(b)
|
||||
} else {
|
||||
|
@ -3950,9 +3898,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
}
|
||||
code = code.Next
|
||||
case encoder.OpStructFieldBoolPtrString:
|
||||
b = appendStructKey(ctx, code, b)
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
p = ptrToNPtr(p+code.Offset, code.PtrNum)
|
||||
b = appendStructKey(ctx, code, b)
|
||||
if p == 0 {
|
||||
b = appendNull(b)
|
||||
} else {
|
||||
|
@ -3989,9 +3937,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
}
|
||||
code = code.Next
|
||||
case encoder.OpStructFieldBytesPtr:
|
||||
b = appendStructKey(ctx, code, b)
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
p = ptrToNPtr(p+code.Offset, code.PtrNum)
|
||||
b = appendStructKey(ctx, code, b)
|
||||
if p == 0 {
|
||||
b = appendNull(b)
|
||||
} else {
|
||||
|
@ -4055,9 +4003,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
}
|
||||
code = code.Next
|
||||
case encoder.OpStructFieldNumberPtr:
|
||||
b = appendStructKey(ctx, code, b)
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
p = ptrToNPtr(p+code.Offset, code.PtrNum)
|
||||
b = appendStructKey(ctx, code, b)
|
||||
if p == 0 {
|
||||
b = appendNull(b)
|
||||
} else {
|
||||
|
@ -4082,9 +4030,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
}
|
||||
code = code.Next
|
||||
case encoder.OpStructFieldNumberPtrString:
|
||||
b = appendStructKey(ctx, code, b)
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
p = ptrToNPtr(p+code.Offset, code.PtrNum)
|
||||
b = appendStructKey(ctx, code, b)
|
||||
if p == 0 {
|
||||
b = appendNull(b)
|
||||
} else {
|
||||
|
@ -4247,9 +4195,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
code = code.Next
|
||||
store(ctxptr, code.Idx, p)
|
||||
case encoder.OpStructFieldOmitEmptyArray:
|
||||
b = appendStructKey(ctx, code, b)
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
p += code.Offset
|
||||
b = appendStructKey(ctx, code, b)
|
||||
code = code.Next
|
||||
store(ctxptr, code.Idx, p)
|
||||
case encoder.OpStructFieldArrayPtr:
|
||||
|
@ -4345,17 +4293,21 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
p += code.Offset
|
||||
code = code.Next
|
||||
store(ctxptr, code.Idx, p)
|
||||
case encoder.OpStructEnd:
|
||||
last := len(b) - 1
|
||||
if b[last] == ',' {
|
||||
b[last] = '}'
|
||||
case encoder.OpStructFieldOmitEmptyStruct:
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
p += code.Offset
|
||||
if ptrToPtr(p) == 0 && code.IsNextOpPtrType {
|
||||
code = code.NextField
|
||||
} else {
|
||||
b = append(b, '}')
|
||||
b = appendStructKey(ctx, code, b)
|
||||
code = code.Next
|
||||
store(ctxptr, code.Idx, p)
|
||||
}
|
||||
b = appendComma(b)
|
||||
code = code.Next
|
||||
case encoder.OpStructAnonymousEnd:
|
||||
code = code.Next
|
||||
case encoder.OpStructEnd:
|
||||
b = appendStructEndSkipLast(ctx, code, b)
|
||||
code = code.Next
|
||||
case encoder.OpStructEndInt:
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
b = appendStructKey(ctx, code, b)
|
||||
|
@ -4620,11 +4572,11 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
code = code.Next
|
||||
case encoder.OpStructEndFloat64:
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
b = appendStructKey(ctx, code, b)
|
||||
v := ptrToFloat64(p + code.Offset)
|
||||
if math.IsInf(v, 0) || math.IsNaN(v) {
|
||||
return nil, errUnsupportedFloat(v)
|
||||
}
|
||||
b = appendStructKey(ctx, code, b)
|
||||
b = appendFloat64(b, v)
|
||||
b = appendStructEnd(ctx, code, b)
|
||||
code = code.Next
|
||||
|
@ -4800,8 +4752,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
if p == 0 {
|
||||
b = appendNull(b)
|
||||
} else {
|
||||
v := ptrToString(p)
|
||||
b = appendString(b, string(appendString([]byte{}, v)))
|
||||
b = appendString(b, string(appendString([]byte{}, ptrToString(p))))
|
||||
}
|
||||
b = appendStructEnd(ctx, code, b)
|
||||
code = code.Next
|
||||
|
@ -4810,8 +4761,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
p = ptrToNPtr(p+code.Offset, code.PtrNum)
|
||||
if p != 0 {
|
||||
b = appendStructKey(ctx, code, b)
|
||||
v := ptrToString(p)
|
||||
b = appendString(b, string(appendString([]byte{}, v)))
|
||||
b = appendString(b, string(appendString([]byte{}, ptrToString(p))))
|
||||
b = appendStructEnd(ctx, code, b)
|
||||
} else {
|
||||
b = appendStructEndSkipLast(ctx, code, b)
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
package vm_escaped
|
||||
|
||||
import (
|
||||
// HACK: compile order
|
||||
// `vm`, `vm_escaped`, `vm_indent`, `vm_escaped_indent`, `vm_debug` packages uses a lot of memory to compile,
|
||||
// so forcibly make dependencies and avoid compiling in concurrent.
|
||||
// dependency order: vm => vm_escaped => vm_indent => vm_escaped_indent => vm_debug
|
||||
_ "github.com/goccy/go-json/internal/encoder/vm_indent"
|
||||
)
|
|
@ -2,12 +2,41 @@ package vm_escaped
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"unsafe"
|
||||
|
||||
"github.com/goccy/go-json/internal/encoder"
|
||||
"github.com/goccy/go-json/internal/runtime"
|
||||
)
|
||||
|
||||
const uintptrSize = 4 << (^uintptr(0) >> 63)
|
||||
|
||||
var (
|
||||
appendInt = encoder.AppendInt
|
||||
appendUint = encoder.AppendUint
|
||||
appendFloat32 = encoder.AppendFloat32
|
||||
appendFloat64 = encoder.AppendFloat64
|
||||
appendString = encoder.AppendEscapedString
|
||||
appendByteSlice = encoder.AppendByteSlice
|
||||
appendNumber = encoder.AppendNumber
|
||||
errUnsupportedValue = encoder.ErrUnsupportedValue
|
||||
errUnsupportedFloat = encoder.ErrUnsupportedFloat
|
||||
mapiterinit = encoder.MapIterInit
|
||||
mapiterkey = encoder.MapIterKey
|
||||
mapitervalue = encoder.MapIterValue
|
||||
mapiternext = encoder.MapIterNext
|
||||
maplen = encoder.MapLen
|
||||
)
|
||||
|
||||
type emptyInterface struct {
|
||||
typ *runtime.Type
|
||||
ptr unsafe.Pointer
|
||||
}
|
||||
|
||||
func errUnimplementedOp(op encoder.OpType) error {
|
||||
return fmt.Errorf("encoder (escaped): opcode %s has not been implemented", op)
|
||||
}
|
||||
|
||||
func load(base uintptr, idx uintptr) uintptr {
|
||||
addr := base + idx
|
||||
return **(**uintptr)(unsafe.Pointer(&addr))
|
||||
|
@ -76,6 +105,57 @@ func appendComma(b []byte) []byte {
|
|||
return append(b, ',')
|
||||
}
|
||||
|
||||
func appendColon(b []byte) []byte {
|
||||
last := len(b) - 1
|
||||
b[last] = ':'
|
||||
return b
|
||||
}
|
||||
|
||||
func appendMapKeyValue(ctx *encoder.RuntimeContext, code *encoder.Opcode, b, key, value []byte) []byte {
|
||||
b = append(b, key...)
|
||||
b[len(b)-1] = ':'
|
||||
return append(b, value...)
|
||||
}
|
||||
|
||||
func appendMapEnd(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
|
||||
b[len(b)-1] = '}'
|
||||
b = append(b, ',')
|
||||
return b
|
||||
}
|
||||
|
||||
func appendInterface(ctx *encoder.RuntimeContext, codeSet *encoder.OpcodeSet, opt encoder.Option, code *encoder.Opcode, b []byte, iface *emptyInterface, ptrOffset uintptr) ([]byte, error) {
|
||||
ctx.KeepRefs = append(ctx.KeepRefs, unsafe.Pointer(iface))
|
||||
ifaceCodeSet, err := encoder.CompileToGetCodeSet(uintptr(unsafe.Pointer(iface.typ)))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
totalLength := uintptr(codeSet.CodeLength)
|
||||
nextTotalLength := uintptr(ifaceCodeSet.CodeLength)
|
||||
|
||||
curlen := uintptr(len(ctx.Ptrs))
|
||||
offsetNum := ptrOffset / uintptrSize
|
||||
|
||||
newLen := offsetNum + totalLength + nextTotalLength
|
||||
if curlen < newLen {
|
||||
ctx.Ptrs = append(ctx.Ptrs, make([]uintptr, newLen-curlen)...)
|
||||
}
|
||||
oldPtrs := ctx.Ptrs
|
||||
|
||||
newPtrs := ctx.Ptrs[(ptrOffset+totalLength*uintptrSize)/uintptrSize:]
|
||||
newPtrs[0] = uintptr(iface.ptr)
|
||||
|
||||
ctx.Ptrs = newPtrs
|
||||
|
||||
bb, err := Run(ctx, b, ifaceCodeSet, opt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ctx.Ptrs = oldPtrs
|
||||
return bb, nil
|
||||
}
|
||||
|
||||
func appendMarshalJSON(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte, v interface{}) ([]byte, error) {
|
||||
return encoder.AppendMarshalJSON(ctx, code, b, v, true)
|
||||
}
|
||||
|
@ -84,6 +164,30 @@ func appendMarshalText(code *encoder.Opcode, b []byte, v interface{}) ([]byte, e
|
|||
return encoder.AppendMarshalText(code, b, v, true)
|
||||
}
|
||||
|
||||
func appendArrayHead(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte {
|
||||
return append(b, '[')
|
||||
}
|
||||
|
||||
func appendArrayEnd(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
|
||||
last := len(b) - 1
|
||||
b[last] = ']'
|
||||
return append(b, ',')
|
||||
}
|
||||
|
||||
func appendEmptyArray(b []byte) []byte {
|
||||
return append(b, '[', ']', ',')
|
||||
}
|
||||
|
||||
func appendEmptyObject(b []byte) []byte {
|
||||
return append(b, '{', '}', ',')
|
||||
}
|
||||
|
||||
func appendObjectEnd(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte {
|
||||
last := len(b) - 1
|
||||
b[last] = '}'
|
||||
return append(b, ',')
|
||||
}
|
||||
|
||||
func appendStructHead(b []byte) []byte {
|
||||
return append(b, '{')
|
||||
}
|
||||
|
@ -104,3 +208,8 @@ func appendStructEndSkipLast(ctx *encoder.RuntimeContext, code *encoder.Opcode,
|
|||
}
|
||||
return appendStructEnd(ctx, code, b)
|
||||
}
|
||||
|
||||
func restoreIndent(ctx *encoder.RuntimeContext, code *encoder.Opcode, ctxptr uintptr) {}
|
||||
func storeIndent(ctxptr uintptr, code *encoder.Opcode, indent uintptr) {}
|
||||
func appendMapKeyIndent(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte { return b }
|
||||
func appendArrayElemIndent(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte { return b }
|
||||
|
|
|
@ -1,45 +1,13 @@
|
|||
package vm_escaped
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"sort"
|
||||
"unsafe"
|
||||
|
||||
"github.com/goccy/go-json/internal/encoder"
|
||||
"github.com/goccy/go-json/internal/runtime"
|
||||
|
||||
// HACK: compile order
|
||||
// `vm`, `vm_escaped`, `vm_indent`, `vm_escaped_indent`, `vm_debug` packages uses a lot of memory to compile,
|
||||
// so forcibly make dependencies and avoid compiling in concurrent.
|
||||
// dependency order: vm => vm_escaped => vm_indent => vm_escaped_indent => vm_debug
|
||||
_ "github.com/goccy/go-json/internal/encoder/vm_indent"
|
||||
)
|
||||
|
||||
const uintptrSize = 4 << (^uintptr(0) >> 63)
|
||||
|
||||
var (
|
||||
appendInt = encoder.AppendInt
|
||||
appendUint = encoder.AppendUint
|
||||
appendFloat32 = encoder.AppendFloat32
|
||||
appendFloat64 = encoder.AppendFloat64
|
||||
appendString = encoder.AppendEscapedString
|
||||
appendByteSlice = encoder.AppendByteSlice
|
||||
appendNumber = encoder.AppendNumber
|
||||
errUnsupportedValue = encoder.ErrUnsupportedValue
|
||||
errUnsupportedFloat = encoder.ErrUnsupportedFloat
|
||||
mapiterinit = encoder.MapIterInit
|
||||
mapiterkey = encoder.MapIterKey
|
||||
mapitervalue = encoder.MapIterValue
|
||||
mapiternext = encoder.MapIterNext
|
||||
maplen = encoder.MapLen
|
||||
)
|
||||
|
||||
type emptyInterface struct {
|
||||
typ *runtime.Type
|
||||
ptr unsafe.Pointer
|
||||
}
|
||||
|
||||
func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt encoder.Option) ([]byte, error) {
|
||||
recursiveLevel := 0
|
||||
ptrOffset := uintptr(0)
|
||||
|
@ -49,7 +17,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
for {
|
||||
switch code.Op {
|
||||
default:
|
||||
return nil, fmt.Errorf("encoder: opcode %s has not been implemented", code.Op)
|
||||
return nil, errUnimplementedOp(code.Op)
|
||||
case encoder.OpPtr:
|
||||
p := load(ctxptr, code.Idx)
|
||||
code = code.Next
|
||||
|
@ -121,7 +89,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
case encoder.OpFloat64:
|
||||
v := ptrToFloat64(load(ctxptr, code.Idx))
|
||||
if math.IsInf(v, 0) || math.IsNaN(v) {
|
||||
return nil, encoder.ErrUnsupportedFloat(v)
|
||||
return nil, errUnsupportedFloat(v)
|
||||
}
|
||||
b = appendFloat64(b, v)
|
||||
b = appendComma(b)
|
||||
|
@ -216,35 +184,10 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
code = code.Next
|
||||
break
|
||||
}
|
||||
ctx.KeepRefs = append(ctx.KeepRefs, unsafe.Pointer(iface))
|
||||
ifaceCodeSet, err := encoder.CompileToGetCodeSet(uintptr(unsafe.Pointer(iface.typ)))
|
||||
bb, err := appendInterface(ctx, codeSet, opt, code, b, iface, ptrOffset)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
totalLength := uintptr(codeSet.CodeLength)
|
||||
nextTotalLength := uintptr(ifaceCodeSet.CodeLength)
|
||||
|
||||
curlen := uintptr(len(ctx.Ptrs))
|
||||
offsetNum := ptrOffset / uintptrSize
|
||||
|
||||
newLen := offsetNum + totalLength + nextTotalLength
|
||||
if curlen < newLen {
|
||||
ctx.Ptrs = append(ctx.Ptrs, make([]uintptr, newLen-curlen)...)
|
||||
}
|
||||
oldPtrs := ctx.Ptrs
|
||||
|
||||
newPtrs := ctx.Ptrs[(ptrOffset+totalLength*uintptrSize)/uintptrSize:]
|
||||
newPtrs[0] = uintptr(iface.ptr)
|
||||
|
||||
ctx.Ptrs = newPtrs
|
||||
|
||||
bb, err := Run(ctx, b, ifaceCodeSet, opt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ctx.Ptrs = oldPtrs
|
||||
ctxptr = ctx.Ptr()
|
||||
ctx.SeenPtr = ctx.SeenPtr[:len(ctx.SeenPtr)-1]
|
||||
|
||||
|
@ -327,11 +270,11 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
store(ctxptr, code.Length, uintptr(slice.Len))
|
||||
store(ctxptr, code.Idx, uintptr(slice.Data))
|
||||
if slice.Len > 0 {
|
||||
b = append(b, '[')
|
||||
b = appendArrayHead(ctx, code, b)
|
||||
code = code.Next
|
||||
store(ctxptr, code.Idx, uintptr(slice.Data))
|
||||
} else {
|
||||
b = append(b, '[', ']', ',')
|
||||
b = appendEmptyArray(b)
|
||||
code = code.End.Next
|
||||
}
|
||||
case encoder.OpSliceElem:
|
||||
|
@ -339,15 +282,14 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
length := load(ctxptr, code.Length)
|
||||
idx++
|
||||
if idx < length {
|
||||
b = appendArrayElemIndent(ctx, code, b)
|
||||
store(ctxptr, code.ElemIdx, idx)
|
||||
data := load(ctxptr, code.HeadIdx)
|
||||
size := code.Size
|
||||
code = code.Next
|
||||
store(ctxptr, code.Idx, data+idx*size)
|
||||
} else {
|
||||
last := len(b) - 1
|
||||
b[last] = ']'
|
||||
b = appendComma(b)
|
||||
b = appendArrayEnd(ctx, code, b)
|
||||
code = code.End.Next
|
||||
}
|
||||
case encoder.OpArrayPtr:
|
||||
|
@ -369,27 +311,26 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
break
|
||||
}
|
||||
if code.Length > 0 {
|
||||
b = append(b, '[')
|
||||
b = appendArrayHead(ctx, code, b)
|
||||
store(ctxptr, code.ElemIdx, 0)
|
||||
code = code.Next
|
||||
store(ctxptr, code.Idx, p)
|
||||
} else {
|
||||
b = append(b, '[', ']', ',')
|
||||
b = appendEmptyArray(b)
|
||||
code = code.End.Next
|
||||
}
|
||||
case encoder.OpArrayElem:
|
||||
idx := load(ctxptr, code.ElemIdx)
|
||||
idx++
|
||||
if idx < code.Length {
|
||||
b = appendArrayElemIndent(ctx, code, b)
|
||||
store(ctxptr, code.ElemIdx, idx)
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
size := code.Size
|
||||
code = code.Next
|
||||
store(ctxptr, code.Idx, p+idx*size)
|
||||
} else {
|
||||
last := len(b) - 1
|
||||
b[last] = ']'
|
||||
b = appendComma(b)
|
||||
b = appendArrayEnd(ctx, code, b)
|
||||
code = code.End.Next
|
||||
}
|
||||
case encoder.OpMapPtr:
|
||||
|
@ -413,11 +354,11 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
uptr := ptrToUnsafePtr(p)
|
||||
mlen := maplen(uptr)
|
||||
if mlen <= 0 {
|
||||
b = append(b, '{', '}', ',')
|
||||
b = appendEmptyObject(b)
|
||||
code = code.End.Next
|
||||
break
|
||||
}
|
||||
b = append(b, '{')
|
||||
b = appendStructHead(b)
|
||||
iter := mapiterinit(code.Type, uptr)
|
||||
ctx.KeepRefs = append(ctx.KeepRefs, iter)
|
||||
store(ctxptr, code.ElemIdx, 0)
|
||||
|
@ -428,6 +369,8 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
mapCtx.Pos = append(mapCtx.Pos, len(b))
|
||||
ctx.KeepRefs = append(ctx.KeepRefs, unsafe.Pointer(mapCtx))
|
||||
store(ctxptr, code.End.MapPos, uintptr(unsafe.Pointer(mapCtx)))
|
||||
} else {
|
||||
b = appendMapKeyIndent(ctx, code.Next, b)
|
||||
}
|
||||
key := mapiterkey(iter)
|
||||
store(ctxptr, code.Next.Idx, uintptr(key))
|
||||
|
@ -438,16 +381,15 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
idx++
|
||||
if (opt & encoder.UnorderedMapOption) != 0 {
|
||||
if idx < length {
|
||||
b = appendMapKeyIndent(ctx, code, b)
|
||||
store(ctxptr, code.ElemIdx, idx)
|
||||
ptr := load(ctxptr, code.MapIter)
|
||||
iter := ptrToUnsafePtr(ptr)
|
||||
store(ctxptr, code.ElemIdx, idx)
|
||||
key := mapiterkey(iter)
|
||||
store(ctxptr, code.Next.Idx, uintptr(key))
|
||||
code = code.Next
|
||||
} else {
|
||||
last := len(b) - 1
|
||||
b[last] = '}'
|
||||
b = appendComma(b)
|
||||
b = appendObjectEnd(ctx, code, b)
|
||||
code = code.End.Next
|
||||
}
|
||||
} else {
|
||||
|
@ -467,8 +409,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
}
|
||||
case encoder.OpMapValue:
|
||||
if (opt & encoder.UnorderedMapOption) != 0 {
|
||||
last := len(b) - 1
|
||||
b[last] = ':'
|
||||
b = appendColon(b)
|
||||
} else {
|
||||
ptr := load(ctxptr, code.End.MapPos)
|
||||
mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(ptr))
|
||||
|
@ -503,12 +444,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
sort.Sort(mapCtx.Slice)
|
||||
buf := mapCtx.Buf
|
||||
for _, item := range mapCtx.Slice.Items {
|
||||
buf = append(buf, item.Key...)
|
||||
buf[len(buf)-1] = ':'
|
||||
buf = append(buf, item.Value...)
|
||||
buf = appendMapKeyValue(ctx, code, buf, item.Key, item.Value)
|
||||
}
|
||||
buf[len(buf)-1] = '}'
|
||||
buf = append(buf, ',')
|
||||
buf = appendMapEnd(ctx, code, buf)
|
||||
b = b[:pos[0]]
|
||||
b = append(b, buf...)
|
||||
mapCtx.Buf = buf
|
||||
|
@ -539,6 +477,8 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
offsetNum := ptrOffset / uintptrSize
|
||||
oldOffset := ptrOffset
|
||||
ptrOffset += code.Jmp.CurLen * uintptrSize
|
||||
oldBaseIndent := ctx.BaseIndent
|
||||
ctx.BaseIndent += code.Indent - 1
|
||||
|
||||
newLen := offsetNum + code.Jmp.CurLen + code.Jmp.NextLen
|
||||
if curlen < newLen {
|
||||
|
@ -549,12 +489,14 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
store(ctxptr, c.Idx, ptr)
|
||||
store(ctxptr, c.End.Next.Idx, oldOffset)
|
||||
store(ctxptr, c.End.Next.ElemIdx, uintptr(unsafe.Pointer(code.Next)))
|
||||
storeIndent(ctxptr, c, uintptr(oldBaseIndent))
|
||||
code = c
|
||||
recursiveLevel++
|
||||
case encoder.OpRecursiveEnd:
|
||||
recursiveLevel--
|
||||
|
||||
// restore ctxptr
|
||||
restoreIndent(ctx, code, ctxptr)
|
||||
offset := load(ctxptr, code.Idx)
|
||||
ctx.SeenPtr = ctx.SeenPtr[:len(ctx.SeenPtr)-1]
|
||||
|
||||
|
@ -587,7 +529,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
if !code.AnonymousHead {
|
||||
b = appendStructHead(b)
|
||||
}
|
||||
if !code.AnonymousKey {
|
||||
if !code.AnonymousKey && len(code.Key) > 0 {
|
||||
b = appendStructKey(ctx, code, b)
|
||||
}
|
||||
p += code.Offset
|
||||
|
@ -1883,8 +1825,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
b = appendStructHead(b)
|
||||
}
|
||||
b = appendStructKey(ctx, code, b)
|
||||
s := ptrToString(p + code.Offset)
|
||||
b = appendString(b, string(appendString([]byte{}, s)))
|
||||
b = appendString(b, string(appendString([]byte{}, ptrToString(p+code.Offset))))
|
||||
b = appendComma(b)
|
||||
code = code.Next
|
||||
case encoder.OpStructPtrHeadOmitEmptyStringString:
|
||||
|
@ -2404,11 +2345,11 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
b = appendStructHead(b)
|
||||
}
|
||||
v := ptrToBytes(p + code.Offset)
|
||||
if v == nil {
|
||||
if len(v) == 0 {
|
||||
code = code.NextField
|
||||
} else {
|
||||
b = appendStructKey(ctx, code, b)
|
||||
b = appendByteSlice(b, ptrToBytes(p))
|
||||
b = appendByteSlice(b, v)
|
||||
b = appendComma(b)
|
||||
code = code.Next
|
||||
}
|
||||
|
@ -3500,9 +3441,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
}
|
||||
code = code.Next
|
||||
case encoder.OpStructFieldIntPtr:
|
||||
b = appendStructKey(ctx, code, b)
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
p = ptrToNPtr(p+code.Offset, code.PtrNum)
|
||||
b = appendStructKey(ctx, code, b)
|
||||
if p == 0 {
|
||||
b = appendNull(b)
|
||||
} else {
|
||||
|
@ -3580,9 +3521,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
}
|
||||
code = code.Next
|
||||
case encoder.OpStructFieldUintPtr:
|
||||
b = appendStructKey(ctx, code, b)
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
p = ptrToNPtr(p+code.Offset, code.PtrNum)
|
||||
b = appendStructKey(ctx, code, b)
|
||||
if p == 0 {
|
||||
b = appendNull(b)
|
||||
} else {
|
||||
|
@ -3658,9 +3599,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
}
|
||||
code = code.Next
|
||||
case encoder.OpStructFieldFloat32Ptr:
|
||||
b = appendStructKey(ctx, code, b)
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
p = ptrToNPtr(p+code.Offset, code.PtrNum)
|
||||
b = appendStructKey(ctx, code, b)
|
||||
if p == 0 {
|
||||
b = appendNull(b)
|
||||
} else {
|
||||
|
@ -3750,9 +3691,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
}
|
||||
code = code.Next
|
||||
case encoder.OpStructFieldFloat64Ptr:
|
||||
b = appendStructKey(ctx, code, b)
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
p = ptrToNPtr(p+code.Offset, code.PtrNum)
|
||||
b = appendStructKey(ctx, code, b)
|
||||
if p == 0 {
|
||||
b = appendNull(b)
|
||||
b = appendComma(b)
|
||||
|
@ -3828,8 +3769,8 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
code = code.Next
|
||||
case encoder.OpStructFieldStringString:
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
b = appendStructKey(ctx, code, b)
|
||||
s := ptrToString(p + code.Offset)
|
||||
b = appendStructKey(ctx, code, b)
|
||||
b = appendString(b, string(appendString([]byte{}, s)))
|
||||
b = appendComma(b)
|
||||
code = code.Next
|
||||
|
@ -3843,9 +3784,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
}
|
||||
code = code.Next
|
||||
case encoder.OpStructFieldStringPtr:
|
||||
b = appendStructKey(ctx, code, b)
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
p = ptrToNPtr(p+code.Offset, code.PtrNum)
|
||||
b = appendStructKey(ctx, code, b)
|
||||
if p == 0 {
|
||||
b = appendNull(b)
|
||||
} else {
|
||||
|
@ -3863,9 +3804,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
}
|
||||
code = code.Next
|
||||
case encoder.OpStructFieldStringPtrString:
|
||||
b = appendStructKey(ctx, code, b)
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
p = ptrToNPtr(p+code.Offset, code.PtrNum)
|
||||
b = appendStructKey(ctx, code, b)
|
||||
if p == 0 {
|
||||
b = appendNull(b)
|
||||
} else {
|
||||
|
@ -3917,9 +3858,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
}
|
||||
code = code.Next
|
||||
case encoder.OpStructFieldBoolPtr:
|
||||
b = appendStructKey(ctx, code, b)
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
p = ptrToNPtr(p+code.Offset, code.PtrNum)
|
||||
b = appendStructKey(ctx, code, b)
|
||||
if p == 0 {
|
||||
b = appendNull(b)
|
||||
} else {
|
||||
|
@ -3937,9 +3878,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
}
|
||||
code = code.Next
|
||||
case encoder.OpStructFieldBoolPtrString:
|
||||
b = appendStructKey(ctx, code, b)
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
p = ptrToNPtr(p+code.Offset, code.PtrNum)
|
||||
b = appendStructKey(ctx, code, b)
|
||||
if p == 0 {
|
||||
b = appendNull(b)
|
||||
} else {
|
||||
|
@ -3976,9 +3917,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
}
|
||||
code = code.Next
|
||||
case encoder.OpStructFieldBytesPtr:
|
||||
b = appendStructKey(ctx, code, b)
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
p = ptrToNPtr(p+code.Offset, code.PtrNum)
|
||||
b = appendStructKey(ctx, code, b)
|
||||
if p == 0 {
|
||||
b = appendNull(b)
|
||||
} else {
|
||||
|
@ -4042,9 +3983,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
}
|
||||
code = code.Next
|
||||
case encoder.OpStructFieldNumberPtr:
|
||||
b = appendStructKey(ctx, code, b)
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
p = ptrToNPtr(p+code.Offset, code.PtrNum)
|
||||
b = appendStructKey(ctx, code, b)
|
||||
if p == 0 {
|
||||
b = appendNull(b)
|
||||
} else {
|
||||
|
@ -4069,9 +4010,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
}
|
||||
code = code.Next
|
||||
case encoder.OpStructFieldNumberPtrString:
|
||||
b = appendStructKey(ctx, code, b)
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
p = ptrToNPtr(p+code.Offset, code.PtrNum)
|
||||
b = appendStructKey(ctx, code, b)
|
||||
if p == 0 {
|
||||
b = appendNull(b)
|
||||
} else {
|
||||
|
@ -4234,9 +4175,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
code = code.Next
|
||||
store(ctxptr, code.Idx, p)
|
||||
case encoder.OpStructFieldOmitEmptyArray:
|
||||
b = appendStructKey(ctx, code, b)
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
p += code.Offset
|
||||
b = appendStructKey(ctx, code, b)
|
||||
code = code.Next
|
||||
store(ctxptr, code.Idx, p)
|
||||
case encoder.OpStructFieldArrayPtr:
|
||||
|
@ -4332,17 +4273,21 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
p += code.Offset
|
||||
code = code.Next
|
||||
store(ctxptr, code.Idx, p)
|
||||
case encoder.OpStructEnd:
|
||||
last := len(b) - 1
|
||||
if b[last] == ',' {
|
||||
b[last] = '}'
|
||||
case encoder.OpStructFieldOmitEmptyStruct:
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
p += code.Offset
|
||||
if ptrToPtr(p) == 0 && code.IsNextOpPtrType {
|
||||
code = code.NextField
|
||||
} else {
|
||||
b = append(b, '}')
|
||||
b = appendStructKey(ctx, code, b)
|
||||
code = code.Next
|
||||
store(ctxptr, code.Idx, p)
|
||||
}
|
||||
b = appendComma(b)
|
||||
code = code.Next
|
||||
case encoder.OpStructAnonymousEnd:
|
||||
code = code.Next
|
||||
case encoder.OpStructEnd:
|
||||
b = appendStructEndSkipLast(ctx, code, b)
|
||||
code = code.Next
|
||||
case encoder.OpStructEndInt:
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
b = appendStructKey(ctx, code, b)
|
||||
|
@ -4607,11 +4552,11 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
code = code.Next
|
||||
case encoder.OpStructEndFloat64:
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
b = appendStructKey(ctx, code, b)
|
||||
v := ptrToFloat64(p + code.Offset)
|
||||
if math.IsInf(v, 0) || math.IsNaN(v) {
|
||||
return nil, errUnsupportedFloat(v)
|
||||
}
|
||||
b = appendStructKey(ctx, code, b)
|
||||
b = appendFloat64(b, v)
|
||||
b = appendStructEnd(ctx, code, b)
|
||||
code = code.Next
|
||||
|
@ -4787,8 +4732,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
if p == 0 {
|
||||
b = appendNull(b)
|
||||
} else {
|
||||
v := ptrToString(p)
|
||||
b = appendString(b, string(appendString([]byte{}, v)))
|
||||
b = appendString(b, string(appendString([]byte{}, ptrToString(p))))
|
||||
}
|
||||
b = appendStructEnd(ctx, code, b)
|
||||
code = code.Next
|
||||
|
@ -4797,8 +4741,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
p = ptrToNPtr(p+code.Offset, code.PtrNum)
|
||||
if p != 0 {
|
||||
b = appendStructKey(ctx, code, b)
|
||||
v := ptrToString(p)
|
||||
b = appendString(b, string(appendString([]byte{}, v)))
|
||||
b = appendString(b, string(appendString([]byte{}, ptrToString(p))))
|
||||
b = appendStructEnd(ctx, code, b)
|
||||
} else {
|
||||
b = appendStructEndSkipLast(ctx, code, b)
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
package vm_escaped_indent
|
||||
|
||||
import (
|
||||
// HACK: compile order
|
||||
// `vm`, `vm_escaped`, `vm_indent`, `vm_escaped_indent`, `vm_debug` packages uses a lot of memory to compile,
|
||||
// so forcibly make dependencies and avoid compiling in concurrent.
|
||||
// dependency order: vm => vm_escaped => vm_indent => vm_escaped_indent => vm_debug
|
||||
_ "github.com/goccy/go-json/internal/encoder/vm_debug"
|
||||
)
|
|
@ -2,12 +2,43 @@ package vm_escaped_indent
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"unsafe"
|
||||
|
||||
"github.com/goccy/go-json/internal/encoder"
|
||||
"github.com/goccy/go-json/internal/runtime"
|
||||
)
|
||||
|
||||
const uintptrSize = 4 << (^uintptr(0) >> 63)
|
||||
|
||||
var (
|
||||
appendInt = encoder.AppendInt
|
||||
appendUint = encoder.AppendUint
|
||||
appendFloat32 = encoder.AppendFloat32
|
||||
appendFloat64 = encoder.AppendFloat64
|
||||
appendString = encoder.AppendString
|
||||
appendByteSlice = encoder.AppendByteSlice
|
||||
appendNumber = encoder.AppendNumber
|
||||
appendStructEnd = encoder.AppendStructEndIndent
|
||||
appendIndent = encoder.AppendIndent
|
||||
errUnsupportedValue = encoder.ErrUnsupportedValue
|
||||
errUnsupportedFloat = encoder.ErrUnsupportedFloat
|
||||
mapiterinit = encoder.MapIterInit
|
||||
mapiterkey = encoder.MapIterKey
|
||||
mapitervalue = encoder.MapIterValue
|
||||
mapiternext = encoder.MapIterNext
|
||||
maplen = encoder.MapLen
|
||||
)
|
||||
|
||||
type emptyInterface struct {
|
||||
typ *runtime.Type
|
||||
ptr unsafe.Pointer
|
||||
}
|
||||
|
||||
func errUnimplementedOp(op encoder.OpType) error {
|
||||
return fmt.Errorf("encoder (indent+escaped): opcode %s has not been implemented", op)
|
||||
}
|
||||
|
||||
func load(base uintptr, idx uintptr) uintptr {
|
||||
addr := base + idx
|
||||
return **(**uintptr)(unsafe.Pointer(&addr))
|
||||
|
@ -76,6 +107,89 @@ func appendComma(b []byte) []byte {
|
|||
return append(b, ',', '\n')
|
||||
}
|
||||
|
||||
func appendColon(b []byte) []byte {
|
||||
return append(b, ':', ' ')
|
||||
}
|
||||
|
||||
func appendInterface(ctx *encoder.RuntimeContext, codeSet *encoder.OpcodeSet, opt encoder.Option, code *encoder.Opcode, b []byte, iface *emptyInterface, ptrOffset uintptr) ([]byte, error) {
|
||||
ctx.KeepRefs = append(ctx.KeepRefs, unsafe.Pointer(iface))
|
||||
ifaceCodeSet, err := encoder.CompileToGetCodeSet(uintptr(unsafe.Pointer(iface.typ)))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
totalLength := uintptr(codeSet.CodeLength)
|
||||
nextTotalLength := uintptr(ifaceCodeSet.CodeLength)
|
||||
|
||||
curlen := uintptr(len(ctx.Ptrs))
|
||||
offsetNum := ptrOffset / uintptrSize
|
||||
|
||||
newLen := offsetNum + totalLength + nextTotalLength
|
||||
if curlen < newLen {
|
||||
ctx.Ptrs = append(ctx.Ptrs, make([]uintptr, newLen-curlen)...)
|
||||
}
|
||||
oldPtrs := ctx.Ptrs
|
||||
|
||||
newPtrs := ctx.Ptrs[(ptrOffset+totalLength*uintptrSize)/uintptrSize:]
|
||||
newPtrs[0] = uintptr(iface.ptr)
|
||||
|
||||
ctx.Ptrs = newPtrs
|
||||
|
||||
oldBaseIndent := ctx.BaseIndent
|
||||
ctx.BaseIndent = code.Indent
|
||||
bb, err := Run(ctx, b, ifaceCodeSet, opt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ctx.BaseIndent = oldBaseIndent
|
||||
|
||||
ctx.Ptrs = oldPtrs
|
||||
|
||||
return bb, nil
|
||||
}
|
||||
|
||||
func appendMapKeyValue(ctx *encoder.RuntimeContext, code *encoder.Opcode, b, key, value []byte) []byte {
|
||||
b = appendIndent(ctx, b, code.Indent+1)
|
||||
b = append(b, key...)
|
||||
b[len(b)-2] = ':'
|
||||
b[len(b)-1] = ' '
|
||||
return append(b, value...)
|
||||
}
|
||||
|
||||
func appendMapEnd(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
|
||||
b = b[:len(b)-2]
|
||||
b = append(b, '\n')
|
||||
b = appendIndent(ctx, b, code.Indent)
|
||||
return append(b, '}', ',', '\n')
|
||||
}
|
||||
|
||||
func appendArrayHead(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
|
||||
b = append(b, '[', '\n')
|
||||
return appendIndent(ctx, b, code.Indent+1)
|
||||
}
|
||||
|
||||
func appendArrayEnd(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
|
||||
b = b[:len(b)-2]
|
||||
b = append(b, '\n')
|
||||
b = appendIndent(ctx, b, code.Indent)
|
||||
return append(b, ']', ',', '\n')
|
||||
}
|
||||
|
||||
func appendEmptyArray(b []byte) []byte {
|
||||
return append(b, '[', ']', ',', '\n')
|
||||
}
|
||||
|
||||
func appendEmptyObject(b []byte) []byte {
|
||||
return append(b, '{', '}', ',', '\n')
|
||||
}
|
||||
|
||||
func appendObjectEnd(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
|
||||
last := len(b) - 1
|
||||
b[last] = '\n'
|
||||
b = appendIndent(ctx, b, code.Indent-1)
|
||||
return append(b, '}', ',', '\n')
|
||||
}
|
||||
|
||||
func appendMarshalJSON(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte, v interface{}) ([]byte, error) {
|
||||
return encoder.AppendMarshalJSONIndent(ctx, code, b, v, true)
|
||||
}
|
||||
|
@ -109,3 +223,19 @@ func appendStructEndSkipLast(ctx *encoder.RuntimeContext, code *encoder.Opcode,
|
|||
}
|
||||
return appendComma(b)
|
||||
}
|
||||
|
||||
func restoreIndent(ctx *encoder.RuntimeContext, code *encoder.Opcode, ctxptr uintptr) {
|
||||
ctx.BaseIndent = int(load(ctxptr, code.Length))
|
||||
}
|
||||
|
||||
func storeIndent(ctxptr uintptr, code *encoder.Opcode, indent uintptr) {
|
||||
store(ctxptr, code.End.Next.Length, indent)
|
||||
}
|
||||
|
||||
func appendArrayElemIndent(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
|
||||
return appendIndent(ctx, b, code.Indent+1)
|
||||
}
|
||||
|
||||
func appendMapKeyIndent(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
|
||||
return appendIndent(ctx, b, code.Indent)
|
||||
}
|
||||
|
|
|
@ -1,47 +1,13 @@
|
|||
package vm_escaped_indent
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"sort"
|
||||
"unsafe"
|
||||
|
||||
"github.com/goccy/go-json/internal/encoder"
|
||||
"github.com/goccy/go-json/internal/runtime"
|
||||
|
||||
// HACK: compile order
|
||||
// `vm`, `vm_escaped`, `vm_indent`, `vm_escaped_indent`, `vm_debug` packages uses a lot of memory to compile,
|
||||
// so forcibly make dependencies and avoid compiling in concurrent.
|
||||
// dependency order: vm => vm_escaped => vm_indent => vm_escaped_indent => vm_debug
|
||||
_ "github.com/goccy/go-json/internal/encoder/vm_debug"
|
||||
)
|
||||
|
||||
const uintptrSize = 4 << (^uintptr(0) >> 63)
|
||||
|
||||
var (
|
||||
appendInt = encoder.AppendInt
|
||||
appendUint = encoder.AppendUint
|
||||
appendFloat32 = encoder.AppendFloat32
|
||||
appendFloat64 = encoder.AppendFloat64
|
||||
appendString = encoder.AppendEscapedString
|
||||
appendByteSlice = encoder.AppendByteSlice
|
||||
appendNumber = encoder.AppendNumber
|
||||
appendStructEnd = encoder.AppendStructEndIndent
|
||||
appendIndent = encoder.AppendIndent
|
||||
errUnsupportedValue = encoder.ErrUnsupportedValue
|
||||
errUnsupportedFloat = encoder.ErrUnsupportedFloat
|
||||
mapiterinit = encoder.MapIterInit
|
||||
mapiterkey = encoder.MapIterKey
|
||||
mapitervalue = encoder.MapIterValue
|
||||
mapiternext = encoder.MapIterNext
|
||||
maplen = encoder.MapLen
|
||||
)
|
||||
|
||||
type emptyInterface struct {
|
||||
typ *runtime.Type
|
||||
ptr unsafe.Pointer
|
||||
}
|
||||
|
||||
func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt encoder.Option) ([]byte, error) {
|
||||
recursiveLevel := 0
|
||||
ptrOffset := uintptr(0)
|
||||
|
@ -51,7 +17,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
for {
|
||||
switch code.Op {
|
||||
default:
|
||||
return nil, fmt.Errorf("encoder (indent): opcode %s has not been implemented", code.Op)
|
||||
return nil, errUnimplementedOp(code.Op)
|
||||
case encoder.OpPtr:
|
||||
p := load(ctxptr, code.Idx)
|
||||
code = code.Next
|
||||
|
@ -218,38 +184,10 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
code = code.Next
|
||||
break
|
||||
}
|
||||
ctx.KeepRefs = append(ctx.KeepRefs, unsafe.Pointer(iface))
|
||||
ifaceCodeSet, err := encoder.CompileToGetCodeSet(uintptr(unsafe.Pointer(iface.typ)))
|
||||
bb, err := appendInterface(ctx, codeSet, opt, code, b, iface, ptrOffset)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
totalLength := uintptr(codeSet.CodeLength)
|
||||
nextTotalLength := uintptr(ifaceCodeSet.CodeLength)
|
||||
|
||||
curlen := uintptr(len(ctx.Ptrs))
|
||||
offsetNum := ptrOffset / uintptrSize
|
||||
|
||||
newLen := offsetNum + totalLength + nextTotalLength
|
||||
if curlen < newLen {
|
||||
ctx.Ptrs = append(ctx.Ptrs, make([]uintptr, newLen-curlen)...)
|
||||
}
|
||||
oldPtrs := ctx.Ptrs
|
||||
|
||||
newPtrs := ctx.Ptrs[(ptrOffset+totalLength*uintptrSize)/uintptrSize:]
|
||||
newPtrs[0] = uintptr(iface.ptr)
|
||||
|
||||
ctx.Ptrs = newPtrs
|
||||
|
||||
oldBaseIndent := ctx.BaseIndent
|
||||
ctx.BaseIndent = code.Indent
|
||||
bb, err := Run(ctx, b, ifaceCodeSet, opt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ctx.BaseIndent = oldBaseIndent
|
||||
|
||||
ctx.Ptrs = oldPtrs
|
||||
ctxptr = ctx.Ptr()
|
||||
ctx.SeenPtr = ctx.SeenPtr[:len(ctx.SeenPtr)-1]
|
||||
|
||||
|
@ -332,12 +270,11 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
store(ctxptr, code.Length, uintptr(slice.Len))
|
||||
store(ctxptr, code.Idx, uintptr(slice.Data))
|
||||
if slice.Len > 0 {
|
||||
b = append(b, '[', '\n')
|
||||
b = appendIndent(ctx, b, code.Indent+1)
|
||||
b = appendArrayHead(ctx, code, b)
|
||||
code = code.Next
|
||||
store(ctxptr, code.Idx, uintptr(slice.Data))
|
||||
} else {
|
||||
b = append(b, '[', ']', ',', '\n')
|
||||
b = appendEmptyArray(b)
|
||||
code = code.End.Next
|
||||
}
|
||||
case encoder.OpSliceElem:
|
||||
|
@ -345,17 +282,14 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
length := load(ctxptr, code.Length)
|
||||
idx++
|
||||
if idx < length {
|
||||
b = appendIndent(ctx, b, code.Indent+1)
|
||||
b = appendArrayElemIndent(ctx, code, b)
|
||||
store(ctxptr, code.ElemIdx, idx)
|
||||
data := load(ctxptr, code.HeadIdx)
|
||||
size := code.Size
|
||||
code = code.Next
|
||||
store(ctxptr, code.Idx, data+idx*size)
|
||||
} else {
|
||||
b = b[:len(b)-2]
|
||||
b = append(b, '\n')
|
||||
b = appendIndent(ctx, b, code.Indent)
|
||||
b = append(b, ']', ',', '\n')
|
||||
b = appendArrayEnd(ctx, code, b)
|
||||
code = code.End.Next
|
||||
}
|
||||
case encoder.OpArrayPtr:
|
||||
|
@ -377,30 +311,26 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
break
|
||||
}
|
||||
if code.Length > 0 {
|
||||
b = append(b, '[', '\n')
|
||||
b = appendIndent(ctx, b, code.Indent+1)
|
||||
b = appendArrayHead(ctx, code, b)
|
||||
store(ctxptr, code.ElemIdx, 0)
|
||||
code = code.Next
|
||||
store(ctxptr, code.Idx, p)
|
||||
} else {
|
||||
b = append(b, '[', ']', ',', '\n')
|
||||
b = appendEmptyArray(b)
|
||||
code = code.End.Next
|
||||
}
|
||||
case encoder.OpArrayElem:
|
||||
idx := load(ctxptr, code.ElemIdx)
|
||||
idx++
|
||||
if idx < code.Length {
|
||||
b = appendIndent(ctx, b, code.Indent+1)
|
||||
b = appendArrayElemIndent(ctx, code, b)
|
||||
store(ctxptr, code.ElemIdx, idx)
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
size := code.Size
|
||||
code = code.Next
|
||||
store(ctxptr, code.Idx, p+idx*size)
|
||||
} else {
|
||||
b = b[:len(b)-2]
|
||||
b = append(b, '\n')
|
||||
b = appendIndent(ctx, b, code.Indent)
|
||||
b = append(b, ']', ',', '\n')
|
||||
b = appendArrayEnd(ctx, code, b)
|
||||
code = code.End.Next
|
||||
}
|
||||
case encoder.OpMapPtr:
|
||||
|
@ -424,7 +354,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
uptr := ptrToUnsafePtr(p)
|
||||
mlen := maplen(uptr)
|
||||
if mlen <= 0 {
|
||||
b = append(b, '{', '}', ',', '\n')
|
||||
b = appendEmptyObject(b)
|
||||
code = code.End.Next
|
||||
break
|
||||
}
|
||||
|
@ -440,7 +370,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
ctx.KeepRefs = append(ctx.KeepRefs, unsafe.Pointer(mapCtx))
|
||||
store(ctxptr, code.End.MapPos, uintptr(unsafe.Pointer(mapCtx)))
|
||||
} else {
|
||||
b = appendIndent(ctx, b, code.Next.Indent)
|
||||
b = appendMapKeyIndent(ctx, code.Next, b)
|
||||
}
|
||||
key := mapiterkey(iter)
|
||||
store(ctxptr, code.Next.Idx, uintptr(key))
|
||||
|
@ -451,7 +381,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
idx++
|
||||
if (opt & encoder.UnorderedMapOption) != 0 {
|
||||
if idx < length {
|
||||
b = appendIndent(ctx, b, code.Indent)
|
||||
b = appendMapKeyIndent(ctx, code, b)
|
||||
store(ctxptr, code.ElemIdx, idx)
|
||||
ptr := load(ctxptr, code.MapIter)
|
||||
iter := ptrToUnsafePtr(ptr)
|
||||
|
@ -459,10 +389,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
store(ctxptr, code.Next.Idx, uintptr(key))
|
||||
code = code.Next
|
||||
} else {
|
||||
last := len(b) - 1
|
||||
b[last] = '\n'
|
||||
b = appendIndent(ctx, b, code.Indent-1)
|
||||
b = append(b, '}', ',', '\n')
|
||||
b = appendObjectEnd(ctx, code, b)
|
||||
code = code.End.Next
|
||||
}
|
||||
} else {
|
||||
|
@ -482,7 +409,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
}
|
||||
case encoder.OpMapValue:
|
||||
if (opt & encoder.UnorderedMapOption) != 0 {
|
||||
b = append(b, ':', ' ')
|
||||
b = appendColon(b)
|
||||
} else {
|
||||
ptr := load(ctxptr, code.End.MapPos)
|
||||
mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(ptr))
|
||||
|
@ -495,7 +422,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
mapiternext(iter)
|
||||
code = code.Next
|
||||
case encoder.OpMapEnd:
|
||||
// this operation only used by sorted map
|
||||
// this operation only used by sorted map.
|
||||
length := int(load(ctxptr, code.Length))
|
||||
ptr := load(ctxptr, code.MapPos)
|
||||
mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(ptr))
|
||||
|
@ -517,17 +444,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
sort.Sort(mapCtx.Slice)
|
||||
buf := mapCtx.Buf
|
||||
for _, item := range mapCtx.Slice.Items {
|
||||
buf = appendIndent(ctx, buf, code.Indent+1)
|
||||
buf = append(buf, item.Key...)
|
||||
buf[len(buf)-2] = ':'
|
||||
buf[len(buf)-1] = ' '
|
||||
buf = append(buf, item.Value...)
|
||||
buf = appendMapKeyValue(ctx, code, buf, item.Key, item.Value)
|
||||
}
|
||||
buf = buf[:len(buf)-2]
|
||||
buf = append(buf, '\n')
|
||||
buf = appendIndent(ctx, buf, code.Indent)
|
||||
buf = append(buf, '}', ',', '\n')
|
||||
|
||||
buf = appendMapEnd(ctx, code, buf)
|
||||
b = b[:pos[0]]
|
||||
b = append(b, buf...)
|
||||
mapCtx.Buf = buf
|
||||
|
@ -570,14 +489,14 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
store(ctxptr, c.Idx, ptr)
|
||||
store(ctxptr, c.End.Next.Idx, oldOffset)
|
||||
store(ctxptr, c.End.Next.ElemIdx, uintptr(unsafe.Pointer(code.Next)))
|
||||
store(ctxptr, c.End.Next.Length, uintptr(oldBaseIndent))
|
||||
storeIndent(ctxptr, c, uintptr(oldBaseIndent))
|
||||
code = c
|
||||
recursiveLevel++
|
||||
case encoder.OpRecursiveEnd:
|
||||
recursiveLevel--
|
||||
|
||||
// restore ctxptr
|
||||
ctx.BaseIndent = int(load(ctxptr, code.Length))
|
||||
restoreIndent(ctx, code, ctxptr)
|
||||
offset := load(ctxptr, code.Idx)
|
||||
ctx.SeenPtr = ctx.SeenPtr[:len(ctx.SeenPtr)-1]
|
||||
|
||||
|
@ -1382,7 +1301,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
}
|
||||
b = appendStructKey(ctx, code, b)
|
||||
if code.Indirect {
|
||||
p = ptrToNPtr(p, code.PtrNum)
|
||||
p = ptrToNPtr(p+code.Offset, code.PtrNum)
|
||||
}
|
||||
if p == 0 {
|
||||
b = appendNull(b)
|
||||
|
@ -1562,12 +1481,12 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
b = appendStructHead(b)
|
||||
}
|
||||
v := ptrToFloat64(p + code.Offset)
|
||||
if math.IsInf(v, 0) || math.IsNaN(v) {
|
||||
return nil, errUnsupportedFloat(v)
|
||||
}
|
||||
if v == 0 {
|
||||
code = code.NextField
|
||||
} else {
|
||||
if math.IsInf(v, 0) || math.IsNaN(v) {
|
||||
return nil, errUnsupportedFloat(v)
|
||||
}
|
||||
b = appendStructKey(ctx, code, b)
|
||||
b = appendFloat64(b, v)
|
||||
b = appendComma(b)
|
||||
|
@ -1600,12 +1519,12 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
if !code.AnonymousHead {
|
||||
b = appendStructHead(b)
|
||||
}
|
||||
b = appendStructKey(ctx, code, b)
|
||||
b = append(b, '"')
|
||||
v := ptrToFloat64(p + code.Offset)
|
||||
if math.IsInf(v, 0) || math.IsNaN(v) {
|
||||
return nil, errUnsupportedFloat(v)
|
||||
}
|
||||
b = appendStructKey(ctx, code, b)
|
||||
b = append(b, '"')
|
||||
b = appendFloat64(b, v)
|
||||
b = append(b, '"')
|
||||
b = appendComma(b)
|
||||
|
@ -1638,12 +1557,12 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
b = appendStructHead(b)
|
||||
}
|
||||
v := ptrToFloat64(p + code.Offset)
|
||||
if math.IsInf(v, 0) || math.IsNaN(v) {
|
||||
return nil, errUnsupportedFloat(v)
|
||||
}
|
||||
if v == 0 {
|
||||
code = code.NextField
|
||||
} else {
|
||||
if math.IsInf(v, 0) || math.IsNaN(v) {
|
||||
return nil, errUnsupportedFloat(v)
|
||||
}
|
||||
b = appendStructKey(ctx, code, b)
|
||||
b = append(b, '"')
|
||||
b = appendFloat64(b, v)
|
||||
|
@ -1906,8 +1825,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
b = appendStructHead(b)
|
||||
}
|
||||
b = appendStructKey(ctx, code, b)
|
||||
v := ptrToString(p + code.Offset)
|
||||
b = appendString(b, string(appendString([]byte{}, v)))
|
||||
b = appendString(b, string(appendString([]byte{}, ptrToString(p+code.Offset))))
|
||||
b = appendComma(b)
|
||||
code = code.Next
|
||||
case encoder.OpStructPtrHeadOmitEmptyStringString:
|
||||
|
@ -2251,12 +2169,12 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
}
|
||||
b = appendStructKey(ctx, code, b)
|
||||
if code.Indirect {
|
||||
p = ptrToNPtr(p, code.PtrNum)
|
||||
p = ptrToNPtr(p+code.Offset, code.PtrNum)
|
||||
}
|
||||
if p == 0 {
|
||||
b = appendNull(b)
|
||||
} else {
|
||||
b = appendBool(b, ptrToBool(p+code.Offset))
|
||||
b = appendBool(b, ptrToBool(p))
|
||||
}
|
||||
b = appendComma(b)
|
||||
code = code.Next
|
||||
|
@ -3778,13 +3696,15 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
b = appendStructKey(ctx, code, b)
|
||||
if p == 0 {
|
||||
b = appendNull(b)
|
||||
} else {
|
||||
v := ptrToFloat64(p)
|
||||
if math.IsInf(v, 0) || math.IsNaN(v) {
|
||||
return nil, errUnsupportedFloat(v)
|
||||
}
|
||||
b = appendFloat64(b, v)
|
||||
b = appendComma(b)
|
||||
code = code.Next
|
||||
break
|
||||
}
|
||||
v := ptrToFloat64(p)
|
||||
if math.IsInf(v, 0) || math.IsNaN(v) {
|
||||
return nil, errUnsupportedFloat(v)
|
||||
}
|
||||
b = appendFloat64(b, v)
|
||||
b = appendComma(b)
|
||||
code = code.Next
|
||||
case encoder.OpStructFieldOmitEmptyFloat64Ptr:
|
||||
|
@ -3807,11 +3727,11 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
if p == 0 {
|
||||
b = appendNull(b)
|
||||
} else {
|
||||
b = append(b, '"')
|
||||
v := ptrToFloat64(p)
|
||||
if math.IsInf(v, 0) || math.IsNaN(v) {
|
||||
return nil, errUnsupportedFloat(v)
|
||||
}
|
||||
b = append(b, '"')
|
||||
b = appendFloat64(b, v)
|
||||
b = append(b, '"')
|
||||
}
|
||||
|
@ -4348,9 +4268,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
code = code.NextField
|
||||
}
|
||||
case encoder.OpStructFieldStruct:
|
||||
b = appendStructKey(ctx, code, b)
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
p += code.Offset
|
||||
b = appendStructKey(ctx, code, b)
|
||||
code = code.Next
|
||||
store(ctxptr, code.Idx, p)
|
||||
case encoder.OpStructFieldOmitEmptyStruct:
|
||||
|
@ -4366,25 +4286,11 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
case encoder.OpStructAnonymousEnd:
|
||||
code = code.Next
|
||||
case encoder.OpStructEnd:
|
||||
last := len(b) - 1
|
||||
if b[last-1] == '{' {
|
||||
b[last] = '}'
|
||||
b = appendComma(b)
|
||||
code = code.Next
|
||||
break
|
||||
}
|
||||
if b[last] == '\n' {
|
||||
// to remove ',' and '\n' characters
|
||||
b = b[:len(b)-2]
|
||||
}
|
||||
b = append(b, '\n')
|
||||
b = appendIndent(ctx, b, code.Indent)
|
||||
b = append(b, '}')
|
||||
b = appendComma(b)
|
||||
b = appendStructEndSkipLast(ctx, code, b)
|
||||
code = code.Next
|
||||
case encoder.OpStructEndInt:
|
||||
b = appendStructKey(ctx, code, b)
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
b = appendStructKey(ctx, code, b)
|
||||
b = appendInt(b, ptrToUint64(p+code.Offset), code)
|
||||
b = appendStructEnd(ctx, code, b)
|
||||
code = code.Next
|
||||
|
@ -4471,8 +4377,8 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
}
|
||||
code = code.Next
|
||||
case encoder.OpStructEndUint:
|
||||
b = appendStructKey(ctx, code, b)
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
b = appendStructKey(ctx, code, b)
|
||||
b = appendUint(b, ptrToUint64(p+code.Offset), code)
|
||||
b = appendStructEnd(ctx, code, b)
|
||||
code = code.Next
|
||||
|
@ -4559,8 +4465,8 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
}
|
||||
code = code.Next
|
||||
case encoder.OpStructEndFloat32:
|
||||
b = appendStructKey(ctx, code, b)
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
b = appendStructKey(ctx, code, b)
|
||||
b = appendFloat32(b, ptrToFloat32(p+code.Offset))
|
||||
b = appendStructEnd(ctx, code, b)
|
||||
code = code.Next
|
||||
|
@ -4645,12 +4551,12 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
}
|
||||
code = code.Next
|
||||
case encoder.OpStructEndFloat64:
|
||||
b = appendStructKey(ctx, code, b)
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
v := ptrToFloat64(p + code.Offset)
|
||||
if math.IsInf(v, 0) || math.IsNaN(v) {
|
||||
return nil, errUnsupportedFloat(v)
|
||||
}
|
||||
b = appendStructKey(ctx, code, b)
|
||||
b = appendFloat64(b, v)
|
||||
b = appendStructEnd(ctx, code, b)
|
||||
code = code.Next
|
||||
|
@ -4658,10 +4564,10 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
p := load(ctxptr, code.HeadIdx)
|
||||
v := ptrToFloat64(p + code.Offset)
|
||||
if v != 0 {
|
||||
b = appendStructKey(ctx, code, b)
|
||||
if math.IsInf(v, 0) || math.IsNaN(v) {
|
||||
return nil, errUnsupportedFloat(v)
|
||||
}
|
||||
b = appendStructKey(ctx, code, b)
|
||||
b = appendFloat64(b, v)
|
||||
b = appendStructEnd(ctx, code, b)
|
||||
} else {
|
||||
|
@ -4684,11 +4590,11 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
p := load(ctxptr, code.HeadIdx)
|
||||
v := ptrToFloat64(p + code.Offset)
|
||||
if v != 0 {
|
||||
b = appendStructKey(ctx, code, b)
|
||||
b = append(b, '"')
|
||||
if math.IsInf(v, 0) || math.IsNaN(v) {
|
||||
return nil, errUnsupportedFloat(v)
|
||||
}
|
||||
b = appendStructKey(ctx, code, b)
|
||||
b = append(b, '"')
|
||||
b = appendFloat64(b, v)
|
||||
b = append(b, '"')
|
||||
b = appendStructEnd(ctx, code, b)
|
||||
|
@ -4702,13 +4608,15 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
p = ptrToNPtr(p+code.Offset, code.PtrNum)
|
||||
if p == 0 {
|
||||
b = appendNull(b)
|
||||
} else {
|
||||
v := ptrToFloat64(p)
|
||||
if math.IsInf(v, 0) || math.IsNaN(v) {
|
||||
return nil, errUnsupportedFloat(v)
|
||||
}
|
||||
b = appendFloat64(b, v)
|
||||
b = appendStructEnd(ctx, code, b)
|
||||
code = code.Next
|
||||
break
|
||||
}
|
||||
v := ptrToFloat64(p)
|
||||
if math.IsInf(v, 0) || math.IsNaN(v) {
|
||||
return nil, errUnsupportedFloat(v)
|
||||
}
|
||||
b = appendFloat64(b, v)
|
||||
b = appendStructEnd(ctx, code, b)
|
||||
code = code.Next
|
||||
case encoder.OpStructEndOmitEmptyFloat64Ptr:
|
||||
|
@ -4748,11 +4656,11 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
p = ptrToNPtr(p+code.Offset, code.PtrNum)
|
||||
if p != 0 {
|
||||
b = appendStructKey(ctx, code, b)
|
||||
b = append(b, '"')
|
||||
v := ptrToFloat64(p)
|
||||
if math.IsInf(v, 0) || math.IsNaN(v) {
|
||||
return nil, errUnsupportedFloat(v)
|
||||
}
|
||||
b = append(b, '"')
|
||||
b = appendFloat64(b, v)
|
||||
b = append(b, '"')
|
||||
b = appendStructEnd(ctx, code, b)
|
||||
|
@ -4761,8 +4669,8 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
}
|
||||
code = code.Next
|
||||
case encoder.OpStructEndString:
|
||||
b = appendStructKey(ctx, code, b)
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
b = appendStructKey(ctx, code, b)
|
||||
b = appendString(b, ptrToString(p+code.Offset))
|
||||
b = appendStructEnd(ctx, code, b)
|
||||
code = code.Next
|
||||
|
@ -4840,8 +4748,8 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
}
|
||||
code = code.Next
|
||||
case encoder.OpStructEndBool:
|
||||
b = appendStructKey(ctx, code, b)
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
b = appendStructKey(ctx, code, b)
|
||||
b = appendBool(b, ptrToBool(p+code.Offset))
|
||||
b = appendStructEnd(ctx, code, b)
|
||||
code = code.Next
|
||||
|
@ -4926,8 +4834,8 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
}
|
||||
code = code.Next
|
||||
case encoder.OpStructEndBytes:
|
||||
b = appendStructKey(ctx, code, b)
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
b = appendStructKey(ctx, code, b)
|
||||
b = appendByteSlice(b, ptrToBytes(p+code.Offset))
|
||||
b = appendStructEnd(ctx, code, b)
|
||||
code = code.Next
|
||||
|
@ -4965,8 +4873,8 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
}
|
||||
code = code.Next
|
||||
case encoder.OpStructEndNumber:
|
||||
b = appendStructKey(ctx, code, b)
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
b = appendStructKey(ctx, code, b)
|
||||
bb, err := appendNumber(b, ptrToNumber(p+code.Offset))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -4988,9 +4896,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
}
|
||||
code = code.Next
|
||||
case encoder.OpStructEndNumberString:
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
b = appendStructKey(ctx, code, b)
|
||||
b = append(b, '"')
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
bb, err := appendNumber(b, ptrToNumber(p+code.Offset))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
package vm_indent
|
||||
|
||||
import (
|
||||
// HACK: compile order
|
||||
// `vm`, `vm_escaped`, `vm_indent`, `vm_escaped_indent`, `vm_debug` packages uses a lot of memory to compile,
|
||||
// so forcibly make dependencies and avoid compiling in concurrent.
|
||||
// dependency order: vm => vm_escaped => vm_indent => vm_escaped_indent => vm_debug
|
||||
_ "github.com/goccy/go-json/internal/encoder/vm_escaped_indent"
|
||||
)
|
|
@ -2,12 +2,43 @@ package vm_indent
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"unsafe"
|
||||
|
||||
"github.com/goccy/go-json/internal/encoder"
|
||||
"github.com/goccy/go-json/internal/runtime"
|
||||
)
|
||||
|
||||
const uintptrSize = 4 << (^uintptr(0) >> 63)
|
||||
|
||||
var (
|
||||
appendInt = encoder.AppendInt
|
||||
appendUint = encoder.AppendUint
|
||||
appendFloat32 = encoder.AppendFloat32
|
||||
appendFloat64 = encoder.AppendFloat64
|
||||
appendString = encoder.AppendString
|
||||
appendByteSlice = encoder.AppendByteSlice
|
||||
appendNumber = encoder.AppendNumber
|
||||
appendStructEnd = encoder.AppendStructEndIndent
|
||||
appendIndent = encoder.AppendIndent
|
||||
errUnsupportedValue = encoder.ErrUnsupportedValue
|
||||
errUnsupportedFloat = encoder.ErrUnsupportedFloat
|
||||
mapiterinit = encoder.MapIterInit
|
||||
mapiterkey = encoder.MapIterKey
|
||||
mapitervalue = encoder.MapIterValue
|
||||
mapiternext = encoder.MapIterNext
|
||||
maplen = encoder.MapLen
|
||||
)
|
||||
|
||||
type emptyInterface struct {
|
||||
typ *runtime.Type
|
||||
ptr unsafe.Pointer
|
||||
}
|
||||
|
||||
func errUnimplementedOp(op encoder.OpType) error {
|
||||
return fmt.Errorf("encoder (indent): opcode %s has not been implemented", op)
|
||||
}
|
||||
|
||||
func load(base uintptr, idx uintptr) uintptr {
|
||||
addr := base + idx
|
||||
return **(**uintptr)(unsafe.Pointer(&addr))
|
||||
|
@ -76,8 +107,87 @@ func appendComma(b []byte) []byte {
|
|||
return append(b, ',', '\n')
|
||||
}
|
||||
|
||||
func appendStructHead(b []byte) []byte {
|
||||
return append(b, '{', '\n')
|
||||
func appendColon(b []byte) []byte {
|
||||
return append(b, ':', ' ')
|
||||
}
|
||||
|
||||
func appendInterface(ctx *encoder.RuntimeContext, codeSet *encoder.OpcodeSet, opt encoder.Option, code *encoder.Opcode, b []byte, iface *emptyInterface, ptrOffset uintptr) ([]byte, error) {
|
||||
ctx.KeepRefs = append(ctx.KeepRefs, unsafe.Pointer(iface))
|
||||
ifaceCodeSet, err := encoder.CompileToGetCodeSet(uintptr(unsafe.Pointer(iface.typ)))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
totalLength := uintptr(codeSet.CodeLength)
|
||||
nextTotalLength := uintptr(ifaceCodeSet.CodeLength)
|
||||
|
||||
curlen := uintptr(len(ctx.Ptrs))
|
||||
offsetNum := ptrOffset / uintptrSize
|
||||
|
||||
newLen := offsetNum + totalLength + nextTotalLength
|
||||
if curlen < newLen {
|
||||
ctx.Ptrs = append(ctx.Ptrs, make([]uintptr, newLen-curlen)...)
|
||||
}
|
||||
oldPtrs := ctx.Ptrs
|
||||
|
||||
newPtrs := ctx.Ptrs[(ptrOffset+totalLength*uintptrSize)/uintptrSize:]
|
||||
newPtrs[0] = uintptr(iface.ptr)
|
||||
|
||||
ctx.Ptrs = newPtrs
|
||||
|
||||
oldBaseIndent := ctx.BaseIndent
|
||||
ctx.BaseIndent = code.Indent
|
||||
bb, err := Run(ctx, b, ifaceCodeSet, opt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ctx.BaseIndent = oldBaseIndent
|
||||
|
||||
ctx.Ptrs = oldPtrs
|
||||
|
||||
return bb, nil
|
||||
}
|
||||
|
||||
func appendMapKeyValue(ctx *encoder.RuntimeContext, code *encoder.Opcode, b, key, value []byte) []byte {
|
||||
b = appendIndent(ctx, b, code.Indent+1)
|
||||
b = append(b, key...)
|
||||
b[len(b)-2] = ':'
|
||||
b[len(b)-1] = ' '
|
||||
return append(b, value...)
|
||||
}
|
||||
|
||||
func appendMapEnd(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
|
||||
b = b[:len(b)-2]
|
||||
b = append(b, '\n')
|
||||
b = appendIndent(ctx, b, code.Indent)
|
||||
return append(b, '}', ',', '\n')
|
||||
}
|
||||
|
||||
func appendArrayHead(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
|
||||
b = append(b, '[', '\n')
|
||||
return appendIndent(ctx, b, code.Indent+1)
|
||||
}
|
||||
|
||||
func appendArrayEnd(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
|
||||
b = b[:len(b)-2]
|
||||
b = append(b, '\n')
|
||||
b = appendIndent(ctx, b, code.Indent)
|
||||
return append(b, ']', ',', '\n')
|
||||
}
|
||||
|
||||
func appendEmptyArray(b []byte) []byte {
|
||||
return append(b, '[', ']', ',', '\n')
|
||||
}
|
||||
|
||||
func appendEmptyObject(b []byte) []byte {
|
||||
return append(b, '{', '}', ',', '\n')
|
||||
}
|
||||
|
||||
func appendObjectEnd(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
|
||||
last := len(b) - 1
|
||||
b[last] = '\n'
|
||||
b = appendIndent(ctx, b, code.Indent-1)
|
||||
return append(b, '}', ',', '\n')
|
||||
}
|
||||
|
||||
func appendMarshalJSON(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte, v interface{}) ([]byte, error) {
|
||||
|
@ -88,6 +198,10 @@ func appendMarshalText(code *encoder.Opcode, b []byte, v interface{}) ([]byte, e
|
|||
return encoder.AppendMarshalTextIndent(code, b, v, false)
|
||||
}
|
||||
|
||||
func appendStructHead(b []byte) []byte {
|
||||
return append(b, '{', '\n')
|
||||
}
|
||||
|
||||
func appendStructKey(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
|
||||
b = appendIndent(ctx, b, code.Indent)
|
||||
b = append(b, code.Key...)
|
||||
|
@ -109,3 +223,19 @@ func appendStructEndSkipLast(ctx *encoder.RuntimeContext, code *encoder.Opcode,
|
|||
}
|
||||
return appendComma(b)
|
||||
}
|
||||
|
||||
func restoreIndent(ctx *encoder.RuntimeContext, code *encoder.Opcode, ctxptr uintptr) {
|
||||
ctx.BaseIndent = int(load(ctxptr, code.Length))
|
||||
}
|
||||
|
||||
func storeIndent(ctxptr uintptr, code *encoder.Opcode, indent uintptr) {
|
||||
store(ctxptr, code.End.Next.Length, indent)
|
||||
}
|
||||
|
||||
func appendArrayElemIndent(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
|
||||
return appendIndent(ctx, b, code.Indent+1)
|
||||
}
|
||||
|
||||
func appendMapKeyIndent(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte {
|
||||
return appendIndent(ctx, b, code.Indent)
|
||||
}
|
||||
|
|
|
@ -1,47 +1,13 @@
|
|||
package vm_indent
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"sort"
|
||||
"unsafe"
|
||||
|
||||
"github.com/goccy/go-json/internal/encoder"
|
||||
"github.com/goccy/go-json/internal/runtime"
|
||||
|
||||
// HACK: compile order
|
||||
// `vm`, `vm_escaped`, `vm_indent`, `vm_escaped_indent`, `vm_debug` packages uses a lot of memory to compile,
|
||||
// so forcibly make dependencies and avoid compiling in concurrent.
|
||||
// dependency order: vm => vm_escaped => vm_indent => vm_escaped_indent => vm_debug
|
||||
_ "github.com/goccy/go-json/internal/encoder/vm_escaped_indent"
|
||||
)
|
||||
|
||||
const uintptrSize = 4 << (^uintptr(0) >> 63)
|
||||
|
||||
var (
|
||||
appendInt = encoder.AppendInt
|
||||
appendUint = encoder.AppendUint
|
||||
appendFloat32 = encoder.AppendFloat32
|
||||
appendFloat64 = encoder.AppendFloat64
|
||||
appendString = encoder.AppendString
|
||||
appendByteSlice = encoder.AppendByteSlice
|
||||
appendNumber = encoder.AppendNumber
|
||||
appendStructEnd = encoder.AppendStructEndIndent
|
||||
appendIndent = encoder.AppendIndent
|
||||
errUnsupportedValue = encoder.ErrUnsupportedValue
|
||||
errUnsupportedFloat = encoder.ErrUnsupportedFloat
|
||||
mapiterinit = encoder.MapIterInit
|
||||
mapiterkey = encoder.MapIterKey
|
||||
mapitervalue = encoder.MapIterValue
|
||||
mapiternext = encoder.MapIterNext
|
||||
maplen = encoder.MapLen
|
||||
)
|
||||
|
||||
type emptyInterface struct {
|
||||
typ *runtime.Type
|
||||
ptr unsafe.Pointer
|
||||
}
|
||||
|
||||
func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt encoder.Option) ([]byte, error) {
|
||||
recursiveLevel := 0
|
||||
ptrOffset := uintptr(0)
|
||||
|
@ -51,7 +17,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
for {
|
||||
switch code.Op {
|
||||
default:
|
||||
return nil, fmt.Errorf("encoder (indent): opcode %s has not been implemented", code.Op)
|
||||
return nil, errUnimplementedOp(code.Op)
|
||||
case encoder.OpPtr:
|
||||
p := load(ctxptr, code.Idx)
|
||||
code = code.Next
|
||||
|
@ -218,38 +184,10 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
code = code.Next
|
||||
break
|
||||
}
|
||||
ctx.KeepRefs = append(ctx.KeepRefs, unsafe.Pointer(iface))
|
||||
ifaceCodeSet, err := encoder.CompileToGetCodeSet(uintptr(unsafe.Pointer(iface.typ)))
|
||||
bb, err := appendInterface(ctx, codeSet, opt, code, b, iface, ptrOffset)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
totalLength := uintptr(codeSet.CodeLength)
|
||||
nextTotalLength := uintptr(ifaceCodeSet.CodeLength)
|
||||
|
||||
curlen := uintptr(len(ctx.Ptrs))
|
||||
offsetNum := ptrOffset / uintptrSize
|
||||
|
||||
newLen := offsetNum + totalLength + nextTotalLength
|
||||
if curlen < newLen {
|
||||
ctx.Ptrs = append(ctx.Ptrs, make([]uintptr, newLen-curlen)...)
|
||||
}
|
||||
oldPtrs := ctx.Ptrs
|
||||
|
||||
newPtrs := ctx.Ptrs[(ptrOffset+totalLength*uintptrSize)/uintptrSize:]
|
||||
newPtrs[0] = uintptr(iface.ptr)
|
||||
|
||||
ctx.Ptrs = newPtrs
|
||||
|
||||
oldBaseIndent := ctx.BaseIndent
|
||||
ctx.BaseIndent = code.Indent
|
||||
bb, err := Run(ctx, b, ifaceCodeSet, opt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ctx.BaseIndent = oldBaseIndent
|
||||
|
||||
ctx.Ptrs = oldPtrs
|
||||
ctxptr = ctx.Ptr()
|
||||
ctx.SeenPtr = ctx.SeenPtr[:len(ctx.SeenPtr)-1]
|
||||
|
||||
|
@ -332,12 +270,11 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
store(ctxptr, code.Length, uintptr(slice.Len))
|
||||
store(ctxptr, code.Idx, uintptr(slice.Data))
|
||||
if slice.Len > 0 {
|
||||
b = append(b, '[', '\n')
|
||||
b = appendIndent(ctx, b, code.Indent+1)
|
||||
b = appendArrayHead(ctx, code, b)
|
||||
code = code.Next
|
||||
store(ctxptr, code.Idx, uintptr(slice.Data))
|
||||
} else {
|
||||
b = append(b, '[', ']', ',', '\n')
|
||||
b = appendEmptyArray(b)
|
||||
code = code.End.Next
|
||||
}
|
||||
case encoder.OpSliceElem:
|
||||
|
@ -345,17 +282,14 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
length := load(ctxptr, code.Length)
|
||||
idx++
|
||||
if idx < length {
|
||||
b = appendIndent(ctx, b, code.Indent+1)
|
||||
b = appendArrayElemIndent(ctx, code, b)
|
||||
store(ctxptr, code.ElemIdx, idx)
|
||||
data := load(ctxptr, code.HeadIdx)
|
||||
size := code.Size
|
||||
code = code.Next
|
||||
store(ctxptr, code.Idx, data+idx*size)
|
||||
} else {
|
||||
b = b[:len(b)-2]
|
||||
b = append(b, '\n')
|
||||
b = appendIndent(ctx, b, code.Indent)
|
||||
b = append(b, ']', ',', '\n')
|
||||
b = appendArrayEnd(ctx, code, b)
|
||||
code = code.End.Next
|
||||
}
|
||||
case encoder.OpArrayPtr:
|
||||
|
@ -377,30 +311,26 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
break
|
||||
}
|
||||
if code.Length > 0 {
|
||||
b = append(b, '[', '\n')
|
||||
b = appendIndent(ctx, b, code.Indent+1)
|
||||
b = appendArrayHead(ctx, code, b)
|
||||
store(ctxptr, code.ElemIdx, 0)
|
||||
code = code.Next
|
||||
store(ctxptr, code.Idx, p)
|
||||
} else {
|
||||
b = append(b, '[', ']', ',', '\n')
|
||||
b = appendEmptyArray(b)
|
||||
code = code.End.Next
|
||||
}
|
||||
case encoder.OpArrayElem:
|
||||
idx := load(ctxptr, code.ElemIdx)
|
||||
idx++
|
||||
if idx < code.Length {
|
||||
b = appendIndent(ctx, b, code.Indent+1)
|
||||
b = appendArrayElemIndent(ctx, code, b)
|
||||
store(ctxptr, code.ElemIdx, idx)
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
size := code.Size
|
||||
code = code.Next
|
||||
store(ctxptr, code.Idx, p+idx*size)
|
||||
} else {
|
||||
b = b[:len(b)-2]
|
||||
b = append(b, '\n')
|
||||
b = appendIndent(ctx, b, code.Indent)
|
||||
b = append(b, ']', ',', '\n')
|
||||
b = appendArrayEnd(ctx, code, b)
|
||||
code = code.End.Next
|
||||
}
|
||||
case encoder.OpMapPtr:
|
||||
|
@ -424,7 +354,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
uptr := ptrToUnsafePtr(p)
|
||||
mlen := maplen(uptr)
|
||||
if mlen <= 0 {
|
||||
b = append(b, '{', '}', ',', '\n')
|
||||
b = appendEmptyObject(b)
|
||||
code = code.End.Next
|
||||
break
|
||||
}
|
||||
|
@ -440,7 +370,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
ctx.KeepRefs = append(ctx.KeepRefs, unsafe.Pointer(mapCtx))
|
||||
store(ctxptr, code.End.MapPos, uintptr(unsafe.Pointer(mapCtx)))
|
||||
} else {
|
||||
b = appendIndent(ctx, b, code.Next.Indent)
|
||||
b = appendMapKeyIndent(ctx, code.Next, b)
|
||||
}
|
||||
key := mapiterkey(iter)
|
||||
store(ctxptr, code.Next.Idx, uintptr(key))
|
||||
|
@ -451,7 +381,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
idx++
|
||||
if (opt & encoder.UnorderedMapOption) != 0 {
|
||||
if idx < length {
|
||||
b = appendIndent(ctx, b, code.Indent)
|
||||
b = appendMapKeyIndent(ctx, code, b)
|
||||
store(ctxptr, code.ElemIdx, idx)
|
||||
ptr := load(ctxptr, code.MapIter)
|
||||
iter := ptrToUnsafePtr(ptr)
|
||||
|
@ -459,10 +389,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
store(ctxptr, code.Next.Idx, uintptr(key))
|
||||
code = code.Next
|
||||
} else {
|
||||
last := len(b) - 1
|
||||
b[last] = '\n'
|
||||
b = appendIndent(ctx, b, code.Indent-1)
|
||||
b = append(b, '}', ',', '\n')
|
||||
b = appendObjectEnd(ctx, code, b)
|
||||
code = code.End.Next
|
||||
}
|
||||
} else {
|
||||
|
@ -482,7 +409,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
}
|
||||
case encoder.OpMapValue:
|
||||
if (opt & encoder.UnorderedMapOption) != 0 {
|
||||
b = append(b, ':', ' ')
|
||||
b = appendColon(b)
|
||||
} else {
|
||||
ptr := load(ctxptr, code.End.MapPos)
|
||||
mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(ptr))
|
||||
|
@ -495,7 +422,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
mapiternext(iter)
|
||||
code = code.Next
|
||||
case encoder.OpMapEnd:
|
||||
// this operation only used by sorted map
|
||||
// this operation only used by sorted map.
|
||||
length := int(load(ctxptr, code.Length))
|
||||
ptr := load(ctxptr, code.MapPos)
|
||||
mapCtx := (*encoder.MapContext)(ptrToUnsafePtr(ptr))
|
||||
|
@ -517,17 +444,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
sort.Sort(mapCtx.Slice)
|
||||
buf := mapCtx.Buf
|
||||
for _, item := range mapCtx.Slice.Items {
|
||||
buf = appendIndent(ctx, buf, code.Indent+1)
|
||||
buf = append(buf, item.Key...)
|
||||
buf[len(buf)-2] = ':'
|
||||
buf[len(buf)-1] = ' '
|
||||
buf = append(buf, item.Value...)
|
||||
buf = appendMapKeyValue(ctx, code, buf, item.Key, item.Value)
|
||||
}
|
||||
buf = buf[:len(buf)-2]
|
||||
buf = append(buf, '\n')
|
||||
buf = appendIndent(ctx, buf, code.Indent)
|
||||
buf = append(buf, '}', ',', '\n')
|
||||
|
||||
buf = appendMapEnd(ctx, code, buf)
|
||||
b = b[:pos[0]]
|
||||
b = append(b, buf...)
|
||||
mapCtx.Buf = buf
|
||||
|
@ -570,14 +489,14 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
store(ctxptr, c.Idx, ptr)
|
||||
store(ctxptr, c.End.Next.Idx, oldOffset)
|
||||
store(ctxptr, c.End.Next.ElemIdx, uintptr(unsafe.Pointer(code.Next)))
|
||||
store(ctxptr, c.End.Next.Length, uintptr(oldBaseIndent))
|
||||
storeIndent(ctxptr, c, uintptr(oldBaseIndent))
|
||||
code = c
|
||||
recursiveLevel++
|
||||
case encoder.OpRecursiveEnd:
|
||||
recursiveLevel--
|
||||
|
||||
// restore ctxptr
|
||||
ctx.BaseIndent = int(load(ctxptr, code.Length))
|
||||
restoreIndent(ctx, code, ctxptr)
|
||||
offset := load(ctxptr, code.Idx)
|
||||
ctx.SeenPtr = ctx.SeenPtr[:len(ctx.SeenPtr)-1]
|
||||
|
||||
|
@ -1382,7 +1301,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
}
|
||||
b = appendStructKey(ctx, code, b)
|
||||
if code.Indirect {
|
||||
p = ptrToNPtr(p, code.PtrNum)
|
||||
p = ptrToNPtr(p+code.Offset, code.PtrNum)
|
||||
}
|
||||
if p == 0 {
|
||||
b = appendNull(b)
|
||||
|
@ -1562,12 +1481,12 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
b = appendStructHead(b)
|
||||
}
|
||||
v := ptrToFloat64(p + code.Offset)
|
||||
if math.IsInf(v, 0) || math.IsNaN(v) {
|
||||
return nil, errUnsupportedFloat(v)
|
||||
}
|
||||
if v == 0 {
|
||||
code = code.NextField
|
||||
} else {
|
||||
if math.IsInf(v, 0) || math.IsNaN(v) {
|
||||
return nil, errUnsupportedFloat(v)
|
||||
}
|
||||
b = appendStructKey(ctx, code, b)
|
||||
b = appendFloat64(b, v)
|
||||
b = appendComma(b)
|
||||
|
@ -1600,12 +1519,12 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
if !code.AnonymousHead {
|
||||
b = appendStructHead(b)
|
||||
}
|
||||
b = appendStructKey(ctx, code, b)
|
||||
b = append(b, '"')
|
||||
v := ptrToFloat64(p + code.Offset)
|
||||
if math.IsInf(v, 0) || math.IsNaN(v) {
|
||||
return nil, errUnsupportedFloat(v)
|
||||
}
|
||||
b = appendStructKey(ctx, code, b)
|
||||
b = append(b, '"')
|
||||
b = appendFloat64(b, v)
|
||||
b = append(b, '"')
|
||||
b = appendComma(b)
|
||||
|
@ -1638,12 +1557,12 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
b = appendStructHead(b)
|
||||
}
|
||||
v := ptrToFloat64(p + code.Offset)
|
||||
if math.IsInf(v, 0) || math.IsNaN(v) {
|
||||
return nil, errUnsupportedFloat(v)
|
||||
}
|
||||
if v == 0 {
|
||||
code = code.NextField
|
||||
} else {
|
||||
if math.IsInf(v, 0) || math.IsNaN(v) {
|
||||
return nil, errUnsupportedFloat(v)
|
||||
}
|
||||
b = appendStructKey(ctx, code, b)
|
||||
b = append(b, '"')
|
||||
b = appendFloat64(b, v)
|
||||
|
@ -1906,8 +1825,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
b = appendStructHead(b)
|
||||
}
|
||||
b = appendStructKey(ctx, code, b)
|
||||
v := ptrToString(p + code.Offset)
|
||||
b = appendString(b, string(appendString([]byte{}, v)))
|
||||
b = appendString(b, string(appendString([]byte{}, ptrToString(p+code.Offset))))
|
||||
b = appendComma(b)
|
||||
code = code.Next
|
||||
case encoder.OpStructPtrHeadOmitEmptyStringString:
|
||||
|
@ -2251,12 +2169,12 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
}
|
||||
b = appendStructKey(ctx, code, b)
|
||||
if code.Indirect {
|
||||
p = ptrToNPtr(p, code.PtrNum)
|
||||
p = ptrToNPtr(p+code.Offset, code.PtrNum)
|
||||
}
|
||||
if p == 0 {
|
||||
b = appendNull(b)
|
||||
} else {
|
||||
b = appendBool(b, ptrToBool(p+code.Offset))
|
||||
b = appendBool(b, ptrToBool(p))
|
||||
}
|
||||
b = appendComma(b)
|
||||
code = code.Next
|
||||
|
@ -3778,13 +3696,15 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
b = appendStructKey(ctx, code, b)
|
||||
if p == 0 {
|
||||
b = appendNull(b)
|
||||
} else {
|
||||
v := ptrToFloat64(p)
|
||||
if math.IsInf(v, 0) || math.IsNaN(v) {
|
||||
return nil, errUnsupportedFloat(v)
|
||||
}
|
||||
b = appendFloat64(b, v)
|
||||
b = appendComma(b)
|
||||
code = code.Next
|
||||
break
|
||||
}
|
||||
v := ptrToFloat64(p)
|
||||
if math.IsInf(v, 0) || math.IsNaN(v) {
|
||||
return nil, errUnsupportedFloat(v)
|
||||
}
|
||||
b = appendFloat64(b, v)
|
||||
b = appendComma(b)
|
||||
code = code.Next
|
||||
case encoder.OpStructFieldOmitEmptyFloat64Ptr:
|
||||
|
@ -3807,11 +3727,11 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
if p == 0 {
|
||||
b = appendNull(b)
|
||||
} else {
|
||||
b = append(b, '"')
|
||||
v := ptrToFloat64(p)
|
||||
if math.IsInf(v, 0) || math.IsNaN(v) {
|
||||
return nil, errUnsupportedFloat(v)
|
||||
}
|
||||
b = append(b, '"')
|
||||
b = appendFloat64(b, v)
|
||||
b = append(b, '"')
|
||||
}
|
||||
|
@ -4348,9 +4268,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
code = code.NextField
|
||||
}
|
||||
case encoder.OpStructFieldStruct:
|
||||
b = appendStructKey(ctx, code, b)
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
p += code.Offset
|
||||
b = appendStructKey(ctx, code, b)
|
||||
code = code.Next
|
||||
store(ctxptr, code.Idx, p)
|
||||
case encoder.OpStructFieldOmitEmptyStruct:
|
||||
|
@ -4366,25 +4286,11 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
case encoder.OpStructAnonymousEnd:
|
||||
code = code.Next
|
||||
case encoder.OpStructEnd:
|
||||
last := len(b) - 1
|
||||
if b[last-1] == '{' {
|
||||
b[last] = '}'
|
||||
b = appendComma(b)
|
||||
code = code.Next
|
||||
break
|
||||
}
|
||||
if b[last] == '\n' {
|
||||
// to remove ',' and '\n' characters
|
||||
b = b[:len(b)-2]
|
||||
}
|
||||
b = append(b, '\n')
|
||||
b = appendIndent(ctx, b, code.Indent)
|
||||
b = append(b, '}')
|
||||
b = appendComma(b)
|
||||
b = appendStructEndSkipLast(ctx, code, b)
|
||||
code = code.Next
|
||||
case encoder.OpStructEndInt:
|
||||
b = appendStructKey(ctx, code, b)
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
b = appendStructKey(ctx, code, b)
|
||||
b = appendInt(b, ptrToUint64(p+code.Offset), code)
|
||||
b = appendStructEnd(ctx, code, b)
|
||||
code = code.Next
|
||||
|
@ -4471,8 +4377,8 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
}
|
||||
code = code.Next
|
||||
case encoder.OpStructEndUint:
|
||||
b = appendStructKey(ctx, code, b)
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
b = appendStructKey(ctx, code, b)
|
||||
b = appendUint(b, ptrToUint64(p+code.Offset), code)
|
||||
b = appendStructEnd(ctx, code, b)
|
||||
code = code.Next
|
||||
|
@ -4559,8 +4465,8 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
}
|
||||
code = code.Next
|
||||
case encoder.OpStructEndFloat32:
|
||||
b = appendStructKey(ctx, code, b)
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
b = appendStructKey(ctx, code, b)
|
||||
b = appendFloat32(b, ptrToFloat32(p+code.Offset))
|
||||
b = appendStructEnd(ctx, code, b)
|
||||
code = code.Next
|
||||
|
@ -4645,12 +4551,12 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
}
|
||||
code = code.Next
|
||||
case encoder.OpStructEndFloat64:
|
||||
b = appendStructKey(ctx, code, b)
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
v := ptrToFloat64(p + code.Offset)
|
||||
if math.IsInf(v, 0) || math.IsNaN(v) {
|
||||
return nil, errUnsupportedFloat(v)
|
||||
}
|
||||
b = appendStructKey(ctx, code, b)
|
||||
b = appendFloat64(b, v)
|
||||
b = appendStructEnd(ctx, code, b)
|
||||
code = code.Next
|
||||
|
@ -4658,10 +4564,10 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
p := load(ctxptr, code.HeadIdx)
|
||||
v := ptrToFloat64(p + code.Offset)
|
||||
if v != 0 {
|
||||
b = appendStructKey(ctx, code, b)
|
||||
if math.IsInf(v, 0) || math.IsNaN(v) {
|
||||
return nil, errUnsupportedFloat(v)
|
||||
}
|
||||
b = appendStructKey(ctx, code, b)
|
||||
b = appendFloat64(b, v)
|
||||
b = appendStructEnd(ctx, code, b)
|
||||
} else {
|
||||
|
@ -4684,11 +4590,11 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
p := load(ctxptr, code.HeadIdx)
|
||||
v := ptrToFloat64(p + code.Offset)
|
||||
if v != 0 {
|
||||
b = appendStructKey(ctx, code, b)
|
||||
b = append(b, '"')
|
||||
if math.IsInf(v, 0) || math.IsNaN(v) {
|
||||
return nil, errUnsupportedFloat(v)
|
||||
}
|
||||
b = appendStructKey(ctx, code, b)
|
||||
b = append(b, '"')
|
||||
b = appendFloat64(b, v)
|
||||
b = append(b, '"')
|
||||
b = appendStructEnd(ctx, code, b)
|
||||
|
@ -4702,13 +4608,15 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
p = ptrToNPtr(p+code.Offset, code.PtrNum)
|
||||
if p == 0 {
|
||||
b = appendNull(b)
|
||||
} else {
|
||||
v := ptrToFloat64(p)
|
||||
if math.IsInf(v, 0) || math.IsNaN(v) {
|
||||
return nil, errUnsupportedFloat(v)
|
||||
}
|
||||
b = appendFloat64(b, v)
|
||||
b = appendStructEnd(ctx, code, b)
|
||||
code = code.Next
|
||||
break
|
||||
}
|
||||
v := ptrToFloat64(p)
|
||||
if math.IsInf(v, 0) || math.IsNaN(v) {
|
||||
return nil, errUnsupportedFloat(v)
|
||||
}
|
||||
b = appendFloat64(b, v)
|
||||
b = appendStructEnd(ctx, code, b)
|
||||
code = code.Next
|
||||
case encoder.OpStructEndOmitEmptyFloat64Ptr:
|
||||
|
@ -4748,11 +4656,11 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
p = ptrToNPtr(p+code.Offset, code.PtrNum)
|
||||
if p != 0 {
|
||||
b = appendStructKey(ctx, code, b)
|
||||
b = append(b, '"')
|
||||
v := ptrToFloat64(p)
|
||||
if math.IsInf(v, 0) || math.IsNaN(v) {
|
||||
return nil, errUnsupportedFloat(v)
|
||||
}
|
||||
b = append(b, '"')
|
||||
b = appendFloat64(b, v)
|
||||
b = append(b, '"')
|
||||
b = appendStructEnd(ctx, code, b)
|
||||
|
@ -4761,8 +4669,8 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
}
|
||||
code = code.Next
|
||||
case encoder.OpStructEndString:
|
||||
b = appendStructKey(ctx, code, b)
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
b = appendStructKey(ctx, code, b)
|
||||
b = appendString(b, ptrToString(p+code.Offset))
|
||||
b = appendStructEnd(ctx, code, b)
|
||||
code = code.Next
|
||||
|
@ -4840,8 +4748,8 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
}
|
||||
code = code.Next
|
||||
case encoder.OpStructEndBool:
|
||||
b = appendStructKey(ctx, code, b)
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
b = appendStructKey(ctx, code, b)
|
||||
b = appendBool(b, ptrToBool(p+code.Offset))
|
||||
b = appendStructEnd(ctx, code, b)
|
||||
code = code.Next
|
||||
|
@ -4926,8 +4834,8 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
}
|
||||
code = code.Next
|
||||
case encoder.OpStructEndBytes:
|
||||
b = appendStructKey(ctx, code, b)
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
b = appendStructKey(ctx, code, b)
|
||||
b = appendByteSlice(b, ptrToBytes(p+code.Offset))
|
||||
b = appendStructEnd(ctx, code, b)
|
||||
code = code.Next
|
||||
|
@ -4965,8 +4873,8 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
}
|
||||
code = code.Next
|
||||
case encoder.OpStructEndNumber:
|
||||
b = appendStructKey(ctx, code, b)
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
b = appendStructKey(ctx, code, b)
|
||||
bb, err := appendNumber(b, ptrToNumber(p+code.Offset))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -4988,9 +4896,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
|||
}
|
||||
code = code.Next
|
||||
case encoder.OpStructEndNumberString:
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
b = appendStructKey(ctx, code, b)
|
||||
b = append(b, '"')
|
||||
p := load(ctxptr, code.HeadIdx)
|
||||
bb, err := appendNumber(b, ptrToNumber(p+code.Offset))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
Loading…
Reference in New Issue