diff --git a/internal/encoder/compiler.go b/internal/encoder/compiler.go index 128ec48..486c80f 100644 --- a/internal/encoder/compiler.go +++ b/internal/encoder/compiler.go @@ -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{ diff --git a/internal/encoder/encoder.go b/internal/encoder/encoder.go index b0cab28..ef6b910 100644 --- a/internal/encoder/encoder.go +++ b/internal/encoder/encoder.go @@ -390,7 +390,7 @@ func AppendMarshalJSON(ctx *RuntimeContext, code *Opcode, b []byte, v interface{ return compactedBuf, nil } -func AppendMarshalJSONIndent(ctx *RuntimeContext, code *Opcode, b []byte, v interface{}, indent int, escape bool) ([]byte, error) { +func AppendMarshalJSONIndent(ctx *RuntimeContext, code *Opcode, b []byte, v interface{}, escape bool) ([]byte, error) { rv := reflect.ValueOf(v) // convert by dynamic interface type if code.AddrForMarshaler { if rv.CanAddr() { @@ -415,7 +415,7 @@ func AppendMarshalJSONIndent(ctx *RuntimeContext, code *Opcode, b []byte, v inte indentedBuf, err := doIndent( b, marshalBuf, - string(ctx.Prefix)+strings.Repeat(string(ctx.IndentStr), ctx.BaseIndent+indent), + string(ctx.Prefix)+strings.Repeat(string(ctx.IndentStr), ctx.BaseIndent+code.Indent), string(ctx.IndentStr), escape, ) @@ -494,10 +494,10 @@ func AppendStructEnd(b []byte) []byte { return append(b, '}', ',') } -func AppendStructEndIndent(ctx *RuntimeContext, b []byte, indent int) []byte { +func AppendStructEndIndent(ctx *RuntimeContext, code *Opcode, b []byte) []byte { b = append(b, '\n') b = append(b, ctx.Prefix...) - indentNum := ctx.BaseIndent + indent + indentNum := ctx.BaseIndent + code.Indent - 1 for i := 0; i < indentNum; i++ { b = append(b, ctx.IndentStr...) } diff --git a/internal/encoder/vm/hack.go b/internal/encoder/vm/hack.go new file mode 100644 index 0000000..2c1918d --- /dev/null +++ b/internal/encoder/vm/hack.go @@ -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" +) diff --git a/internal/encoder/vm/util.go b/internal/encoder/vm/util.go index f8c9c07..01e608f 100644 --- a/internal/encoder/vm/util.go +++ b/internal/encoder/vm/util.go @@ -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,23 +105,111 @@ func appendComma(b []byte) []byte { return append(b, ',') } -func appendStructKey(_ *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte { - return append(b, code.Key...) +func appendColon(b []byte) []byte { + last := len(b) - 1 + b[last] = ':' + return b +} + +func appendMapKeyValue(_ *encoder.RuntimeContext, _ *encoder.Opcode, b, key, value []byte) []byte { + b = append(b, key...) + b[len(b)-1] = ':' + return append(b, value...) +} + +func appendMapEnd(_ *encoder.RuntimeContext, _ *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, _ *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) +} + +func appendMarshalText(code *encoder.Opcode, b []byte, v interface{}) ([]byte, error) { + return encoder.AppendMarshalText(code, b, v, false) +} + +func appendArrayHead(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte { + return append(b, '[') +} + +func appendArrayEnd(_ *encoder.RuntimeContext, _ *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 appendStructEnd(b []byte) []byte { +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, '}', ',') } -func appendStructEndSkipLast(b []byte) []byte { +func appendStructEndSkipLast(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte { last := len(b) - 1 if b[last] == ',' { b[last] = '}' return appendComma(b) } - return appendStructEnd(b) + return appendStructEnd(ctx, code, b) } + +func restoreIndent(_ *encoder.RuntimeContext, _ *encoder.Opcode, _ uintptr) {} +func storeIndent(_ uintptr, _ *encoder.Opcode, _ uintptr) {} +func appendMapKeyIndent(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte { return b } +func appendArrayElemIndent(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte { return b } diff --git a/internal/encoder/vm/vm.go b/internal/encoder/vm/vm.go index 0214598..dca1a99 100644 --- a/internal/encoder/vm/vm.go +++ b/internal/encoder/vm/vm.go @@ -1,47 +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 - appendMarshalJSON = encoder.AppendMarshalJSON - appendMarshalText = encoder.AppendMarshalText - 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: opcode %s has not been implemented", code.Op) + return nil, errUnimplementedOp(code.Op) case encoder.OpPtr: p := load(ctxptr, code.Idx) code = code.Next @@ -123,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) @@ -218,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] @@ -273,7 +214,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if code.IsNilableType && code.Indirect { p = ptrToPtr(p) } - bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), false) + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -300,7 +241,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if code.IsNilableType && code.Indirect { p = ptrToPtr(p) } - bb, err := appendMarshalText(code, b, ptrToInterface(code, p), false) + bb, err := appendMarshalText(code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -329,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: @@ -341,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: @@ -371,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: @@ -415,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) @@ -430,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)) @@ -440,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 { @@ -469,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)) @@ -505,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 @@ -541,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 { @@ -551,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] @@ -589,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 @@ -1885,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: @@ -2406,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 } @@ -3147,7 +3086,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p == 0 && code.Nilcheck { b = appendNull(b) } else { - bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), false) + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -3192,7 +3131,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt code = code.NextField } else { b = appendStructKey(ctx, code, b) - bb, err := appendMarshalJSON(ctx, code, b, iface, false) + bb, err := appendMarshalJSON(ctx, code, b, iface) if err != nil { return nil, err } @@ -3232,7 +3171,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p == 0 { b = appendNull(b) } else { - bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), false) + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -3272,7 +3211,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt code = code.NextField } else { b = appendStructKey(ctx, code, b) - bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), false) + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -3316,7 +3255,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p == 0 && code.Nilcheck { b = appendNull(b) } else { - bb, err := appendMarshalText(code, b, ptrToInterface(code, p), false) + bb, err := appendMarshalText(code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -3360,7 +3299,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt code = code.NextField } else { b = appendStructKey(ctx, code, b) - bb, err := appendMarshalText(code, b, ptrToInterface(code, p), false) + bb, err := appendMarshalText(code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -3400,7 +3339,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p == 0 { b = appendNull(b) } else { - bb, err := appendMarshalText(code, b, ptrToInterface(code, p), false) + bb, err := appendMarshalText(code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -3440,7 +3379,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt code = code.NextField } else { b = appendStructKey(ctx, code, b) - bb, err := appendMarshalText(code, b, ptrToInterface(code, p), false) + bb, err := appendMarshalText(code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -3502,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 { @@ -3582,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 { @@ -3660,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 { @@ -3752,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) @@ -3830,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 @@ -3845,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 { @@ -3865,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 { @@ -3919,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 { @@ -3939,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 { @@ -3978,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 { @@ -4044,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 { @@ -4071,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 { @@ -4110,7 +4049,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p == 0 && code.Nilcheck { b = appendNull(b) } else { - bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), false) + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -4134,7 +4073,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt break } b = appendStructKey(ctx, code, b) - bb, err := appendMarshalJSON(ctx, code, b, iface, false) + bb, err := appendMarshalJSON(ctx, code, b, iface) if err != nil { return nil, err } @@ -4147,7 +4086,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p == 0 { b = appendNull(b) } else { - bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), false) + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -4160,7 +4099,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) - bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), false) + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -4177,7 +4116,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p == 0 && code.Nilcheck { b = appendNull(b) } else { - bb, err := appendMarshalText(code, b, ptrToInterface(code, p), false) + bb, err := appendMarshalText(code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -4196,7 +4135,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt break } b = appendStructKey(ctx, code, b) - bb, err := appendMarshalText(code, b, ptrToInterface(code, p), false) + bb, err := appendMarshalText(code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -4209,7 +4148,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p == 0 { b = appendNull(b) } else { - bb, err := appendMarshalText(code, b, ptrToInterface(code, p), false) + bb, err := appendMarshalText(code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -4222,7 +4161,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) - bb, err := appendMarshalText(code, b, ptrToInterface(code, p), false) + bb, err := appendMarshalText(code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -4236,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: @@ -4334,22 +4273,26 @@ 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) b = appendInt(b, ptrToUint64(p+code.Offset), code) - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyInt: p := load(ctxptr, code.HeadIdx) @@ -4358,9 +4301,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if v != 0 { b = appendStructKey(ctx, code, b) b = appendInt(b, u64, code) - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndIntString: @@ -4369,7 +4312,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '"') b = appendInt(b, ptrToUint64(p+code.Offset), code) b = append(b, '"') - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyIntString: p := load(ctxptr, code.HeadIdx) @@ -4380,9 +4323,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '"') b = appendInt(b, u64, code) b = append(b, '"') - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndIntPtr: @@ -4394,7 +4337,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt } else { b = appendInt(b, ptrToUint64(p), code) } - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyIntPtr: p := load(ctxptr, code.HeadIdx) @@ -4402,9 +4345,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p != 0 { b = appendStructKey(ctx, code, b) b = appendInt(b, ptrToUint64(p), code) - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndIntPtrString: @@ -4418,7 +4361,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = appendInt(b, ptrToUint64(p), code) b = append(b, '"') } - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyIntPtrString: p := load(ctxptr, code.HeadIdx) @@ -4428,16 +4371,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '"') b = appendInt(b, ptrToUint64(p), code) b = append(b, '"') - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndUint: p := load(ctxptr, code.HeadIdx) b = appendStructKey(ctx, code, b) b = appendUint(b, ptrToUint64(p+code.Offset), code) - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyUint: p := load(ctxptr, code.HeadIdx) @@ -4446,9 +4389,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if v != 0 { b = appendStructKey(ctx, code, b) b = appendUint(b, u64, code) - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndUintString: @@ -4457,7 +4400,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '"') b = appendUint(b, ptrToUint64(p+code.Offset), code) b = append(b, '"') - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyUintString: p := load(ctxptr, code.HeadIdx) @@ -4468,9 +4411,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '"') b = appendUint(b, u64, code) b = append(b, '"') - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndUintPtr: @@ -4482,7 +4425,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt } else { b = appendUint(b, ptrToUint64(p), code) } - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyUintPtr: p := load(ctxptr, code.HeadIdx) @@ -4490,9 +4433,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p != 0 { b = appendStructKey(ctx, code, b) b = appendUint(b, ptrToUint64(p), code) - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndUintPtrString: @@ -4506,7 +4449,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = appendUint(b, ptrToUint64(p), code) b = append(b, '"') } - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyUintPtrString: p := load(ctxptr, code.HeadIdx) @@ -4516,16 +4459,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '"') b = appendUint(b, ptrToUint64(p), code) b = append(b, '"') - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndFloat32: p := load(ctxptr, code.HeadIdx) b = appendStructKey(ctx, code, b) b = appendFloat32(b, ptrToFloat32(p+code.Offset)) - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyFloat32: p := load(ctxptr, code.HeadIdx) @@ -4533,9 +4476,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if v != 0 { b = appendStructKey(ctx, code, b) b = appendFloat32(b, v) - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndFloat32String: @@ -4544,7 +4487,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '"') b = appendFloat32(b, ptrToFloat32(p+code.Offset)) b = append(b, '"') - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyFloat32String: p := load(ctxptr, code.HeadIdx) @@ -4554,9 +4497,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '"') b = appendFloat32(b, v) b = append(b, '"') - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndFloat32Ptr: @@ -4568,7 +4511,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt } else { b = appendFloat32(b, ptrToFloat32(p)) } - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyFloat32Ptr: p := load(ctxptr, code.HeadIdx) @@ -4576,9 +4519,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p != 0 { b = appendStructKey(ctx, code, b) b = appendFloat32(b, ptrToFloat32(p)) - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndFloat32PtrString: @@ -4592,7 +4535,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = appendFloat32(b, ptrToFloat32(p)) b = append(b, '"') } - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyFloat32PtrString: p := load(ctxptr, code.HeadIdx) @@ -4602,20 +4545,20 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '"') b = appendFloat32(b, ptrToFloat32(p)) b = append(b, '"') - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } 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(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyFloat64: p := load(ctxptr, code.HeadIdx) @@ -4626,9 +4569,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt } b = appendStructKey(ctx, code, b) b = appendFloat64(b, v) - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndFloat64String: @@ -4641,7 +4584,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '"') b = appendFloat64(b, v) b = append(b, '"') - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyFloat64String: p := load(ctxptr, code.HeadIdx) @@ -4654,9 +4597,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '"') b = appendFloat64(b, v) b = append(b, '"') - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndFloat64Ptr: @@ -4665,7 +4608,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt p = ptrToNPtr(p+code.Offset, code.PtrNum) if p == 0 { b = appendNull(b) - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next break } @@ -4674,7 +4617,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt return nil, errUnsupportedFloat(v) } b = appendFloat64(b, v) - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyFloat64Ptr: p := load(ctxptr, code.HeadIdx) @@ -4686,9 +4629,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt return nil, errUnsupportedFloat(v) } b = appendFloat64(b, v) - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndFloat64PtrString: @@ -4706,7 +4649,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = appendFloat64(b, v) b = append(b, '"') } - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyFloat64PtrString: p := load(ctxptr, code.HeadIdx) @@ -4720,16 +4663,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '"') b = appendFloat64(b, v) b = append(b, '"') - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndString: p := load(ctxptr, code.HeadIdx) b = appendStructKey(ctx, code, b) b = appendString(b, ptrToString(p+code.Offset)) - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyString: p := load(ctxptr, code.HeadIdx) @@ -4737,9 +4680,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if v != "" { b = appendStructKey(ctx, code, b) b = appendString(b, v) - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndStringString: @@ -4747,7 +4690,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = appendStructKey(ctx, code, b) s := ptrToString(p + code.Offset) b = appendString(b, string(appendString([]byte{}, s))) - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyStringString: p := load(ctxptr, code.HeadIdx) @@ -4755,9 +4698,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if v != "" { b = appendStructKey(ctx, code, b) b = appendString(b, string(appendString([]byte{}, v))) - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndStringPtr: @@ -4769,7 +4712,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt } else { b = appendString(b, ptrToString(p)) } - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyStringPtr: p := load(ctxptr, code.HeadIdx) @@ -4777,9 +4720,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p != 0 { b = appendStructKey(ctx, code, b) b = appendString(b, ptrToString(p)) - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndStringPtrString: @@ -4789,28 +4732,26 @@ 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(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyStringPtrString: p := load(ctxptr, code.HeadIdx) 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 = appendStructEnd(b) + b = appendString(b, string(appendString([]byte{}, ptrToString(p)))) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndBool: p := load(ctxptr, code.HeadIdx) b = appendStructKey(ctx, code, b) b = appendBool(b, ptrToBool(p+code.Offset)) - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyBool: p := load(ctxptr, code.HeadIdx) @@ -4818,9 +4759,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if v { b = appendStructKey(ctx, code, b) b = appendBool(b, v) - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndBoolString: @@ -4829,7 +4770,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '"') b = appendBool(b, ptrToBool(p+code.Offset)) b = append(b, '"') - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyBoolString: p := load(ctxptr, code.HeadIdx) @@ -4839,9 +4780,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '"') b = appendBool(b, v) b = append(b, '"') - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndBoolPtr: @@ -4853,7 +4794,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt } else { b = appendBool(b, ptrToBool(p)) } - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyBoolPtr: p := load(ctxptr, code.HeadIdx) @@ -4861,9 +4802,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p != 0 { b = appendStructKey(ctx, code, b) b = appendBool(b, ptrToBool(p)) - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndBoolPtrString: @@ -4877,7 +4818,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = appendBool(b, ptrToBool(p)) b = append(b, '"') } - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyBoolPtrString: p := load(ctxptr, code.HeadIdx) @@ -4887,16 +4828,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '"') b = appendBool(b, ptrToBool(p)) b = append(b, '"') - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndBytes: p := load(ctxptr, code.HeadIdx) b = appendStructKey(ctx, code, b) b = appendByteSlice(b, ptrToBytes(p+code.Offset)) - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyBytes: p := load(ctxptr, code.HeadIdx) @@ -4904,9 +4845,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if len(v) > 0 { b = appendStructKey(ctx, code, b) b = appendByteSlice(b, v) - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndBytesPtr: @@ -4918,7 +4859,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt } else { b = appendByteSlice(b, ptrToBytes(p)) } - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyBytesPtr: p := load(ctxptr, code.HeadIdx) @@ -4926,9 +4867,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p != 0 { b = appendStructKey(ctx, code, b) b = appendByteSlice(b, ptrToBytes(p)) - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndNumber: @@ -4938,7 +4879,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if err != nil { return nil, err } - b = appendStructEnd(bb) + b = appendStructEnd(ctx, code, bb) code = code.Next case encoder.OpStructEndOmitEmptyNumber: p := load(ctxptr, code.HeadIdx) @@ -4949,9 +4890,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if err != nil { return nil, err } - b = appendStructEnd(bb) + b = appendStructEnd(ctx, code, bb) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndNumberString: @@ -4963,7 +4904,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt return nil, err } b = append(bb, '"') - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyNumberString: p := load(ctxptr, code.HeadIdx) @@ -4976,9 +4917,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt return nil, err } b = append(bb, '"') - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndNumberPtr: @@ -4994,7 +4935,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt } b = bb } - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyNumberPtr: p := load(ctxptr, code.HeadIdx) @@ -5005,9 +4946,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if err != nil { return nil, err } - b = appendStructEnd(bb) + b = appendStructEnd(ctx, code, bb) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndNumberPtrString: @@ -5024,7 +4965,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt } b = append(bb, '"') } - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyNumberPtrString: p := load(ctxptr, code.HeadIdx) @@ -5037,9 +4978,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt return nil, err } b = append(bb, '"') - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpEnd: diff --git a/internal/encoder/vm_debug/util.go b/internal/encoder/vm_debug/util.go index 94f8521..2fe1a9a 100644 --- a/internal/encoder/vm_debug/util.go +++ b/internal/encoder/vm_debug/util.go @@ -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,23 +105,111 @@ func appendComma(b []byte) []byte { return append(b, ',') } -func appendStructKey(_ *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte { - return append(b, code.Key...) +func appendColon(b []byte) []byte { + last := len(b) - 1 + b[last] = ':' + return b +} + +func appendMapKeyValue(_ *encoder.RuntimeContext, _ *encoder.Opcode, b, key, value []byte) []byte { + b = append(b, key...) + b[len(b)-1] = ':' + return append(b, value...) +} + +func appendMapEnd(_ *encoder.RuntimeContext, _ *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, _ *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) +} + +func appendMarshalText(code *encoder.Opcode, b []byte, v interface{}) ([]byte, error) { + return encoder.AppendMarshalText(code, b, v, false) +} + +func appendArrayHead(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte { + return append(b, '[') +} + +func appendArrayEnd(_ *encoder.RuntimeContext, _ *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 appendStructEnd(b []byte) []byte { +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, '}', ',') } -func appendStructEndSkipLast(b []byte) []byte { +func appendStructEndSkipLast(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte { last := len(b) - 1 if b[last] == ',' { b[last] = '}' return appendComma(b) } - return appendStructEnd(b) + return appendStructEnd(ctx, code, b) } + +func restoreIndent(_ *encoder.RuntimeContext, _ *encoder.Opcode, _ uintptr) {} +func storeIndent(_ uintptr, _ *encoder.Opcode, _ uintptr) {} +func appendMapKeyIndent(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte { return b } +func appendArrayElemIndent(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte { return b } diff --git a/internal/encoder/vm_debug/vm.go b/internal/encoder/vm_debug/vm.go index ce6ec9f..4f344df 100644 --- a/internal/encoder/vm_debug/vm.go +++ b/internal/encoder/vm_debug/vm.go @@ -7,35 +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 - appendMarshalJSON = encoder.AppendMarshalJSON - appendMarshalText = encoder.AppendMarshalText - 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) @@ -64,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 @@ -136,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) @@ -231,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] @@ -286,7 +234,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if code.IsNilableType && code.Indirect { p = ptrToPtr(p) } - bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), false) + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -313,7 +261,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if code.IsNilableType && code.Indirect { p = ptrToPtr(p) } - bb, err := appendMarshalText(code, b, ptrToInterface(code, p), false) + bb, err := appendMarshalText(code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -342,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: @@ -354,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: @@ -384,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: @@ -428,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) @@ -443,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)) @@ -453,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 { @@ -482,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)) @@ -518,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 @@ -554,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 { @@ -564,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] @@ -602,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 @@ -1898,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: @@ -2419,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 } @@ -3160,7 +3106,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p == 0 && code.Nilcheck { b = appendNull(b) } else { - bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), false) + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -3205,7 +3151,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt code = code.NextField } else { b = appendStructKey(ctx, code, b) - bb, err := appendMarshalJSON(ctx, code, b, iface, false) + bb, err := appendMarshalJSON(ctx, code, b, iface) if err != nil { return nil, err } @@ -3245,7 +3191,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p == 0 { b = appendNull(b) } else { - bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), false) + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -3285,7 +3231,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt code = code.NextField } else { b = appendStructKey(ctx, code, b) - bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), false) + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -3329,7 +3275,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p == 0 && code.Nilcheck { b = appendNull(b) } else { - bb, err := appendMarshalText(code, b, ptrToInterface(code, p), false) + bb, err := appendMarshalText(code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -3373,7 +3319,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt code = code.NextField } else { b = appendStructKey(ctx, code, b) - bb, err := appendMarshalText(code, b, ptrToInterface(code, p), false) + bb, err := appendMarshalText(code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -3413,7 +3359,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p == 0 { b = appendNull(b) } else { - bb, err := appendMarshalText(code, b, ptrToInterface(code, p), false) + bb, err := appendMarshalText(code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -3453,7 +3399,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt code = code.NextField } else { b = appendStructKey(ctx, code, b) - bb, err := appendMarshalText(code, b, ptrToInterface(code, p), false) + bb, err := appendMarshalText(code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -3515,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 { @@ -3595,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 { @@ -3673,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 { @@ -3765,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) @@ -3843,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 @@ -3858,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 { @@ -3878,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 { @@ -3932,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 { @@ -3952,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 { @@ -3991,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 { @@ -4057,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 { @@ -4084,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 { @@ -4123,7 +4069,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p == 0 && code.Nilcheck { b = appendNull(b) } else { - bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), false) + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -4147,7 +4093,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt break } b = appendStructKey(ctx, code, b) - bb, err := appendMarshalJSON(ctx, code, b, iface, false) + bb, err := appendMarshalJSON(ctx, code, b, iface) if err != nil { return nil, err } @@ -4160,7 +4106,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p == 0 { b = appendNull(b) } else { - bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), false) + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -4173,7 +4119,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) - bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), false) + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -4190,7 +4136,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p == 0 && code.Nilcheck { b = appendNull(b) } else { - bb, err := appendMarshalText(code, b, ptrToInterface(code, p), false) + bb, err := appendMarshalText(code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -4209,7 +4155,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt break } b = appendStructKey(ctx, code, b) - bb, err := appendMarshalText(code, b, ptrToInterface(code, p), false) + bb, err := appendMarshalText(code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -4222,7 +4168,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p == 0 { b = appendNull(b) } else { - bb, err := appendMarshalText(code, b, ptrToInterface(code, p), false) + bb, err := appendMarshalText(code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -4235,7 +4181,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) - bb, err := appendMarshalText(code, b, ptrToInterface(code, p), false) + bb, err := appendMarshalText(code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -4249,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: @@ -4347,22 +4293,26 @@ 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) b = appendInt(b, ptrToUint64(p+code.Offset), code) - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyInt: p := load(ctxptr, code.HeadIdx) @@ -4371,9 +4321,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if v != 0 { b = appendStructKey(ctx, code, b) b = appendInt(b, u64, code) - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndIntString: @@ -4382,7 +4332,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '"') b = appendInt(b, ptrToUint64(p+code.Offset), code) b = append(b, '"') - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyIntString: p := load(ctxptr, code.HeadIdx) @@ -4393,9 +4343,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '"') b = appendInt(b, u64, code) b = append(b, '"') - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndIntPtr: @@ -4407,7 +4357,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt } else { b = appendInt(b, ptrToUint64(p), code) } - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyIntPtr: p := load(ctxptr, code.HeadIdx) @@ -4415,9 +4365,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p != 0 { b = appendStructKey(ctx, code, b) b = appendInt(b, ptrToUint64(p), code) - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndIntPtrString: @@ -4431,7 +4381,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = appendInt(b, ptrToUint64(p), code) b = append(b, '"') } - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyIntPtrString: p := load(ctxptr, code.HeadIdx) @@ -4441,16 +4391,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '"') b = appendInt(b, ptrToUint64(p), code) b = append(b, '"') - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndUint: p := load(ctxptr, code.HeadIdx) b = appendStructKey(ctx, code, b) b = appendUint(b, ptrToUint64(p+code.Offset), code) - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyUint: p := load(ctxptr, code.HeadIdx) @@ -4459,9 +4409,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if v != 0 { b = appendStructKey(ctx, code, b) b = appendUint(b, u64, code) - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndUintString: @@ -4470,7 +4420,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '"') b = appendUint(b, ptrToUint64(p+code.Offset), code) b = append(b, '"') - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyUintString: p := load(ctxptr, code.HeadIdx) @@ -4481,9 +4431,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '"') b = appendUint(b, u64, code) b = append(b, '"') - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndUintPtr: @@ -4495,7 +4445,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt } else { b = appendUint(b, ptrToUint64(p), code) } - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyUintPtr: p := load(ctxptr, code.HeadIdx) @@ -4503,9 +4453,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p != 0 { b = appendStructKey(ctx, code, b) b = appendUint(b, ptrToUint64(p), code) - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndUintPtrString: @@ -4519,7 +4469,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = appendUint(b, ptrToUint64(p), code) b = append(b, '"') } - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyUintPtrString: p := load(ctxptr, code.HeadIdx) @@ -4529,16 +4479,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '"') b = appendUint(b, ptrToUint64(p), code) b = append(b, '"') - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndFloat32: p := load(ctxptr, code.HeadIdx) b = appendStructKey(ctx, code, b) b = appendFloat32(b, ptrToFloat32(p+code.Offset)) - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyFloat32: p := load(ctxptr, code.HeadIdx) @@ -4546,9 +4496,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if v != 0 { b = appendStructKey(ctx, code, b) b = appendFloat32(b, v) - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndFloat32String: @@ -4557,7 +4507,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '"') b = appendFloat32(b, ptrToFloat32(p+code.Offset)) b = append(b, '"') - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyFloat32String: p := load(ctxptr, code.HeadIdx) @@ -4567,9 +4517,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '"') b = appendFloat32(b, v) b = append(b, '"') - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndFloat32Ptr: @@ -4581,7 +4531,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt } else { b = appendFloat32(b, ptrToFloat32(p)) } - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyFloat32Ptr: p := load(ctxptr, code.HeadIdx) @@ -4589,9 +4539,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p != 0 { b = appendStructKey(ctx, code, b) b = appendFloat32(b, ptrToFloat32(p)) - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndFloat32PtrString: @@ -4605,7 +4555,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = appendFloat32(b, ptrToFloat32(p)) b = append(b, '"') } - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyFloat32PtrString: p := load(ctxptr, code.HeadIdx) @@ -4615,20 +4565,20 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '"') b = appendFloat32(b, ptrToFloat32(p)) b = append(b, '"') - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } 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(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyFloat64: p := load(ctxptr, code.HeadIdx) @@ -4639,9 +4589,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt } b = appendStructKey(ctx, code, b) b = appendFloat64(b, v) - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndFloat64String: @@ -4654,7 +4604,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '"') b = appendFloat64(b, v) b = append(b, '"') - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyFloat64String: p := load(ctxptr, code.HeadIdx) @@ -4667,9 +4617,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '"') b = appendFloat64(b, v) b = append(b, '"') - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndFloat64Ptr: @@ -4678,7 +4628,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt p = ptrToNPtr(p+code.Offset, code.PtrNum) if p == 0 { b = appendNull(b) - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next break } @@ -4687,7 +4637,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt return nil, errUnsupportedFloat(v) } b = appendFloat64(b, v) - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyFloat64Ptr: p := load(ctxptr, code.HeadIdx) @@ -4699,9 +4649,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt return nil, errUnsupportedFloat(v) } b = appendFloat64(b, v) - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndFloat64PtrString: @@ -4719,7 +4669,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = appendFloat64(b, v) b = append(b, '"') } - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyFloat64PtrString: p := load(ctxptr, code.HeadIdx) @@ -4733,16 +4683,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '"') b = appendFloat64(b, v) b = append(b, '"') - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndString: p := load(ctxptr, code.HeadIdx) b = appendStructKey(ctx, code, b) b = appendString(b, ptrToString(p+code.Offset)) - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyString: p := load(ctxptr, code.HeadIdx) @@ -4750,9 +4700,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if v != "" { b = appendStructKey(ctx, code, b) b = appendString(b, v) - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndStringString: @@ -4760,7 +4710,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = appendStructKey(ctx, code, b) s := ptrToString(p + code.Offset) b = appendString(b, string(appendString([]byte{}, s))) - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyStringString: p := load(ctxptr, code.HeadIdx) @@ -4768,9 +4718,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if v != "" { b = appendStructKey(ctx, code, b) b = appendString(b, string(appendString([]byte{}, v))) - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndStringPtr: @@ -4782,7 +4732,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt } else { b = appendString(b, ptrToString(p)) } - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyStringPtr: p := load(ctxptr, code.HeadIdx) @@ -4790,9 +4740,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p != 0 { b = appendStructKey(ctx, code, b) b = appendString(b, ptrToString(p)) - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndStringPtrString: @@ -4802,28 +4752,26 @@ 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(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyStringPtrString: p := load(ctxptr, code.HeadIdx) 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 = appendStructEnd(b) + b = appendString(b, string(appendString([]byte{}, ptrToString(p)))) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndBool: p := load(ctxptr, code.HeadIdx) b = appendStructKey(ctx, code, b) b = appendBool(b, ptrToBool(p+code.Offset)) - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyBool: p := load(ctxptr, code.HeadIdx) @@ -4831,9 +4779,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if v { b = appendStructKey(ctx, code, b) b = appendBool(b, v) - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndBoolString: @@ -4842,7 +4790,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '"') b = appendBool(b, ptrToBool(p+code.Offset)) b = append(b, '"') - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyBoolString: p := load(ctxptr, code.HeadIdx) @@ -4852,9 +4800,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '"') b = appendBool(b, v) b = append(b, '"') - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndBoolPtr: @@ -4866,7 +4814,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt } else { b = appendBool(b, ptrToBool(p)) } - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyBoolPtr: p := load(ctxptr, code.HeadIdx) @@ -4874,9 +4822,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p != 0 { b = appendStructKey(ctx, code, b) b = appendBool(b, ptrToBool(p)) - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndBoolPtrString: @@ -4890,7 +4838,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = appendBool(b, ptrToBool(p)) b = append(b, '"') } - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyBoolPtrString: p := load(ctxptr, code.HeadIdx) @@ -4900,16 +4848,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '"') b = appendBool(b, ptrToBool(p)) b = append(b, '"') - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndBytes: p := load(ctxptr, code.HeadIdx) b = appendStructKey(ctx, code, b) b = appendByteSlice(b, ptrToBytes(p+code.Offset)) - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyBytes: p := load(ctxptr, code.HeadIdx) @@ -4917,9 +4865,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if len(v) > 0 { b = appendStructKey(ctx, code, b) b = appendByteSlice(b, v) - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndBytesPtr: @@ -4931,7 +4879,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt } else { b = appendByteSlice(b, ptrToBytes(p)) } - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyBytesPtr: p := load(ctxptr, code.HeadIdx) @@ -4939,9 +4887,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p != 0 { b = appendStructKey(ctx, code, b) b = appendByteSlice(b, ptrToBytes(p)) - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndNumber: @@ -4951,7 +4899,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if err != nil { return nil, err } - b = appendStructEnd(bb) + b = appendStructEnd(ctx, code, bb) code = code.Next case encoder.OpStructEndOmitEmptyNumber: p := load(ctxptr, code.HeadIdx) @@ -4962,9 +4910,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if err != nil { return nil, err } - b = appendStructEnd(bb) + b = appendStructEnd(ctx, code, bb) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndNumberString: @@ -4976,7 +4924,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt return nil, err } b = append(bb, '"') - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyNumberString: p := load(ctxptr, code.HeadIdx) @@ -4989,9 +4937,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt return nil, err } b = append(bb, '"') - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndNumberPtr: @@ -5007,7 +4955,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt } b = bb } - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyNumberPtr: p := load(ctxptr, code.HeadIdx) @@ -5018,9 +4966,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if err != nil { return nil, err } - b = appendStructEnd(bb) + b = appendStructEnd(ctx, code, bb) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndNumberPtrString: @@ -5037,7 +4985,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt } b = append(bb, '"') } - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyNumberPtrString: p := load(ctxptr, code.HeadIdx) @@ -5050,9 +4998,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt return nil, err } b = append(bb, '"') - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpEnd: diff --git a/internal/encoder/vm_escaped/hack.go b/internal/encoder/vm_escaped/hack.go new file mode 100644 index 0000000..d6c1997 --- /dev/null +++ b/internal/encoder/vm_escaped/hack.go @@ -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" +) diff --git a/internal/encoder/vm_escaped/util.go b/internal/encoder/vm_escaped/util.go index 07765a7..129eb2c 100644 --- a/internal/encoder/vm_escaped/util.go +++ b/internal/encoder/vm_escaped/util.go @@ -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,89 @@ func appendComma(b []byte) []byte { return append(b, ',') } +func appendColon(b []byte) []byte { + last := len(b) - 1 + b[last] = ':' + return b +} + +func appendMapKeyValue(_ *encoder.RuntimeContext, _ *encoder.Opcode, b, key, value []byte) []byte { + b = append(b, key...) + b[len(b)-1] = ':' + return append(b, value...) +} + +func appendMapEnd(_ *encoder.RuntimeContext, _ *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, _ *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) +} + +func appendMarshalText(code *encoder.Opcode, b []byte, v interface{}) ([]byte, error) { + return encoder.AppendMarshalText(code, b, v, true) +} + +func appendArrayHead(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte { + return append(b, '[') +} + +func appendArrayEnd(_ *encoder.RuntimeContext, _ *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, '{') } @@ -84,15 +196,20 @@ func appendStructKey(_ *encoder.RuntimeContext, code *encoder.Opcode, b []byte) return append(b, code.EscapedKey...) } -func appendStructEnd(b []byte) []byte { +func appendStructEnd(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte { return append(b, '}', ',') } -func appendStructEndSkipLast(b []byte) []byte { +func appendStructEndSkipLast(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte { last := len(b) - 1 if b[last] == ',' { b[last] = '}' return appendComma(b) } - return appendStructEnd(b) + return appendStructEnd(ctx, code, b) } + +func restoreIndent(_ *encoder.RuntimeContext, _ *encoder.Opcode, _ uintptr) {} +func storeIndent(_ uintptr, _ *encoder.Opcode, _ uintptr) {} +func appendMapKeyIndent(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte { return b } +func appendArrayElemIndent(_ *encoder.RuntimeContext, _ *encoder.Opcode, b []byte) []byte { return b } diff --git a/internal/encoder/vm_escaped/vm.go b/internal/encoder/vm_escaped/vm.go index f65920f..891fa59 100644 --- a/internal/encoder/vm_escaped/vm.go +++ b/internal/encoder/vm_escaped/vm.go @@ -1,47 +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 - appendMarshalJSON = encoder.AppendMarshalJSON - appendMarshalText = encoder.AppendMarshalText - 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: opcode %s has not been implemented", code.Op) + return nil, errUnimplementedOp(code.Op) case encoder.OpPtr: p := load(ctxptr, code.Idx) code = code.Next @@ -123,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) @@ -218,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] @@ -273,7 +214,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if code.IsNilableType && code.Indirect { p = ptrToPtr(p) } - bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), true) + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -300,7 +241,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if code.IsNilableType && code.Indirect { p = ptrToPtr(p) } - bb, err := appendMarshalText(code, b, ptrToInterface(code, p), true) + bb, err := appendMarshalText(code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -329,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: @@ -341,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: @@ -371,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: @@ -415,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) @@ -430,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)) @@ -440,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 { @@ -469,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)) @@ -505,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 @@ -541,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 { @@ -551,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] @@ -589,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 @@ -1885,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: @@ -2406,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 } @@ -3147,7 +3086,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p == 0 && code.Nilcheck { b = appendNull(b) } else { - bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), true) + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -3192,7 +3131,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt code = code.NextField } else { b = appendStructKey(ctx, code, b) - bb, err := appendMarshalJSON(ctx, code, b, iface, true) + bb, err := appendMarshalJSON(ctx, code, b, iface) if err != nil { return nil, err } @@ -3232,7 +3171,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p == 0 { b = appendNull(b) } else { - bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), true) + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -3272,7 +3211,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt code = code.NextField } else { b = appendStructKey(ctx, code, b) - bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), true) + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -3316,7 +3255,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p == 0 && code.Nilcheck { b = appendNull(b) } else { - bb, err := appendMarshalText(code, b, ptrToInterface(code, p), true) + bb, err := appendMarshalText(code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -3360,7 +3299,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt code = code.NextField } else { b = appendStructKey(ctx, code, b) - bb, err := appendMarshalText(code, b, ptrToInterface(code, p), true) + bb, err := appendMarshalText(code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -3400,7 +3339,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p == 0 { b = appendNull(b) } else { - bb, err := appendMarshalText(code, b, ptrToInterface(code, p), true) + bb, err := appendMarshalText(code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -3440,7 +3379,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt code = code.NextField } else { b = appendStructKey(ctx, code, b) - bb, err := appendMarshalText(code, b, ptrToInterface(code, p), true) + bb, err := appendMarshalText(code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -3502,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 { @@ -3582,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 { @@ -3660,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 { @@ -3752,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) @@ -3830,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 @@ -3845,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 { @@ -3865,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 { @@ -3919,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 { @@ -3939,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 { @@ -3978,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 { @@ -4044,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 { @@ -4071,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 { @@ -4110,7 +4049,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p == 0 && code.Nilcheck { b = appendNull(b) } else { - bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), true) + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -4134,7 +4073,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt break } b = appendStructKey(ctx, code, b) - bb, err := appendMarshalJSON(ctx, code, b, iface, true) + bb, err := appendMarshalJSON(ctx, code, b, iface) if err != nil { return nil, err } @@ -4147,7 +4086,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p == 0 { b = appendNull(b) } else { - bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), true) + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -4160,7 +4099,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) - bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), true) + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -4177,7 +4116,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p == 0 && code.Nilcheck { b = appendNull(b) } else { - bb, err := appendMarshalText(code, b, ptrToInterface(code, p), true) + bb, err := appendMarshalText(code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -4196,7 +4135,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt break } b = appendStructKey(ctx, code, b) - bb, err := appendMarshalText(code, b, ptrToInterface(code, p), true) + bb, err := appendMarshalText(code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -4209,7 +4148,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p == 0 { b = appendNull(b) } else { - bb, err := appendMarshalText(code, b, ptrToInterface(code, p), true) + bb, err := appendMarshalText(code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -4222,7 +4161,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) - bb, err := appendMarshalText(code, b, ptrToInterface(code, p), true) + bb, err := appendMarshalText(code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -4236,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: @@ -4334,22 +4273,26 @@ 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) b = appendInt(b, ptrToUint64(p+code.Offset), code) - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyInt: p := load(ctxptr, code.HeadIdx) @@ -4358,9 +4301,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if v != 0 { b = appendStructKey(ctx, code, b) b = appendInt(b, u64, code) - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndIntString: @@ -4369,7 +4312,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '"') b = appendInt(b, ptrToUint64(p+code.Offset), code) b = append(b, '"') - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyIntString: p := load(ctxptr, code.HeadIdx) @@ -4380,9 +4323,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '"') b = appendInt(b, u64, code) b = append(b, '"') - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndIntPtr: @@ -4394,7 +4337,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt } else { b = appendInt(b, ptrToUint64(p), code) } - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyIntPtr: p := load(ctxptr, code.HeadIdx) @@ -4402,9 +4345,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p != 0 { b = appendStructKey(ctx, code, b) b = appendInt(b, ptrToUint64(p), code) - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndIntPtrString: @@ -4418,7 +4361,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = appendInt(b, ptrToUint64(p), code) b = append(b, '"') } - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyIntPtrString: p := load(ctxptr, code.HeadIdx) @@ -4428,16 +4371,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '"') b = appendInt(b, ptrToUint64(p), code) b = append(b, '"') - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndUint: p := load(ctxptr, code.HeadIdx) b = appendStructKey(ctx, code, b) b = appendUint(b, ptrToUint64(p+code.Offset), code) - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyUint: p := load(ctxptr, code.HeadIdx) @@ -4446,9 +4389,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if v != 0 { b = appendStructKey(ctx, code, b) b = appendUint(b, u64, code) - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndUintString: @@ -4457,7 +4400,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '"') b = appendUint(b, ptrToUint64(p+code.Offset), code) b = append(b, '"') - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyUintString: p := load(ctxptr, code.HeadIdx) @@ -4468,9 +4411,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '"') b = appendUint(b, u64, code) b = append(b, '"') - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndUintPtr: @@ -4482,7 +4425,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt } else { b = appendUint(b, ptrToUint64(p), code) } - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyUintPtr: p := load(ctxptr, code.HeadIdx) @@ -4490,9 +4433,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p != 0 { b = appendStructKey(ctx, code, b) b = appendUint(b, ptrToUint64(p), code) - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndUintPtrString: @@ -4506,7 +4449,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = appendUint(b, ptrToUint64(p), code) b = append(b, '"') } - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyUintPtrString: p := load(ctxptr, code.HeadIdx) @@ -4516,16 +4459,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '"') b = appendUint(b, ptrToUint64(p), code) b = append(b, '"') - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndFloat32: p := load(ctxptr, code.HeadIdx) b = appendStructKey(ctx, code, b) b = appendFloat32(b, ptrToFloat32(p+code.Offset)) - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyFloat32: p := load(ctxptr, code.HeadIdx) @@ -4533,9 +4476,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if v != 0 { b = appendStructKey(ctx, code, b) b = appendFloat32(b, v) - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndFloat32String: @@ -4544,7 +4487,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '"') b = appendFloat32(b, ptrToFloat32(p+code.Offset)) b = append(b, '"') - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyFloat32String: p := load(ctxptr, code.HeadIdx) @@ -4554,9 +4497,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '"') b = appendFloat32(b, v) b = append(b, '"') - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndFloat32Ptr: @@ -4568,7 +4511,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt } else { b = appendFloat32(b, ptrToFloat32(p)) } - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyFloat32Ptr: p := load(ctxptr, code.HeadIdx) @@ -4576,9 +4519,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p != 0 { b = appendStructKey(ctx, code, b) b = appendFloat32(b, ptrToFloat32(p)) - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndFloat32PtrString: @@ -4592,7 +4535,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = appendFloat32(b, ptrToFloat32(p)) b = append(b, '"') } - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyFloat32PtrString: p := load(ctxptr, code.HeadIdx) @@ -4602,20 +4545,20 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '"') b = appendFloat32(b, ptrToFloat32(p)) b = append(b, '"') - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } 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(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyFloat64: p := load(ctxptr, code.HeadIdx) @@ -4626,9 +4569,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt } b = appendStructKey(ctx, code, b) b = appendFloat64(b, v) - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndFloat64String: @@ -4641,7 +4584,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '"') b = appendFloat64(b, v) b = append(b, '"') - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyFloat64String: p := load(ctxptr, code.HeadIdx) @@ -4654,9 +4597,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '"') b = appendFloat64(b, v) b = append(b, '"') - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndFloat64Ptr: @@ -4665,7 +4608,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt p = ptrToNPtr(p+code.Offset, code.PtrNum) if p == 0 { b = appendNull(b) - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next break } @@ -4674,7 +4617,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt return nil, errUnsupportedFloat(v) } b = appendFloat64(b, v) - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyFloat64Ptr: p := load(ctxptr, code.HeadIdx) @@ -4686,9 +4629,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt return nil, errUnsupportedFloat(v) } b = appendFloat64(b, v) - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndFloat64PtrString: @@ -4706,7 +4649,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = appendFloat64(b, v) b = append(b, '"') } - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyFloat64PtrString: p := load(ctxptr, code.HeadIdx) @@ -4720,16 +4663,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '"') b = appendFloat64(b, v) b = append(b, '"') - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndString: p := load(ctxptr, code.HeadIdx) b = appendStructKey(ctx, code, b) b = appendString(b, ptrToString(p+code.Offset)) - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyString: p := load(ctxptr, code.HeadIdx) @@ -4737,9 +4680,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if v != "" { b = appendStructKey(ctx, code, b) b = appendString(b, v) - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndStringString: @@ -4747,7 +4690,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = appendStructKey(ctx, code, b) s := ptrToString(p + code.Offset) b = appendString(b, string(appendString([]byte{}, s))) - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyStringString: p := load(ctxptr, code.HeadIdx) @@ -4755,9 +4698,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if v != "" { b = appendStructKey(ctx, code, b) b = appendString(b, string(appendString([]byte{}, v))) - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndStringPtr: @@ -4769,7 +4712,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt } else { b = appendString(b, ptrToString(p)) } - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyStringPtr: p := load(ctxptr, code.HeadIdx) @@ -4777,9 +4720,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p != 0 { b = appendStructKey(ctx, code, b) b = appendString(b, ptrToString(p)) - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndStringPtrString: @@ -4789,28 +4732,26 @@ 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(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyStringPtrString: p := load(ctxptr, code.HeadIdx) 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 = appendStructEnd(b) + b = appendString(b, string(appendString([]byte{}, ptrToString(p)))) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndBool: p := load(ctxptr, code.HeadIdx) b = appendStructKey(ctx, code, b) b = appendBool(b, ptrToBool(p+code.Offset)) - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyBool: p := load(ctxptr, code.HeadIdx) @@ -4818,9 +4759,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if v { b = appendStructKey(ctx, code, b) b = appendBool(b, v) - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndBoolString: @@ -4829,7 +4770,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '"') b = appendBool(b, ptrToBool(p+code.Offset)) b = append(b, '"') - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyBoolString: p := load(ctxptr, code.HeadIdx) @@ -4839,9 +4780,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '"') b = appendBool(b, v) b = append(b, '"') - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndBoolPtr: @@ -4853,7 +4794,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt } else { b = appendBool(b, ptrToBool(p)) } - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyBoolPtr: p := load(ctxptr, code.HeadIdx) @@ -4861,9 +4802,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p != 0 { b = appendStructKey(ctx, code, b) b = appendBool(b, ptrToBool(p)) - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndBoolPtrString: @@ -4877,7 +4818,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = appendBool(b, ptrToBool(p)) b = append(b, '"') } - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyBoolPtrString: p := load(ctxptr, code.HeadIdx) @@ -4887,16 +4828,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '"') b = appendBool(b, ptrToBool(p)) b = append(b, '"') - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndBytes: p := load(ctxptr, code.HeadIdx) b = appendStructKey(ctx, code, b) b = appendByteSlice(b, ptrToBytes(p+code.Offset)) - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyBytes: p := load(ctxptr, code.HeadIdx) @@ -4904,9 +4845,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if len(v) > 0 { b = appendStructKey(ctx, code, b) b = appendByteSlice(b, v) - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndBytesPtr: @@ -4918,7 +4859,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt } else { b = appendByteSlice(b, ptrToBytes(p)) } - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyBytesPtr: p := load(ctxptr, code.HeadIdx) @@ -4926,9 +4867,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p != 0 { b = appendStructKey(ctx, code, b) b = appendByteSlice(b, ptrToBytes(p)) - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndNumber: @@ -4938,7 +4879,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if err != nil { return nil, err } - b = appendStructEnd(bb) + b = appendStructEnd(ctx, code, bb) code = code.Next case encoder.OpStructEndOmitEmptyNumber: p := load(ctxptr, code.HeadIdx) @@ -4949,9 +4890,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if err != nil { return nil, err } - b = appendStructEnd(bb) + b = appendStructEnd(ctx, code, bb) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndNumberString: @@ -4963,7 +4904,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt return nil, err } b = append(bb, '"') - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyNumberString: p := load(ctxptr, code.HeadIdx) @@ -4976,9 +4917,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt return nil, err } b = append(bb, '"') - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndNumberPtr: @@ -4994,7 +4935,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt } b = bb } - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyNumberPtr: p := load(ctxptr, code.HeadIdx) @@ -5005,9 +4946,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if err != nil { return nil, err } - b = appendStructEnd(bb) + b = appendStructEnd(ctx, code, bb) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndNumberPtrString: @@ -5024,7 +4965,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt } b = append(bb, '"') } - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyNumberPtrString: p := load(ctxptr, code.HeadIdx) @@ -5037,9 +4978,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt return nil, err } b = append(bb, '"') - b = appendStructEnd(b) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(b) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpEnd: diff --git a/internal/encoder/vm_escaped_indent/hack.go b/internal/encoder/vm_escaped_indent/hack.go new file mode 100644 index 0000000..a3672d9 --- /dev/null +++ b/internal/encoder/vm_escaped_indent/hack.go @@ -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" +) diff --git a/internal/encoder/vm_escaped_indent/util.go b/internal/encoder/vm_escaped_indent/util.go index 6f427b1..60d73e0 100644 --- a/internal/encoder/vm_escaped_indent/util.go +++ b/internal/encoder/vm_escaped_indent/util.go @@ -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,97 @@ 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) +} + +func appendMarshalText(code *encoder.Opcode, b []byte, v interface{}) ([]byte, error) { + return encoder.AppendMarshalTextIndent(code, b, v, true) +} + func appendStructHead(b []byte) []byte { return append(b, '{', '\n') } @@ -86,7 +208,7 @@ func appendStructKey(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte return append(b, ' ') } -func appendStructEndSkipLast(ctx *encoder.RuntimeContext, b []byte, code *encoder.Opcode) []byte { +func appendStructEndSkipLast(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte { last := len(b) - 1 if b[last-1] == '{' { b[last] = '}' @@ -101,3 +223,19 @@ func appendStructEndSkipLast(ctx *encoder.RuntimeContext, b []byte, code *encode } 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) +} diff --git a/internal/encoder/vm_escaped_indent/vm.go b/internal/encoder/vm_escaped_indent/vm.go index 752b541..75aa3cb 100644 --- a/internal/encoder/vm_escaped_indent/vm.go +++ b/internal/encoder/vm_escaped_indent/vm.go @@ -1,49 +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 - appendMarshalJSON = encoder.AppendMarshalJSONIndent - appendMarshalText = encoder.AppendMarshalTextIndent - 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) @@ -53,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 @@ -220,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] @@ -278,7 +214,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if code.IsNilableType && code.Indirect { p = ptrToPtr(p) } - bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), code.Indent, true) + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -305,7 +241,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if code.IsNilableType && code.Indirect { p = ptrToPtr(p) } - bb, err := appendMarshalText(code, b, ptrToInterface(code, p), true) + bb, err := appendMarshalText(code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -334,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: @@ -347,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: @@ -379,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: @@ -426,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 } @@ -442,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)) @@ -453,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) @@ -461,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 { @@ -484,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)) @@ -497,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)) @@ -519,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 @@ -572,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] @@ -612,7 +529,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if !code.AnonymousHead { b = appendStructHead(b) } - if !code.AnonymousKey && len(code.EscapedKey) > 0 { + if !code.AnonymousKey && len(code.Key) > 0 { b = appendStructKey(ctx, code, b) } p += code.Offset @@ -1384,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) @@ -1564,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) @@ -1602,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) @@ -1640,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) @@ -1908,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: @@ -2253,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 @@ -3170,7 +3086,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p == 0 && code.Nilcheck { b = appendNull(b) } else { - bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), code.Indent, true) + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -3215,7 +3131,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt code = code.NextField } else { b = appendStructKey(ctx, code, b) - bb, err := appendMarshalJSON(ctx, code, b, iface, code.Indent, true) + bb, err := appendMarshalJSON(ctx, code, b, iface) if err != nil { return nil, err } @@ -3255,7 +3171,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p == 0 { b = appendNull(b) } else { - bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), code.Indent, true) + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -3295,7 +3211,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt code = code.NextField } else { b = appendStructKey(ctx, code, b) - bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), code.Indent, true) + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -3339,7 +3255,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p == 0 && code.Nilcheck { b = appendNull(b) } else { - bb, err := appendMarshalText(code, b, ptrToInterface(code, p), true) + bb, err := appendMarshalText(code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -3383,7 +3299,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt code = code.NextField } else { b = appendStructKey(ctx, code, b) - bb, err := appendMarshalText(code, b, ptrToInterface(code, p), true) + bb, err := appendMarshalText(code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -3423,7 +3339,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p == 0 { b = appendNull(b) } else { - bb, err := appendMarshalText(code, b, ptrToInterface(code, p), true) + bb, err := appendMarshalText(code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -3463,7 +3379,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt code = code.NextField } else { b = appendStructKey(ctx, code, b) - bb, err := appendMarshalText(code, b, ptrToInterface(code, p), true) + bb, err := appendMarshalText(code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -3780,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: @@ -3809,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, '"') } @@ -4131,7 +4049,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p == 0 && code.Nilcheck { b = appendNull(b) } else { - bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), code.Indent, true) + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -4155,7 +4073,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt break } b = appendStructKey(ctx, code, b) - bb, err := appendMarshalJSON(ctx, code, b, iface, code.Indent, true) + bb, err := appendMarshalJSON(ctx, code, b, iface) if err != nil { return nil, err } @@ -4168,7 +4086,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p == 0 { b = appendNull(b) } else { - bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), code.Indent, true) + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -4181,7 +4099,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) - bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), code.Indent, true) + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -4198,7 +4116,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p == 0 && code.Nilcheck { b = appendNull(b) } else { - bb, err := appendMarshalText(code, b, ptrToInterface(code, p), true) + bb, err := appendMarshalText(code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -4217,7 +4135,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt break } b = appendStructKey(ctx, code, b) - bb, err := appendMarshalText(code, b, ptrToInterface(code, p), true) + bb, err := appendMarshalText(code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -4230,7 +4148,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p == 0 { b = appendNull(b) } else { - bb, err := appendMarshalText(code, b, ptrToInterface(code, p), true) + bb, err := appendMarshalText(code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -4243,7 +4161,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) - bb, err := appendMarshalText(code, b, ptrToInterface(code, p), true) + bb, err := appendMarshalText(code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -4350,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: @@ -4368,27 +4286,13 @@ 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, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyInt: p := load(ctxptr, code.HeadIdx) @@ -4397,9 +4301,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if v != 0 { b = appendStructKey(ctx, code, b) b = appendInt(b, u64, code) - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(ctx, b, code) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndIntString: @@ -4408,7 +4312,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '"') b = appendInt(b, ptrToUint64(p+code.Offset), code) b = append(b, '"') - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyIntString: p := load(ctxptr, code.HeadIdx) @@ -4419,9 +4323,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '"') b = appendInt(b, u64, code) b = append(b, '"') - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(ctx, b, code) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndIntPtr: @@ -4433,7 +4337,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt } else { b = appendInt(b, ptrToUint64(p), code) } - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyIntPtr: p := load(ctxptr, code.HeadIdx) @@ -4441,9 +4345,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p != 0 { b = appendStructKey(ctx, code, b) b = appendInt(b, ptrToUint64(p), code) - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(ctx, b, code) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndIntPtrString: @@ -4457,7 +4361,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = appendInt(b, ptrToUint64(p), code) b = append(b, '"') } - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyIntPtrString: p := load(ctxptr, code.HeadIdx) @@ -4467,16 +4371,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '"') b = appendInt(b, ptrToUint64(p), code) b = append(b, '"') - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(ctx, b, code) + b = appendStructEndSkipLast(ctx, code, b) } 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, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyUint: p := load(ctxptr, code.HeadIdx) @@ -4485,9 +4389,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if v != 0 { b = appendStructKey(ctx, code, b) b = appendUint(b, u64, code) - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(ctx, b, code) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndUintString: @@ -4496,7 +4400,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '"') b = appendUint(b, ptrToUint64(p+code.Offset), code) b = append(b, '"') - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyUintString: p := load(ctxptr, code.HeadIdx) @@ -4507,9 +4411,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '"') b = appendUint(b, u64, code) b = append(b, '"') - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(ctx, b, code) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndUintPtr: @@ -4521,7 +4425,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt } else { b = appendUint(b, ptrToUint64(p), code) } - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyUintPtr: p := load(ctxptr, code.HeadIdx) @@ -4529,9 +4433,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p != 0 { b = appendStructKey(ctx, code, b) b = appendUint(b, ptrToUint64(p), code) - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(ctx, b, code) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndUintPtrString: @@ -4545,7 +4449,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = appendUint(b, ptrToUint64(p), code) b = append(b, '"') } - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyUintPtrString: p := load(ctxptr, code.HeadIdx) @@ -4555,16 +4459,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '"') b = appendUint(b, ptrToUint64(p), code) b = append(b, '"') - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(ctx, b, code) + b = appendStructEndSkipLast(ctx, code, b) } 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, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyFloat32: p := load(ctxptr, code.HeadIdx) @@ -4572,9 +4476,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if v != 0 { b = appendStructKey(ctx, code, b) b = appendFloat32(b, v) - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(ctx, b, code) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndFloat32String: @@ -4583,7 +4487,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '"') b = appendFloat32(b, ptrToFloat32(p+code.Offset)) b = append(b, '"') - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyFloat32String: p := load(ctxptr, code.HeadIdx) @@ -4593,9 +4497,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '"') b = appendFloat32(b, v) b = append(b, '"') - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(ctx, b, code) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndFloat32Ptr: @@ -4607,7 +4511,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt } else { b = appendFloat32(b, ptrToFloat32(p)) } - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyFloat32Ptr: p := load(ctxptr, code.HeadIdx) @@ -4615,9 +4519,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p != 0 { b = appendStructKey(ctx, code, b) b = appendFloat32(b, ptrToFloat32(p)) - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(ctx, b, code) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndFloat32PtrString: @@ -4631,7 +4535,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = appendFloat32(b, ptrToFloat32(p)) b = append(b, '"') } - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyFloat32PtrString: p := load(ctxptr, code.HeadIdx) @@ -4641,33 +4545,33 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '"') b = appendFloat32(b, ptrToFloat32(p)) b = append(b, '"') - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(ctx, b, code) + b = appendStructEndSkipLast(ctx, code, b) } 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, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyFloat64: 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, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(ctx, b, code) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndFloat64String: @@ -4680,22 +4584,22 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '"') b = appendFloat64(b, v) b = append(b, '"') - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyFloat64String: 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, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(ctx, b, code) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndFloat64Ptr: @@ -4704,14 +4608,16 @@ 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 } - b = appendStructEnd(ctx, b, code.Indent-1) + 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: p := load(ctxptr, code.HeadIdx) @@ -4723,9 +4629,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt return nil, errUnsupportedFloat(v) } b = appendFloat64(b, v) - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(ctx, b, code) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndFloat64PtrString: @@ -4743,30 +4649,30 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = appendFloat64(b, v) b = append(b, '"') } - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyFloat64PtrString: p := load(ctxptr, code.HeadIdx) 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, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(ctx, b, code) + b = appendStructEndSkipLast(ctx, code, b) } 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, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyString: p := load(ctxptr, code.HeadIdx) @@ -4774,9 +4680,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if v != "" { b = appendStructKey(ctx, code, b) b = appendString(b, v) - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(ctx, b, code) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndStringString: @@ -4784,7 +4690,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = appendStructKey(ctx, code, b) s := ptrToString(p + code.Offset) b = appendString(b, string(appendString([]byte{}, s))) - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyStringString: p := load(ctxptr, code.HeadIdx) @@ -4792,9 +4698,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if v != "" { b = appendStructKey(ctx, code, b) b = appendString(b, string(appendString([]byte{}, v))) - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(ctx, b, code) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndStringPtr: @@ -4806,7 +4712,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt } else { b = appendString(b, ptrToString(p)) } - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyStringPtr: p := load(ctxptr, code.HeadIdx) @@ -4814,9 +4720,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p != 0 { b = appendStructKey(ctx, code, b) b = appendString(b, ptrToString(p)) - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(ctx, b, code) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndStringPtrString: @@ -4828,7 +4734,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt } else { b = appendString(b, string(appendString([]byte{}, ptrToString(p)))) } - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyStringPtrString: p := load(ctxptr, code.HeadIdx) @@ -4836,16 +4742,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p != 0 { b = appendStructKey(ctx, code, b) b = appendString(b, string(appendString([]byte{}, ptrToString(p)))) - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(ctx, b, code) + b = appendStructEndSkipLast(ctx, code, b) } 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, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyBool: p := load(ctxptr, code.HeadIdx) @@ -4853,9 +4759,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if v { b = appendStructKey(ctx, code, b) b = appendBool(b, v) - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(ctx, b, code) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndBoolString: @@ -4864,7 +4770,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '"') b = appendBool(b, ptrToBool(p+code.Offset)) b = append(b, '"') - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyBoolString: p := load(ctxptr, code.HeadIdx) @@ -4874,9 +4780,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '"') b = appendBool(b, v) b = append(b, '"') - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(ctx, b, code) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndBoolPtr: @@ -4888,7 +4794,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt } else { b = appendBool(b, ptrToBool(p)) } - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyBoolPtr: p := load(ctxptr, code.HeadIdx) @@ -4896,9 +4802,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p != 0 { b = appendStructKey(ctx, code, b) b = appendBool(b, ptrToBool(p)) - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(ctx, b, code) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndBoolPtrString: @@ -4912,7 +4818,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = appendBool(b, ptrToBool(p)) b = append(b, '"') } - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyBoolPtrString: p := load(ctxptr, code.HeadIdx) @@ -4922,16 +4828,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '"') b = appendBool(b, ptrToBool(p)) b = append(b, '"') - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(ctx, b, code) + b = appendStructEndSkipLast(ctx, code, b) } 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, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyBytes: p := load(ctxptr, code.HeadIdx) @@ -4939,9 +4845,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if len(v) > 0 { b = appendStructKey(ctx, code, b) b = appendByteSlice(b, v) - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(ctx, b, code) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndBytesPtr: @@ -4953,7 +4859,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt } else { b = appendByteSlice(b, ptrToBytes(p)) } - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyBytesPtr: p := load(ctxptr, code.HeadIdx) @@ -4961,19 +4867,19 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p != 0 { b = appendStructKey(ctx, code, b) b = appendByteSlice(b, ptrToBytes(p)) - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(ctx, b, code) + b = appendStructEndSkipLast(ctx, code, b) } 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 } - b = appendStructEnd(ctx, bb, code.Indent-1) + b = appendStructEnd(ctx, code, bb) code = code.Next case encoder.OpStructEndOmitEmptyNumber: p := load(ctxptr, code.HeadIdx) @@ -4984,21 +4890,21 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if err != nil { return nil, err } - b = appendStructEnd(ctx, bb, code.Indent-1) + b = appendStructEnd(ctx, code, bb) } else { - b = appendStructEndSkipLast(ctx, b, code) + b = appendStructEndSkipLast(ctx, code, b) } 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 } b = append(bb, '"') - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyNumberString: p := load(ctxptr, code.HeadIdx) @@ -5011,9 +4917,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt return nil, err } b = append(bb, '"') - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(ctx, b, code) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndNumberPtr: @@ -5029,7 +4935,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt } b = bb } - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyNumberPtr: p := load(ctxptr, code.HeadIdx) @@ -5040,9 +4946,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if err != nil { return nil, err } - b = appendStructEnd(ctx, bb, code.Indent-1) + b = appendStructEnd(ctx, code, bb) } else { - b = appendStructEndSkipLast(ctx, b, code) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndNumberPtrString: @@ -5059,7 +4965,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt } b = append(bb, '"') } - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyNumberPtrString: p := load(ctxptr, code.HeadIdx) @@ -5072,9 +4978,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt return nil, err } b = append(bb, '"') - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(ctx, b, code) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpEnd: diff --git a/internal/encoder/vm_indent/hack.go b/internal/encoder/vm_indent/hack.go new file mode 100644 index 0000000..7838010 --- /dev/null +++ b/internal/encoder/vm_indent/hack.go @@ -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" +) diff --git a/internal/encoder/vm_indent/util.go b/internal/encoder/vm_indent/util.go index a20ca12..d73fb7b 100644 --- a/internal/encoder/vm_indent/util.go +++ b/internal/encoder/vm_indent/util.go @@ -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,6 +107,97 @@ 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, false) +} + +func appendMarshalText(code *encoder.Opcode, b []byte, v interface{}) ([]byte, error) { + return encoder.AppendMarshalTextIndent(code, b, v, false) +} + func appendStructHead(b []byte) []byte { return append(b, '{', '\n') } @@ -86,7 +208,7 @@ func appendStructKey(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte return append(b, ' ') } -func appendStructEndSkipLast(ctx *encoder.RuntimeContext, b []byte, code *encoder.Opcode) []byte { +func appendStructEndSkipLast(ctx *encoder.RuntimeContext, code *encoder.Opcode, b []byte) []byte { last := len(b) - 1 if b[last-1] == '{' { b[last] = '}' @@ -101,3 +223,19 @@ func appendStructEndSkipLast(ctx *encoder.RuntimeContext, b []byte, code *encode } 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) +} diff --git a/internal/encoder/vm_indent/vm.go b/internal/encoder/vm_indent/vm.go index 31ce1e4..4b47457 100644 --- a/internal/encoder/vm_indent/vm.go +++ b/internal/encoder/vm_indent/vm.go @@ -1,49 +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 - appendMarshalJSON = encoder.AppendMarshalJSONIndent - appendMarshalText = encoder.AppendMarshalTextIndent - 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) @@ -53,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 @@ -220,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] @@ -278,7 +214,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if code.IsNilableType && code.Indirect { p = ptrToPtr(p) } - bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), code.Indent, false) + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -305,7 +241,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if code.IsNilableType && code.Indirect { p = ptrToPtr(p) } - bb, err := appendMarshalText(code, b, ptrToInterface(code, p), false) + bb, err := appendMarshalText(code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -334,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: @@ -347,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: @@ -379,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: @@ -426,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 } @@ -442,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)) @@ -453,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) @@ -461,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 { @@ -484,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)) @@ -497,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)) @@ -519,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 @@ -572,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] @@ -1384,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) @@ -1564,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) @@ -1602,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) @@ -1640,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) @@ -1908,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: @@ -2253,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 @@ -3170,7 +3086,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p == 0 && code.Nilcheck { b = appendNull(b) } else { - bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), code.Indent, false) + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -3215,7 +3131,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt code = code.NextField } else { b = appendStructKey(ctx, code, b) - bb, err := appendMarshalJSON(ctx, code, b, iface, code.Indent, false) + bb, err := appendMarshalJSON(ctx, code, b, iface) if err != nil { return nil, err } @@ -3255,7 +3171,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p == 0 { b = appendNull(b) } else { - bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), code.Indent, false) + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -3295,7 +3211,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt code = code.NextField } else { b = appendStructKey(ctx, code, b) - bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), code.Indent, false) + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -3339,7 +3255,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p == 0 && code.Nilcheck { b = appendNull(b) } else { - bb, err := appendMarshalText(code, b, ptrToInterface(code, p), false) + bb, err := appendMarshalText(code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -3383,7 +3299,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt code = code.NextField } else { b = appendStructKey(ctx, code, b) - bb, err := appendMarshalText(code, b, ptrToInterface(code, p), false) + bb, err := appendMarshalText(code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -3423,7 +3339,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p == 0 { b = appendNull(b) } else { - bb, err := appendMarshalText(code, b, ptrToInterface(code, p), false) + bb, err := appendMarshalText(code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -3463,7 +3379,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt code = code.NextField } else { b = appendStructKey(ctx, code, b) - bb, err := appendMarshalText(code, b, ptrToInterface(code, p), false) + bb, err := appendMarshalText(code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -3780,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: @@ -3809,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, '"') } @@ -4131,7 +4049,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p == 0 && code.Nilcheck { b = appendNull(b) } else { - bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), code.Indent, false) + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -4155,7 +4073,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt break } b = appendStructKey(ctx, code, b) - bb, err := appendMarshalJSON(ctx, code, b, iface, code.Indent, false) + bb, err := appendMarshalJSON(ctx, code, b, iface) if err != nil { return nil, err } @@ -4168,7 +4086,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p == 0 { b = appendNull(b) } else { - bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), code.Indent, false) + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -4181,7 +4099,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) - bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), code.Indent, false) + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -4198,7 +4116,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p == 0 && code.Nilcheck { b = appendNull(b) } else { - bb, err := appendMarshalText(code, b, ptrToInterface(code, p), false) + bb, err := appendMarshalText(code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -4217,7 +4135,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt break } b = appendStructKey(ctx, code, b) - bb, err := appendMarshalText(code, b, ptrToInterface(code, p), false) + bb, err := appendMarshalText(code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -4230,7 +4148,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p == 0 { b = appendNull(b) } else { - bb, err := appendMarshalText(code, b, ptrToInterface(code, p), false) + bb, err := appendMarshalText(code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -4243,7 +4161,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) - bb, err := appendMarshalText(code, b, ptrToInterface(code, p), false) + bb, err := appendMarshalText(code, b, ptrToInterface(code, p)) if err != nil { return nil, err } @@ -4350,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: @@ -4368,27 +4286,13 @@ 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, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyInt: p := load(ctxptr, code.HeadIdx) @@ -4397,9 +4301,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if v != 0 { b = appendStructKey(ctx, code, b) b = appendInt(b, u64, code) - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(ctx, b, code) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndIntString: @@ -4408,7 +4312,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '"') b = appendInt(b, ptrToUint64(p+code.Offset), code) b = append(b, '"') - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyIntString: p := load(ctxptr, code.HeadIdx) @@ -4419,9 +4323,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '"') b = appendInt(b, u64, code) b = append(b, '"') - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(ctx, b, code) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndIntPtr: @@ -4433,7 +4337,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt } else { b = appendInt(b, ptrToUint64(p), code) } - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyIntPtr: p := load(ctxptr, code.HeadIdx) @@ -4441,9 +4345,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p != 0 { b = appendStructKey(ctx, code, b) b = appendInt(b, ptrToUint64(p), code) - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(ctx, b, code) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndIntPtrString: @@ -4457,7 +4361,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = appendInt(b, ptrToUint64(p), code) b = append(b, '"') } - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyIntPtrString: p := load(ctxptr, code.HeadIdx) @@ -4467,16 +4371,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '"') b = appendInt(b, ptrToUint64(p), code) b = append(b, '"') - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(ctx, b, code) + b = appendStructEndSkipLast(ctx, code, b) } 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, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyUint: p := load(ctxptr, code.HeadIdx) @@ -4485,9 +4389,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if v != 0 { b = appendStructKey(ctx, code, b) b = appendUint(b, u64, code) - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(ctx, b, code) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndUintString: @@ -4496,7 +4400,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '"') b = appendUint(b, ptrToUint64(p+code.Offset), code) b = append(b, '"') - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyUintString: p := load(ctxptr, code.HeadIdx) @@ -4507,9 +4411,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '"') b = appendUint(b, u64, code) b = append(b, '"') - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(ctx, b, code) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndUintPtr: @@ -4521,7 +4425,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt } else { b = appendUint(b, ptrToUint64(p), code) } - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyUintPtr: p := load(ctxptr, code.HeadIdx) @@ -4529,9 +4433,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p != 0 { b = appendStructKey(ctx, code, b) b = appendUint(b, ptrToUint64(p), code) - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(ctx, b, code) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndUintPtrString: @@ -4545,7 +4449,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = appendUint(b, ptrToUint64(p), code) b = append(b, '"') } - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyUintPtrString: p := load(ctxptr, code.HeadIdx) @@ -4555,16 +4459,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '"') b = appendUint(b, ptrToUint64(p), code) b = append(b, '"') - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(ctx, b, code) + b = appendStructEndSkipLast(ctx, code, b) } 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, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyFloat32: p := load(ctxptr, code.HeadIdx) @@ -4572,9 +4476,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if v != 0 { b = appendStructKey(ctx, code, b) b = appendFloat32(b, v) - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(ctx, b, code) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndFloat32String: @@ -4583,7 +4487,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '"') b = appendFloat32(b, ptrToFloat32(p+code.Offset)) b = append(b, '"') - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyFloat32String: p := load(ctxptr, code.HeadIdx) @@ -4593,9 +4497,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '"') b = appendFloat32(b, v) b = append(b, '"') - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(ctx, b, code) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndFloat32Ptr: @@ -4607,7 +4511,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt } else { b = appendFloat32(b, ptrToFloat32(p)) } - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyFloat32Ptr: p := load(ctxptr, code.HeadIdx) @@ -4615,9 +4519,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p != 0 { b = appendStructKey(ctx, code, b) b = appendFloat32(b, ptrToFloat32(p)) - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(ctx, b, code) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndFloat32PtrString: @@ -4631,7 +4535,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = appendFloat32(b, ptrToFloat32(p)) b = append(b, '"') } - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyFloat32PtrString: p := load(ctxptr, code.HeadIdx) @@ -4641,33 +4545,33 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '"') b = appendFloat32(b, ptrToFloat32(p)) b = append(b, '"') - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(ctx, b, code) + b = appendStructEndSkipLast(ctx, code, b) } 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, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyFloat64: 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, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(ctx, b, code) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndFloat64String: @@ -4680,22 +4584,22 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '"') b = appendFloat64(b, v) b = append(b, '"') - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyFloat64String: 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, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(ctx, b, code) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndFloat64Ptr: @@ -4704,14 +4608,16 @@ 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 } - b = appendStructEnd(ctx, b, code.Indent-1) + 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: p := load(ctxptr, code.HeadIdx) @@ -4723,9 +4629,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt return nil, errUnsupportedFloat(v) } b = appendFloat64(b, v) - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(ctx, b, code) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndFloat64PtrString: @@ -4743,30 +4649,30 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = appendFloat64(b, v) b = append(b, '"') } - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyFloat64PtrString: p := load(ctxptr, code.HeadIdx) 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, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(ctx, b, code) + b = appendStructEndSkipLast(ctx, code, b) } 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, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyString: p := load(ctxptr, code.HeadIdx) @@ -4774,9 +4680,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if v != "" { b = appendStructKey(ctx, code, b) b = appendString(b, v) - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(ctx, b, code) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndStringString: @@ -4784,7 +4690,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = appendStructKey(ctx, code, b) s := ptrToString(p + code.Offset) b = appendString(b, string(appendString([]byte{}, s))) - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyStringString: p := load(ctxptr, code.HeadIdx) @@ -4792,9 +4698,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if v != "" { b = appendStructKey(ctx, code, b) b = appendString(b, string(appendString([]byte{}, v))) - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(ctx, b, code) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndStringPtr: @@ -4806,7 +4712,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt } else { b = appendString(b, ptrToString(p)) } - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyStringPtr: p := load(ctxptr, code.HeadIdx) @@ -4814,9 +4720,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p != 0 { b = appendStructKey(ctx, code, b) b = appendString(b, ptrToString(p)) - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(ctx, b, code) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndStringPtrString: @@ -4828,7 +4734,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt } else { b = appendString(b, string(appendString([]byte{}, ptrToString(p)))) } - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyStringPtrString: p := load(ctxptr, code.HeadIdx) @@ -4836,16 +4742,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p != 0 { b = appendStructKey(ctx, code, b) b = appendString(b, string(appendString([]byte{}, ptrToString(p)))) - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(ctx, b, code) + b = appendStructEndSkipLast(ctx, code, b) } 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, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyBool: p := load(ctxptr, code.HeadIdx) @@ -4853,9 +4759,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if v { b = appendStructKey(ctx, code, b) b = appendBool(b, v) - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(ctx, b, code) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndBoolString: @@ -4864,7 +4770,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '"') b = appendBool(b, ptrToBool(p+code.Offset)) b = append(b, '"') - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyBoolString: p := load(ctxptr, code.HeadIdx) @@ -4874,9 +4780,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '"') b = appendBool(b, v) b = append(b, '"') - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(ctx, b, code) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndBoolPtr: @@ -4888,7 +4794,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt } else { b = appendBool(b, ptrToBool(p)) } - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyBoolPtr: p := load(ctxptr, code.HeadIdx) @@ -4896,9 +4802,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p != 0 { b = appendStructKey(ctx, code, b) b = appendBool(b, ptrToBool(p)) - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(ctx, b, code) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndBoolPtrString: @@ -4912,7 +4818,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = appendBool(b, ptrToBool(p)) b = append(b, '"') } - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyBoolPtrString: p := load(ctxptr, code.HeadIdx) @@ -4922,16 +4828,16 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '"') b = appendBool(b, ptrToBool(p)) b = append(b, '"') - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(ctx, b, code) + b = appendStructEndSkipLast(ctx, code, b) } 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, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyBytes: p := load(ctxptr, code.HeadIdx) @@ -4939,9 +4845,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if len(v) > 0 { b = appendStructKey(ctx, code, b) b = appendByteSlice(b, v) - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(ctx, b, code) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndBytesPtr: @@ -4953,7 +4859,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt } else { b = appendByteSlice(b, ptrToBytes(p)) } - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyBytesPtr: p := load(ctxptr, code.HeadIdx) @@ -4961,19 +4867,19 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p != 0 { b = appendStructKey(ctx, code, b) b = appendByteSlice(b, ptrToBytes(p)) - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(ctx, b, code) + b = appendStructEndSkipLast(ctx, code, b) } 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 } - b = appendStructEnd(ctx, bb, code.Indent-1) + b = appendStructEnd(ctx, code, bb) code = code.Next case encoder.OpStructEndOmitEmptyNumber: p := load(ctxptr, code.HeadIdx) @@ -4984,21 +4890,21 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if err != nil { return nil, err } - b = appendStructEnd(ctx, bb, code.Indent-1) + b = appendStructEnd(ctx, code, bb) } else { - b = appendStructEndSkipLast(ctx, b, code) + b = appendStructEndSkipLast(ctx, code, b) } 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 } b = append(bb, '"') - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyNumberString: p := load(ctxptr, code.HeadIdx) @@ -5011,9 +4917,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt return nil, err } b = append(bb, '"') - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(ctx, b, code) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndNumberPtr: @@ -5029,7 +4935,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt } b = bb } - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyNumberPtr: p := load(ctxptr, code.HeadIdx) @@ -5040,9 +4946,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if err != nil { return nil, err } - b = appendStructEnd(ctx, bb, code.Indent-1) + b = appendStructEnd(ctx, code, bb) } else { - b = appendStructEndSkipLast(ctx, b, code) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpStructEndNumberPtrString: @@ -5059,7 +4965,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt } b = append(bb, '"') } - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) code = code.Next case encoder.OpStructEndOmitEmptyNumberPtrString: p := load(ctxptr, code.HeadIdx) @@ -5072,9 +4978,9 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt return nil, err } b = append(bb, '"') - b = appendStructEnd(ctx, b, code.Indent-1) + b = appendStructEnd(ctx, code, b) } else { - b = appendStructEndSkipLast(ctx, b, code) + b = appendStructEndSkipLast(ctx, code, b) } code = code.Next case encoder.OpEnd: