diff --git a/internal/encoder/compact.go b/internal/encoder/compact.go index 718d1cc..d70d9e3 100644 --- a/internal/encoder/compact.go +++ b/internal/encoder/compact.go @@ -7,7 +7,6 @@ import ( "unsafe" "github.com/goccy/go-json/internal/errors" - "github.com/goccy/go-json/internal/runtime" ) var ( @@ -29,8 +28,11 @@ func Compact(buf *bytes.Buffer, src []byte, escape bool) error { if len(src) == 0 { return errors.ErrUnexpectedEndOfJSON("", 0) } - dst := make([]byte, 0, len(src)) - dst, err := compact(dst, src, escape) + buf.Grow(len(src)) + dst := buf.Bytes() + newSrc := make([]byte, len(src)+1) // append nul byte to the end + copy(newSrc, src) + dst, err := compact(dst, newSrc, escape) if err != nil { return err } @@ -41,12 +43,10 @@ func Compact(buf *bytes.Buffer, src []byte, escape bool) error { } func compact(dst, src []byte, escape bool) ([]byte, error) { - src = append(src, nul) buf, _, err := compactValue(dst, src, 0, escape) if err != nil { return nil, err } - (*runtime.SliceHeader)(unsafe.Pointer(&src)).Len-- return buf, nil } diff --git a/internal/encoder/encoder.go b/internal/encoder/encoder.go index 2c0a30c..8815d62 100644 --- a/internal/encoder/encoder.go +++ b/internal/encoder/encoder.go @@ -306,6 +306,7 @@ func MapLen(m unsafe.Pointer) int type RuntimeContext struct { Buf []byte + MarshalBuf []byte Ptrs []uintptr KeepRefs []unsafe.Pointer SeenPtr []uintptr @@ -413,7 +414,7 @@ func AppendNumber(b []byte, n json.Number) ([]byte, error) { return b, nil } -func AppendMarshalJSON(code *Opcode, b []byte, v interface{}, escape bool) ([]byte, error) { +func AppendMarshalJSON(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() { @@ -433,10 +434,13 @@ func AppendMarshalJSON(code *Opcode, b []byte, v interface{}, escape bool) ([]by if err != nil { return nil, &errors.MarshalerError{Type: reflect.TypeOf(v), Err: err} } - compactedBuf, err := compact(b, bb, escape) + marshalBuf := ctx.MarshalBuf[:0] + marshalBuf = append(append(marshalBuf, bb...), nul) + compactedBuf, err := compact(b, marshalBuf, escape) if err != nil { return nil, &errors.MarshalerError{Type: reflect.TypeOf(v), Err: err} } + ctx.MarshalBuf = marshalBuf return compactedBuf, nil } diff --git a/internal/encoder/vm/vm.go b/internal/encoder/vm/vm.go index b4b80b6..ac2997a 100644 --- a/internal/encoder/vm/vm.go +++ b/internal/encoder/vm/vm.go @@ -273,7 +273,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if code.IsNilableType && code.Indirect { p = ptrToPtr(p) } - bb, err := appendMarshalJSON(code, b, ptrToInterface(code, p), false) + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), false) if err != nil { return nil, err } @@ -2718,7 +2718,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p == 0 && code.Nilcheck { b = appendNull(b) } else { - bb, err := appendMarshalJSON(code, b, ptrToInterface(code, p), false) + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), false) if err != nil { return nil, err } @@ -2762,7 +2762,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p == 0 && code.Nilcheck { b = appendNull(b) } else { - bb, err := appendMarshalJSON(code, b, ptrToInterface(code, p), false) + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), false) if err != nil { return nil, err } @@ -2807,7 +2807,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt code = code.NextField } else { b = append(b, code.Key...) - bb, err := appendMarshalJSON(code, b, iface, false) + bb, err := appendMarshalJSON(ctx, code, b, iface, false) if err != nil { return nil, err } @@ -2847,7 +2847,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p == 0 { b = appendNull(b) } else { - bb, err := appendMarshalJSON(code, b, ptrToInterface(code, p), false) + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), false) if err != nil { return nil, err } @@ -2887,7 +2887,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt code = code.NextField } else { b = append(b, code.Key...) - bb, err := appendMarshalJSON(code, b, ptrToInterface(code, p), false) + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), false) if err != nil { return nil, err } @@ -3628,7 +3628,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p == 0 && code.Nilcheck { b = appendNull(b) } else { - bb, err := appendMarshalJSON(code, b, ptrToInterface(code, p), false) + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), false) if err != nil { return nil, err } @@ -3652,7 +3652,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt break } b = append(b, code.Key...) - bb, err := appendMarshalJSON(code, b, iface, false) + bb, err := appendMarshalJSON(ctx, code, b, iface, false) if err != nil { return nil, err } @@ -3665,7 +3665,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p == 0 { b = appendNull(b) } else { - bb, err := appendMarshalJSON(code, b, ptrToInterface(code, p), false) + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), false) if err != nil { return nil, err } @@ -3678,7 +3678,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt p = ptrToNPtr(p+code.Offset, code.PtrNum) if p != 0 { b = append(b, code.Key...) - bb, err := appendMarshalJSON(code, b, ptrToInterface(code, p), false) + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), false) if err != nil { return nil, err } diff --git a/internal/encoder/vm_debug/vm.go b/internal/encoder/vm_debug/vm.go index b78d813..88809f7 100644 --- a/internal/encoder/vm_debug/vm.go +++ b/internal/encoder/vm_debug/vm.go @@ -286,7 +286,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if code.IsNilableType && code.Indirect { p = ptrToPtr(p) } - bb, err := appendMarshalJSON(code, b, ptrToInterface(code, p), false) + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), false) if err != nil { return nil, err } @@ -2731,7 +2731,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p == 0 && code.Nilcheck { b = appendNull(b) } else { - bb, err := appendMarshalJSON(code, b, ptrToInterface(code, p), false) + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), false) if err != nil { return nil, err } @@ -2775,7 +2775,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p == 0 && code.Nilcheck { b = appendNull(b) } else { - bb, err := appendMarshalJSON(code, b, ptrToInterface(code, p), false) + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), false) if err != nil { return nil, err } @@ -2820,7 +2820,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt code = code.NextField } else { b = append(b, code.Key...) - bb, err := appendMarshalJSON(code, b, iface, false) + bb, err := appendMarshalJSON(ctx, code, b, iface, false) if err != nil { return nil, err } @@ -2860,7 +2860,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p == 0 { b = appendNull(b) } else { - bb, err := appendMarshalJSON(code, b, ptrToInterface(code, p), false) + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), false) if err != nil { return nil, err } @@ -2900,7 +2900,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt code = code.NextField } else { b = append(b, code.Key...) - bb, err := appendMarshalJSON(code, b, ptrToInterface(code, p), false) + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), false) if err != nil { return nil, err } @@ -3641,7 +3641,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p == 0 && code.Nilcheck { b = appendNull(b) } else { - bb, err := appendMarshalJSON(code, b, ptrToInterface(code, p), false) + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), false) if err != nil { return nil, err } @@ -3665,7 +3665,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt break } b = append(b, code.Key...) - bb, err := appendMarshalJSON(code, b, iface, false) + bb, err := appendMarshalJSON(ctx, code, b, iface, false) if err != nil { return nil, err } @@ -3678,7 +3678,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p == 0 { b = appendNull(b) } else { - bb, err := appendMarshalJSON(code, b, ptrToInterface(code, p), false) + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), false) if err != nil { return nil, err } @@ -3691,7 +3691,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt p = ptrToNPtr(p+code.Offset, code.PtrNum) if p != 0 { b = append(b, code.Key...) - bb, err := appendMarshalJSON(code, b, ptrToInterface(code, p), false) + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), false) if err != nil { return nil, err } diff --git a/internal/encoder/vm_escaped/vm.go b/internal/encoder/vm_escaped/vm.go index 846119b..1daec9d 100644 --- a/internal/encoder/vm_escaped/vm.go +++ b/internal/encoder/vm_escaped/vm.go @@ -273,7 +273,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if code.IsNilableType && code.Indirect { p = ptrToPtr(p) } - bb, err := appendMarshalJSON(code, b, ptrToInterface(code, p), true) + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), true) if err != nil { return nil, err } @@ -2718,7 +2718,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p == 0 && code.Nilcheck { b = appendNull(b) } else { - bb, err := appendMarshalJSON(code, b, ptrToInterface(code, p), true) + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), true) if err != nil { return nil, err } @@ -2762,7 +2762,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p == 0 && code.Nilcheck { b = appendNull(b) } else { - bb, err := appendMarshalJSON(code, b, ptrToInterface(code, p), true) + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), true) if err != nil { return nil, err } @@ -2807,7 +2807,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt code = code.NextField } else { b = append(b, code.EscapedKey...) - bb, err := appendMarshalJSON(code, b, iface, true) + bb, err := appendMarshalJSON(ctx, code, b, iface, true) if err != nil { return nil, err } @@ -2847,7 +2847,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p == 0 { b = appendNull(b) } else { - bb, err := appendMarshalJSON(code, b, ptrToInterface(code, p), true) + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), true) if err != nil { return nil, err } @@ -2887,7 +2887,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt code = code.NextField } else { b = append(b, code.EscapedKey...) - bb, err := appendMarshalJSON(code, b, ptrToInterface(code, p), true) + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), true) if err != nil { return nil, err } @@ -3628,7 +3628,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p == 0 && code.Nilcheck { b = appendNull(b) } else { - bb, err := appendMarshalJSON(code, b, ptrToInterface(code, p), true) + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), true) if err != nil { return nil, err } @@ -3652,7 +3652,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt break } b = append(b, code.EscapedKey...) - bb, err := appendMarshalJSON(code, b, iface, true) + bb, err := appendMarshalJSON(ctx, code, b, iface, true) if err != nil { return nil, err } @@ -3665,7 +3665,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if p == 0 { b = appendNull(b) } else { - bb, err := appendMarshalJSON(code, b, ptrToInterface(code, p), true) + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), true) if err != nil { return nil, err } @@ -3678,7 +3678,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt p = ptrToNPtr(p+code.Offset, code.PtrNum) if p != 0 { b = append(b, code.EscapedKey...) - bb, err := appendMarshalJSON(code, b, ptrToInterface(code, p), true) + bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), true) if err != nil { return nil, err }