forked from mirror/go-json
Replace vm and escaped vm codes with internal package
This commit is contained in:
parent
10c4118a45
commit
cccf9f9f33
|
@ -7,7 +7,7 @@ services:
|
||||||
deploy:
|
deploy:
|
||||||
resources:
|
resources:
|
||||||
limits:
|
limits:
|
||||||
memory: 2048M
|
memory: 1200M
|
||||||
working_dir: /go/src/go-json
|
working_dir: /go/src/go-json
|
||||||
command: |
|
command: |
|
||||||
sh -c "go test -c . && ls go-json.test"
|
sh -c "go test -c . && ls go-json.test"
|
||||||
|
|
75
encode.go
75
encode.go
|
@ -15,6 +15,7 @@ import (
|
||||||
|
|
||||||
"github.com/goccy/go-json/internal/encoder"
|
"github.com/goccy/go-json/internal/encoder"
|
||||||
"github.com/goccy/go-json/internal/encoder/vm"
|
"github.com/goccy/go-json/internal/encoder/vm"
|
||||||
|
"github.com/goccy/go-json/internal/encoder/vm_escaped"
|
||||||
)
|
)
|
||||||
|
|
||||||
// An Encoder writes JSON values to an output stream.
|
// An Encoder writes JSON values to an output stream.
|
||||||
|
@ -48,6 +49,15 @@ var (
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
encRuntimeContextPool2 = sync.Pool{
|
||||||
|
New: func() interface{} {
|
||||||
|
return &encoder.RuntimeContext{
|
||||||
|
Buf: make([]byte, 0, bufSize),
|
||||||
|
Ptrs: make([]uintptr, 128),
|
||||||
|
KeepRefs: make([]unsafe.Pointer, 0, 8),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func takeEncodeRuntimeContext() *encodeRuntimeContext {
|
func takeEncodeRuntimeContext() *encodeRuntimeContext {
|
||||||
|
@ -58,6 +68,14 @@ func releaseEncodeRuntimeContext(ctx *encodeRuntimeContext) {
|
||||||
encRuntimeContextPool.Put(ctx)
|
encRuntimeContextPool.Put(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func takeEncodeRuntimeContext2() *encoder.RuntimeContext {
|
||||||
|
return encRuntimeContextPool2.Get().(*encoder.RuntimeContext)
|
||||||
|
}
|
||||||
|
|
||||||
|
func releaseEncodeRuntimeContext2(ctx *encoder.RuntimeContext) {
|
||||||
|
encRuntimeContextPool2.Put(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
// NewEncoder returns a new encoder that writes to w.
|
// NewEncoder returns a new encoder that writes to w.
|
||||||
func NewEncoder(w io.Writer) *Encoder {
|
func NewEncoder(w io.Writer) *Encoder {
|
||||||
return &Encoder{w: w, enabledHTMLEscape: true}
|
return &Encoder{w: w, enabledHTMLEscape: true}
|
||||||
|
@ -95,7 +113,9 @@ func (e *Encoder) encodeWithOption(ctx *encodeRuntimeContext, v interface{}, opt
|
||||||
if e.enabledIndent {
|
if e.enabledIndent {
|
||||||
buf, err = encodeIndent(ctx, v, e.prefix, e.indentStr, opt)
|
buf, err = encodeIndent(ctx, v, e.prefix, e.indentStr, opt)
|
||||||
} else {
|
} else {
|
||||||
|
ctx := takeEncodeRuntimeContext2()
|
||||||
buf, err = encode(ctx, v, opt)
|
buf, err = encode(ctx, v, opt)
|
||||||
|
releaseEncodeRuntimeContext2(ctx)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -133,11 +153,11 @@ func (e *Encoder) SetIndent(prefix, indent string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func marshal(v interface{}, opt EncodeOption) ([]byte, error) {
|
func marshal(v interface{}, opt EncodeOption) ([]byte, error) {
|
||||||
ctx := takeEncodeRuntimeContext()
|
ctx := takeEncodeRuntimeContext2()
|
||||||
|
|
||||||
buf, err := encode(ctx, v, opt|EncodeOptionHTMLEscape)
|
buf, err := encode(ctx, v, opt|EncodeOptionHTMLEscape)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
releaseEncodeRuntimeContext(ctx)
|
releaseEncodeRuntimeContext2(ctx)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,16 +169,16 @@ func marshal(v interface{}, opt EncodeOption) ([]byte, error) {
|
||||||
copied := make([]byte, len(buf))
|
copied := make([]byte, len(buf))
|
||||||
copy(copied, buf)
|
copy(copied, buf)
|
||||||
|
|
||||||
releaseEncodeRuntimeContext(ctx)
|
releaseEncodeRuntimeContext2(ctx)
|
||||||
return copied, nil
|
return copied, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func marshalNoEscape(v interface{}, opt EncodeOption) ([]byte, error) {
|
func marshalNoEscape(v interface{}, opt EncodeOption) ([]byte, error) {
|
||||||
ctx := takeEncodeRuntimeContext()
|
ctx := takeEncodeRuntimeContext2()
|
||||||
|
|
||||||
buf, err := encodeNoEscape(ctx, v, opt|EncodeOptionHTMLEscape)
|
buf, err := encodeNoEscape(ctx, v, opt|EncodeOptionHTMLEscape)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
releaseEncodeRuntimeContext(ctx)
|
releaseEncodeRuntimeContext2(ctx)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,7 +190,7 @@ func marshalNoEscape(v interface{}, opt EncodeOption) ([]byte, error) {
|
||||||
copied := make([]byte, len(buf))
|
copied := make([]byte, len(buf))
|
||||||
copy(copied, buf)
|
copy(copied, buf)
|
||||||
|
|
||||||
releaseEncodeRuntimeContext(ctx)
|
releaseEncodeRuntimeContext2(ctx)
|
||||||
return copied, nil
|
return copied, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -191,8 +211,8 @@ func marshalIndent(v interface{}, prefix, indent string, opt EncodeOption) ([]by
|
||||||
return copied, nil
|
return copied, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func encode(ctx *encodeRuntimeContext, v interface{}, opt EncodeOption) ([]byte, error) {
|
func encode(ctx *encoder.RuntimeContext, v interface{}, opt EncodeOption) ([]byte, error) {
|
||||||
b := ctx.buf[:0]
|
b := ctx.Buf[:0]
|
||||||
if v == nil {
|
if v == nil {
|
||||||
b = encodeNull(b)
|
b = encodeNull(b)
|
||||||
b = encodeComma(b)
|
b = encodeComma(b)
|
||||||
|
@ -202,40 +222,25 @@ func encode(ctx *encodeRuntimeContext, v interface{}, opt EncodeOption) ([]byte,
|
||||||
typ := header.typ
|
typ := header.typ
|
||||||
|
|
||||||
typeptr := uintptr(unsafe.Pointer(typ))
|
typeptr := uintptr(unsafe.Pointer(typ))
|
||||||
codeSet, err := encodeCompileToGetCodeSet(typeptr)
|
codeSet, err := encoder.CompileToGetCodeSet(typeptr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
p := uintptr(header.ptr)
|
p := uintptr(header.ptr)
|
||||||
ctx.init(p, codeSet.codeLength)
|
|
||||||
ctx.keepRefs = append(ctx.keepRefs, header.ptr)
|
|
||||||
|
|
||||||
if (opt & EncodeOptionHTMLEscape) != 0 {
|
|
||||||
buf, err := encodeRunCode(ctx, b, codeSet, opt)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
ctx.buf = buf
|
|
||||||
return buf, nil
|
|
||||||
} else {
|
|
||||||
codeSet, err := encoder.CompileToGetCodeSet(typeptr)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
ctx := &encoder.RuntimeContext{}
|
|
||||||
ctx.Init(p, codeSet.CodeLength)
|
ctx.Init(p, codeSet.CodeLength)
|
||||||
buf, err := vm.Run(ctx, b, codeSet, encoder.Option(opt))
|
ctx.KeepRefs = append(ctx.KeepRefs, header.ptr)
|
||||||
|
|
||||||
|
buf, err := encodeRunCode(ctx, b, codeSet, opt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
ctx.Buf = buf
|
ctx.Buf = buf
|
||||||
return buf, nil
|
return buf, nil
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func encodeNoEscape(ctx *encodeRuntimeContext, v interface{}, opt EncodeOption) ([]byte, error) {
|
func encodeNoEscape(ctx *encoder.RuntimeContext, v interface{}, opt EncodeOption) ([]byte, error) {
|
||||||
b := ctx.buf[:0]
|
b := ctx.Buf[:0]
|
||||||
if v == nil {
|
if v == nil {
|
||||||
b = encodeNull(b)
|
b = encodeNull(b)
|
||||||
b = encodeComma(b)
|
b = encodeComma(b)
|
||||||
|
@ -245,19 +250,19 @@ func encodeNoEscape(ctx *encodeRuntimeContext, v interface{}, opt EncodeOption)
|
||||||
typ := header.typ
|
typ := header.typ
|
||||||
|
|
||||||
typeptr := uintptr(unsafe.Pointer(typ))
|
typeptr := uintptr(unsafe.Pointer(typ))
|
||||||
codeSet, err := encodeCompileToGetCodeSet(typeptr)
|
codeSet, err := encoder.CompileToGetCodeSet(typeptr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
p := uintptr(header.ptr)
|
p := uintptr(header.ptr)
|
||||||
ctx.init(p, codeSet.codeLength)
|
ctx.Init(p, codeSet.CodeLength)
|
||||||
buf, err := encodeRunCode(ctx, b, codeSet, opt)
|
buf, err := encodeRunCode(ctx, b, codeSet, opt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.buf = buf
|
ctx.Buf = buf
|
||||||
return buf, nil
|
return buf, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -291,11 +296,11 @@ func encodeIndent(ctx *encodeRuntimeContext, v interface{}, prefix, indent strin
|
||||||
return buf, nil
|
return buf, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func encodeRunCode(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet, opt EncodeOption) ([]byte, error) {
|
func encodeRunCode(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt EncodeOption) ([]byte, error) {
|
||||||
if (opt & EncodeOptionHTMLEscape) != 0 {
|
if (opt & EncodeOptionHTMLEscape) != 0 {
|
||||||
return encodeRunEscaped(ctx, b, codeSet, opt)
|
return vm_escaped.Run(ctx, b, codeSet, encoder.Option(opt))
|
||||||
}
|
}
|
||||||
return encodeRun(ctx, b, codeSet, opt)
|
return vm.Run(ctx, b, codeSet, encoder.Option(opt))
|
||||||
}
|
}
|
||||||
|
|
||||||
func encodeRunIndentCode(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet, prefix, indent string, opt EncodeOption) ([]byte, error) {
|
func encodeRunIndentCode(ctx *encodeRuntimeContext, b []byte, codeSet *opcodeSet, prefix, indent string, opt EncodeOption) ([]byte, error) {
|
||||||
|
|
4050
encode_vm.go
4050
encode_vm.go
File diff suppressed because it is too large
Load Diff
4091
encode_vm_escaped.go
4091
encode_vm_escaped.go
File diff suppressed because it is too large
Load Diff
|
@ -11,7 +11,7 @@ import (
|
||||||
|
|
||||||
var setsMu sync.RWMutex
|
var setsMu sync.RWMutex
|
||||||
|
|
||||||
func CompileToGetCodeSet(typeptr uintptr) (*opcodeSet, error) {
|
func CompileToGetCodeSet(typeptr uintptr) (*OpcodeSet, error) {
|
||||||
if typeptr > typeAddr.MaxTypeAddr {
|
if typeptr > typeAddr.MaxTypeAddr {
|
||||||
return compileToGetCodeSetSlowPath(typeptr)
|
return compileToGetCodeSetSlowPath(typeptr)
|
||||||
}
|
}
|
||||||
|
|
|
@ -476,3 +476,14 @@ func AppendComma(b []byte) []byte {
|
||||||
func AppendStructEnd(b []byte) []byte {
|
func AppendStructEnd(b []byte) []byte {
|
||||||
return append(b, '}', ',')
|
return append(b, '}', ',')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func IsNilForMarshaler(v interface{}) bool {
|
||||||
|
rv := reflect.ValueOf(v)
|
||||||
|
switch rv.Kind() {
|
||||||
|
case reflect.Interface, reflect.Map, reflect.Ptr:
|
||||||
|
return rv.IsNil()
|
||||||
|
case reflect.Slice:
|
||||||
|
return rv.IsNil() || rv.Len() == 0
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
|
@ -269,14 +269,14 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
||||||
b = bb
|
b = bb
|
||||||
code = code.Next
|
code = code.Next
|
||||||
case encoder.OpMarshalJSONPtr:
|
case encoder.OpMarshalJSONPtr:
|
||||||
p := loadNPtr(ctxptr, code.Idx, code.PtrNum)
|
p := load(ctxptr, code.Idx)
|
||||||
if p == 0 {
|
if p == 0 {
|
||||||
b = appendNull(b)
|
b = appendNull(b)
|
||||||
b = appendComma(b)
|
b = appendComma(b)
|
||||||
code = code.Next
|
code = code.Next
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
store(ctxptr, code.Idx, p)
|
store(ctxptr, code.Idx, ptrToPtr(p))
|
||||||
fallthrough
|
fallthrough
|
||||||
case encoder.OpMarshalJSON:
|
case encoder.OpMarshalJSON:
|
||||||
p := load(ctxptr, code.Idx)
|
p := load(ctxptr, code.Idx)
|
||||||
|
@ -293,14 +293,14 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
||||||
b = appendComma(bb)
|
b = appendComma(bb)
|
||||||
code = code.Next
|
code = code.Next
|
||||||
case encoder.OpMarshalTextPtr:
|
case encoder.OpMarshalTextPtr:
|
||||||
p := loadNPtr(ctxptr, code.Idx, code.PtrNum)
|
p := load(ctxptr, code.Idx)
|
||||||
if p == 0 {
|
if p == 0 {
|
||||||
b = appendNull(b)
|
b = appendNull(b)
|
||||||
b = appendComma(b)
|
b = appendComma(b)
|
||||||
code = code.Next
|
code = code.Next
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
store(ctxptr, code.Idx, p)
|
store(ctxptr, code.Idx, ptrToPtr(p))
|
||||||
fallthrough
|
fallthrough
|
||||||
case encoder.OpMarshalText:
|
case encoder.OpMarshalText:
|
||||||
p := load(ctxptr, code.Idx)
|
p := load(ctxptr, code.Idx)
|
||||||
|
@ -337,6 +337,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
||||||
}
|
}
|
||||||
store(ctxptr, code.ElemIdx, 0)
|
store(ctxptr, code.ElemIdx, 0)
|
||||||
store(ctxptr, code.Length, uintptr(slice.Len))
|
store(ctxptr, code.Length, uintptr(slice.Len))
|
||||||
|
store(ctxptr, code.Idx, uintptr(slice.Data))
|
||||||
if slice.Len > 0 {
|
if slice.Len > 0 {
|
||||||
b = append(b, '[')
|
b = append(b, '[')
|
||||||
code = code.Next
|
code = code.Next
|
||||||
|
@ -2815,11 +2816,12 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
|
||||||
p = ptrToPtr(p + code.Offset)
|
p = ptrToPtr(p + code.Offset)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if p == 0 && code.Nilcheck {
|
iface := ptrToInterface(code, p)
|
||||||
|
if code.Nilcheck && encoder.IsNilForMarshaler(iface) {
|
||||||
code = code.NextField
|
code = code.NextField
|
||||||
} else {
|
} else {
|
||||||
b = append(b, code.Key...)
|
b = append(b, code.Key...)
|
||||||
bb, err := appendMarshalJSON(code, b, ptrToInterface(code, p), false)
|
bb, err := appendMarshalJSON(code, b, iface, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue