mirror of https://github.com/goccy/go-json.git
Fix vm code
This commit is contained in:
parent
62b7d3ba0a
commit
10c4118a45
30
encode.go
30
encode.go
|
@ -13,7 +13,8 @@ import (
|
|||
"sync"
|
||||
"unsafe"
|
||||
|
||||
_ "github.com/goccy/go-json/internal/encoder/vm"
|
||||
"github.com/goccy/go-json/internal/encoder"
|
||||
"github.com/goccy/go-json/internal/encoder/vm"
|
||||
)
|
||||
|
||||
// An Encoder writes JSON values to an output stream.
|
||||
|
@ -208,16 +209,29 @@ func encode(ctx *encodeRuntimeContext, v interface{}, opt EncodeOption) ([]byte,
|
|||
|
||||
p := uintptr(header.ptr)
|
||||
ctx.init(p, codeSet.codeLength)
|
||||
buf, err := encodeRunCode(ctx, b, codeSet, opt)
|
||||
|
||||
ctx.keepRefs = append(ctx.keepRefs, header.ptr)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
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))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ctx.Buf = buf
|
||||
return buf, nil
|
||||
}
|
||||
|
||||
ctx.buf = buf
|
||||
return buf, nil
|
||||
}
|
||||
|
||||
func encodeNoEscape(ctx *encodeRuntimeContext, v interface{}, opt EncodeOption) ([]byte, error) {
|
||||
|
|
|
@ -140,7 +140,7 @@ func (t OpType) HeadToPtrHead() OpType {
|
|||
if idx == -1 {
|
||||
return t
|
||||
}
|
||||
suffix := "Ptr"+t.String()[idx+len("Head"):]
|
||||
suffix := "PtrHead"+t.String()[idx+len("Head"):]
|
||||
|
||||
const toPtrOffset = 3
|
||||
if strings.Contains(OpType(int(t) + toPtrOffset).String(), suffix) {
|
||||
|
@ -186,6 +186,9 @@ func (t OpType) FieldToEnd() OpType {
|
|||
return t
|
||||
}
|
||||
suffix := t.String()[idx+len("Field"):]
|
||||
if suffix == "" || suffix == "OmitEmpty" || suffix == "StringTag" {
|
||||
return t
|
||||
}
|
||||
const toEndOffset = 3
|
||||
if strings.Contains(OpType(int(t) + toEndOffset).String(), "End"+suffix) {
|
||||
return OpType(int(t) + toEndOffset)
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
package encoder
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
||||
"github.com/goccy/go-json/internal/errors"
|
||||
)
|
||||
|
||||
func compact(dst *bytes.Buffer, src []byte, escape bool) error {
|
||||
if len(src) == 0 {
|
||||
return errors.ErrUnexpectedEndOfJSON("", 0)
|
||||
}
|
||||
length := len(src)
|
||||
for cursor := 0; cursor < length; cursor++ {
|
||||
c := src[cursor]
|
||||
switch c {
|
||||
case ' ', '\t', '\n', '\r':
|
||||
continue
|
||||
case '"':
|
||||
if err := dst.WriteByte(c); err != nil {
|
||||
return err
|
||||
}
|
||||
for {
|
||||
cursor++
|
||||
c := src[cursor]
|
||||
if escape && (c == '<' || c == '>' || c == '&') {
|
||||
if _, err := dst.WriteString(`\u00`); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := dst.Write([]byte{hex[c>>4], hex[c&0xF]}); err != nil {
|
||||
return err
|
||||
}
|
||||
} else if err := dst.WriteByte(c); err != nil {
|
||||
return err
|
||||
}
|
||||
switch c {
|
||||
case '\\':
|
||||
cursor++
|
||||
if err := dst.WriteByte(src[cursor]); err != nil {
|
||||
return err
|
||||
}
|
||||
case '"':
|
||||
goto LOOP_END
|
||||
case '\000':
|
||||
return errors.ErrUnexpectedEndOfJSON("string", int64(length))
|
||||
}
|
||||
}
|
||||
default:
|
||||
if err := dst.WriteByte(c); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
LOOP_END:
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -299,6 +299,10 @@ func compile(ctx *compileContext, isPtr bool) (*Opcode, error) {
|
|||
func convertPtrOp(code *Opcode) OpType {
|
||||
ptrHeadOp := code.Op.HeadToPtrHead()
|
||||
if code.Op != ptrHeadOp {
|
||||
if code.PtrNum > 0 {
|
||||
// ptr field and ptr head
|
||||
code.PtrNum--
|
||||
}
|
||||
return ptrHeadOp
|
||||
}
|
||||
switch code.Op {
|
||||
|
|
|
@ -12,10 +12,10 @@ import (
|
|||
var setsMu sync.RWMutex
|
||||
|
||||
func CompileToGetCodeSet(typeptr uintptr) (*opcodeSet, error) {
|
||||
if typeptr > maxTypeAddr {
|
||||
if typeptr > typeAddr.MaxTypeAddr {
|
||||
return compileToGetCodeSetSlowPath(typeptr)
|
||||
}
|
||||
index := typeptr - baseTypeAddr
|
||||
index := typeptr - typeAddr.BaseTypeAddr
|
||||
setsMu.RLock()
|
||||
if codeSet := cachedOpcodeSets[index]; codeSet != nil {
|
||||
setsMu.RUnlock()
|
||||
|
@ -35,7 +35,7 @@ func CompileToGetCodeSet(typeptr uintptr) (*opcodeSet, error) {
|
|||
}
|
||||
code = copyOpcode(code)
|
||||
codeLength := code.TotalLength()
|
||||
codeSet := &opcodeSet{
|
||||
codeSet := &OpcodeSet{
|
||||
Code: code,
|
||||
CodeLength: codeLength,
|
||||
}
|
||||
|
|
|
@ -152,17 +152,22 @@ func Store(base uintptr, idx uintptr, p uintptr) {
|
|||
**(**uintptr)(unsafe.Pointer(&addr)) = p
|
||||
}
|
||||
|
||||
func LoadAndStoreNPtr(base uintptr, idx uintptr, ptrNum int) {
|
||||
func LoadNPtr(base uintptr, idx uintptr, ptrNum int) uintptr {
|
||||
addr := base + idx
|
||||
p := **(**uintptr)(unsafe.Pointer(&addr))
|
||||
for i := 0; i < ptrNum; i++ {
|
||||
if p == 0 {
|
||||
**(**uintptr)(unsafe.Pointer(&addr)) = 0
|
||||
return
|
||||
}
|
||||
p = PtrToPtr(p)
|
||||
if p == 0 {
|
||||
return 0
|
||||
}
|
||||
**(**uintptr)(unsafe.Pointer(&addr)) = p
|
||||
return PtrToPtr(p)
|
||||
/*
|
||||
for i := 0; i < ptrNum; i++ {
|
||||
if p == 0 {
|
||||
return p
|
||||
}
|
||||
p = PtrToPtr(p)
|
||||
}
|
||||
return p
|
||||
*/
|
||||
}
|
||||
|
||||
func PtrToUint64(p uintptr) uint64 { return **(**uint64)(unsafe.Pointer(&p)) }
|
||||
|
@ -426,13 +431,12 @@ func AppendMarshalJSON(code *Opcode, b []byte, v interface{}, escape bool) ([]by
|
|||
if err != nil {
|
||||
return nil, &errors.MarshalerError{Type: reflect.TypeOf(v), Err: err}
|
||||
}
|
||||
return bb, nil
|
||||
//buf := bytes.NewBuffer(b)
|
||||
//TODO: we should validate buffer with `compact`
|
||||
// if err := compact(buf, bb, escape); err != nil {
|
||||
// return nil, &errors.MarshalerError{Type: reflect.TypeOf(v), Err: err}
|
||||
// }
|
||||
//return buf.Bytes(), nil
|
||||
buf := bytes.NewBuffer(b)
|
||||
// TODO: we should validate buffer with `compact`
|
||||
if err := compact(buf, bb, escape); err != nil {
|
||||
return nil, &errors.MarshalerError{Type: reflect.TypeOf(v), Err: err}
|
||||
}
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
func AppendMarshalText(code *Opcode, b []byte, v interface{}, escape bool) ([]byte, error) {
|
||||
|
|
|
@ -427,7 +427,7 @@ func (c *Opcode) dumpValue(code *Opcode) string {
|
|||
)
|
||||
}
|
||||
|
||||
func (c *Opcode) dump() string {
|
||||
func (c *Opcode) Dump() string {
|
||||
codes := []string{}
|
||||
for code := c; code.Op != OpEnd; {
|
||||
switch code.Op.CodeType() {
|
||||
|
|
|
@ -955,7 +955,7 @@ func (t OpType) HeadToPtrHead() OpType {
|
|||
if idx == -1 {
|
||||
return t
|
||||
}
|
||||
suffix := "Ptr" + t.String()[idx+len("Head"):]
|
||||
suffix := "PtrHead" + t.String()[idx+len("Head"):]
|
||||
|
||||
const toPtrOffset = 3
|
||||
if strings.Contains(OpType(int(t)+toPtrOffset).String(), suffix) {
|
||||
|
@ -1001,6 +1001,9 @@ func (t OpType) FieldToEnd() OpType {
|
|||
return t
|
||||
}
|
||||
suffix := t.String()[idx+len("Field"):]
|
||||
if suffix == "" || suffix == "OmitEmpty" || suffix == "StringTag" {
|
||||
return t
|
||||
}
|
||||
const toEndOffset = 3
|
||||
if strings.Contains(OpType(int(t)+toEndOffset).String(), "End"+suffix) {
|
||||
return OpType(int(t) + toEndOffset)
|
||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue