Replace vm and escaped vm codes with internal package

This commit is contained in:
Masaaki Goshima 2021-03-17 12:32:23 +09:00
parent 10c4118a45
commit cccf9f9f33
8 changed files with 4565 additions and 8188 deletions

View File

@ -7,7 +7,7 @@ services:
deploy:
resources:
limits:
memory: 2048M
memory: 1200M
working_dir: /go/src/go-json
command: |
sh -c "go test -c . && ls go-json.test"

View File

@ -15,6 +15,7 @@ import (
"github.com/goccy/go-json/internal/encoder"
"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.
@ -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 {
@ -58,6 +68,14 @@ func releaseEncodeRuntimeContext(ctx *encodeRuntimeContext) {
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.
func NewEncoder(w io.Writer) *Encoder {
return &Encoder{w: w, enabledHTMLEscape: true}
@ -95,7 +113,9 @@ func (e *Encoder) encodeWithOption(ctx *encodeRuntimeContext, v interface{}, opt
if e.enabledIndent {
buf, err = encodeIndent(ctx, v, e.prefix, e.indentStr, opt)
} else {
ctx := takeEncodeRuntimeContext2()
buf, err = encode(ctx, v, opt)
releaseEncodeRuntimeContext2(ctx)
}
if err != nil {
return err
@ -133,11 +153,11 @@ func (e *Encoder) SetIndent(prefix, indent string) {
}
func marshal(v interface{}, opt EncodeOption) ([]byte, error) {
ctx := takeEncodeRuntimeContext()
ctx := takeEncodeRuntimeContext2()
buf, err := encode(ctx, v, opt|EncodeOptionHTMLEscape)
if err != nil {
releaseEncodeRuntimeContext(ctx)
releaseEncodeRuntimeContext2(ctx)
return nil, err
}
@ -149,16 +169,16 @@ func marshal(v interface{}, opt EncodeOption) ([]byte, error) {
copied := make([]byte, len(buf))
copy(copied, buf)
releaseEncodeRuntimeContext(ctx)
releaseEncodeRuntimeContext2(ctx)
return copied, nil
}
func marshalNoEscape(v interface{}, opt EncodeOption) ([]byte, error) {
ctx := takeEncodeRuntimeContext()
ctx := takeEncodeRuntimeContext2()
buf, err := encodeNoEscape(ctx, v, opt|EncodeOptionHTMLEscape)
if err != nil {
releaseEncodeRuntimeContext(ctx)
releaseEncodeRuntimeContext2(ctx)
return nil, err
}
@ -170,7 +190,7 @@ func marshalNoEscape(v interface{}, opt EncodeOption) ([]byte, error) {
copied := make([]byte, len(buf))
copy(copied, buf)
releaseEncodeRuntimeContext(ctx)
releaseEncodeRuntimeContext2(ctx)
return copied, nil
}
@ -191,8 +211,8 @@ func marshalIndent(v interface{}, prefix, indent string, opt EncodeOption) ([]by
return copied, nil
}
func encode(ctx *encodeRuntimeContext, v interface{}, opt EncodeOption) ([]byte, error) {
b := ctx.buf[:0]
func encode(ctx *encoder.RuntimeContext, v interface{}, opt EncodeOption) ([]byte, error) {
b := ctx.Buf[:0]
if v == nil {
b = encodeNull(b)
b = encodeComma(b)
@ -202,40 +222,25 @@ func encode(ctx *encodeRuntimeContext, v interface{}, opt EncodeOption) ([]byte,
typ := header.typ
typeptr := uintptr(unsafe.Pointer(typ))
codeSet, err := encodeCompileToGetCodeSet(typeptr)
codeSet, err := encoder.CompileToGetCodeSet(typeptr)
if err != nil {
return nil, err
}
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)
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 {
return nil, err
}
ctx.Buf = buf
return buf, nil
}
}
func encodeNoEscape(ctx *encodeRuntimeContext, v interface{}, opt EncodeOption) ([]byte, error) {
b := ctx.buf[:0]
func encodeNoEscape(ctx *encoder.RuntimeContext, v interface{}, opt EncodeOption) ([]byte, error) {
b := ctx.Buf[:0]
if v == nil {
b = encodeNull(b)
b = encodeComma(b)
@ -245,19 +250,19 @@ func encodeNoEscape(ctx *encodeRuntimeContext, v interface{}, opt EncodeOption)
typ := header.typ
typeptr := uintptr(unsafe.Pointer(typ))
codeSet, err := encodeCompileToGetCodeSet(typeptr)
codeSet, err := encoder.CompileToGetCodeSet(typeptr)
if err != nil {
return nil, err
}
p := uintptr(header.ptr)
ctx.init(p, codeSet.codeLength)
ctx.Init(p, codeSet.CodeLength)
buf, err := encodeRunCode(ctx, b, codeSet, opt)
if err != nil {
return nil, err
}
ctx.buf = buf
ctx.Buf = buf
return buf, nil
}
@ -291,11 +296,11 @@ func encodeIndent(ctx *encodeRuntimeContext, v interface{}, prefix, indent strin
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 {
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) {

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -11,7 +11,7 @@ import (
var setsMu sync.RWMutex
func CompileToGetCodeSet(typeptr uintptr) (*opcodeSet, error) {
func CompileToGetCodeSet(typeptr uintptr) (*OpcodeSet, error) {
if typeptr > typeAddr.MaxTypeAddr {
return compileToGetCodeSetSlowPath(typeptr)
}

View File

@ -476,3 +476,14 @@ func AppendComma(b []byte) []byte {
func AppendStructEnd(b []byte) []byte {
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
}

View File

@ -269,14 +269,14 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
b = bb
code = code.Next
case encoder.OpMarshalJSONPtr:
p := loadNPtr(ctxptr, code.Idx, code.PtrNum)
p := load(ctxptr, code.Idx)
if p == 0 {
b = appendNull(b)
b = appendComma(b)
code = code.Next
break
}
store(ctxptr, code.Idx, p)
store(ctxptr, code.Idx, ptrToPtr(p))
fallthrough
case encoder.OpMarshalJSON:
p := load(ctxptr, code.Idx)
@ -293,14 +293,14 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
b = appendComma(bb)
code = code.Next
case encoder.OpMarshalTextPtr:
p := loadNPtr(ctxptr, code.Idx, code.PtrNum)
p := load(ctxptr, code.Idx)
if p == 0 {
b = appendNull(b)
b = appendComma(b)
code = code.Next
break
}
store(ctxptr, code.Idx, p)
store(ctxptr, code.Idx, ptrToPtr(p))
fallthrough
case encoder.OpMarshalText:
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.Length, uintptr(slice.Len))
store(ctxptr, code.Idx, uintptr(slice.Data))
if slice.Len > 0 {
b = append(b, '[')
code = code.Next
@ -2815,11 +2816,12 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt
p = ptrToPtr(p + code.Offset)
}
}
if p == 0 && code.Nilcheck {
iface := ptrToInterface(code, p)
if code.Nilcheck && encoder.IsNilForMarshaler(iface) {
code = code.NextField
} else {
b = append(b, code.Key...)
bb, err := appendMarshalJSON(code, b, ptrToInterface(code, p), false)
bb, err := appendMarshalJSON(code, b, iface, false)
if err != nil {
return nil, err
}

File diff suppressed because it is too large Load Diff