Merge pull request #1 from goccy/feature/encode-vm

Support VirtualMachine for encoding
This commit is contained in:
Masaaki Goshima 2020-04-30 13:56:42 +09:00 committed by GitHub
commit 6a479c7159
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 1438 additions and 622 deletions

635
encode.go
View File

@ -1,15 +1,11 @@
package json
import (
"fmt"
"io"
"reflect"
"strconv"
"strings"
"sync"
"unsafe"
"golang.org/x/xerrors"
)
// An Encoder writes JSON values to an output stream.
@ -19,31 +15,28 @@ type Encoder struct {
pool sync.Pool
}
type EncodeOp func(*Encoder, *rtype, uintptr) error
const (
bufSize = 1024
)
type EncodeOpMap struct {
type opcodeMap struct {
sync.Map
}
func (m *EncodeOpMap) Get(k string) EncodeOp {
func (m *opcodeMap) Get(k string) *opcode {
if v, ok := m.Load(k); ok {
return v.(EncodeOp)
return v.(*opcode)
}
return nil
}
func (m *EncodeOpMap) Set(k string, op EncodeOp) {
func (m *opcodeMap) Set(k string, op *opcode) {
m.Store(k, op)
}
var (
encPool sync.Pool
cachedEncodeOp EncodeOpMap
errCompileSlowPath = xerrors.New("json: detect dynamic type ( interface{} ) and compile with slow path")
cachedOpcode opcodeMap
)
func init() {
@ -55,7 +48,7 @@ func init() {
}
},
}
cachedEncodeOp = EncodeOpMap{}
cachedOpcode = opcodeMap{}
}
// NewEncoder returns a new encoder that writes to w.
@ -163,6 +156,10 @@ func (e *Encoder) encodeBool(v bool) {
e.buf = strconv.AppendBool(e.buf, v)
}
func (e *Encoder) encodeBytes(b []byte) {
e.buf = append(e.buf, b...)
}
func (e *Encoder) encodeString(s string) {
b := *(*[]byte)(unsafe.Pointer(&s))
e.buf = append(e.buf, b...)
@ -179,616 +176,22 @@ func (e *Encoder) encode(v interface{}) error {
typ = typ.Elem()
}
name := typ.String()
if op := cachedEncodeOp.Get(name); op != nil {
if code := cachedOpcode.Get(name); code != nil {
p := uintptr(header.ptr)
op(e, typ, p)
code.ptr = p
if err := e.run(code); err != nil {
return err
}
return nil
}
op, err := e.compile(typ)
if err != nil {
if err == errCompileSlowPath {
slowOp, err := e.compileSlowPath(typ)
code, err := e.compile(typ)
if err != nil {
return err
}
op = slowOp
} else {
return err
}
}
if name != "" {
cachedEncodeOp.Set(name, op)
cachedOpcode.Set(name, code)
}
p := uintptr(header.ptr)
op(e, typ, p)
return nil
code.ptr = p
return e.run(code)
}
func (e *Encoder) compile(typ *rtype) (EncodeOp, error) {
switch typ.Kind() {
case reflect.Ptr:
return e.compilePtr(typ)
case reflect.Slice:
return e.compileSlice(typ)
case reflect.Struct:
return e.compileStruct(typ)
case reflect.Map:
return e.compileMap(typ)
case reflect.Array:
return e.compileArray(typ)
case reflect.Int:
return e.compileInt()
case reflect.Int8:
return e.compileInt8()
case reflect.Int16:
return e.compileInt16()
case reflect.Int32:
return e.compileInt32()
case reflect.Int64:
return e.compileInt64()
case reflect.Uint:
return e.compileUint()
case reflect.Uint8:
return e.compileUint8()
case reflect.Uint16:
return e.compileUint16()
case reflect.Uint32:
return e.compileUint32()
case reflect.Uint64:
return e.compileUint64()
case reflect.Uintptr:
return e.compileUint()
case reflect.Float32:
return e.compileFloat32()
case reflect.Float64:
return e.compileFloat64()
case reflect.String:
return e.compileString()
case reflect.Bool:
return e.compileBool()
case reflect.Interface:
return nil, errCompileSlowPath
}
return nil, xerrors.Errorf("failed to encode type %s: %w", typ.String(), ErrUnsupportedType)
}
func (e *Encoder) compileSlowPath(typ *rtype) (EncodeOp, error) {
switch typ.Kind() {
case reflect.Ptr:
return e.compilePtrSlowPath(typ)
case reflect.Slice:
return e.compileSliceSlowPath(typ)
case reflect.Struct:
return e.compileStructSlowPath(typ)
case reflect.Map:
return e.compileMapSlowPath(typ)
case reflect.Array:
return e.compileArraySlowPath(typ)
case reflect.Int:
return e.compileInt()
case reflect.Int8:
return e.compileInt8()
case reflect.Int16:
return e.compileInt16()
case reflect.Int32:
return e.compileInt32()
case reflect.Int64:
return e.compileInt64()
case reflect.Uint:
return e.compileUint()
case reflect.Uint8:
return e.compileUint8()
case reflect.Uint16:
return e.compileUint16()
case reflect.Uint32:
return e.compileUint32()
case reflect.Uint64:
return e.compileUint64()
case reflect.Uintptr:
return e.compileUint()
case reflect.Float32:
return e.compileFloat32()
case reflect.Float64:
return e.compileFloat64()
case reflect.String:
return e.compileString()
case reflect.Bool:
return e.compileBool()
case reflect.Interface:
return e.compileInterface()
}
return nil, xerrors.Errorf("failed to encode type %s: %w", typ.String(), ErrUnsupportedType)
}
func (e *Encoder) compilePtr(typ *rtype) (EncodeOp, error) {
elem := typ.Elem()
op, err := e.compile(elem)
if err != nil {
return nil, err
}
return func(enc *Encoder, typ *rtype, p uintptr) error {
return op(enc, elem, e.ptrToPtr(p))
}, nil
}
func (e *Encoder) compilePtrSlowPath(typ *rtype) (EncodeOp, error) {
elem := typ.Elem()
op, err := e.compileSlowPath(elem)
if err != nil {
return nil, err
}
return func(enc *Encoder, typ *rtype, p uintptr) error {
return op(enc, typ.Elem(), e.ptrToPtr(p))
}, nil
}
func (e *Encoder) compileInt() (EncodeOp, error) {
return func(enc *Encoder, typ *rtype, p uintptr) error {
enc.encodeInt(e.ptrToInt(p))
return nil
}, nil
}
func (e *Encoder) compileInt8() (EncodeOp, error) {
return func(enc *Encoder, typ *rtype, p uintptr) error {
enc.encodeInt8(e.ptrToInt8(p))
return nil
}, nil
}
func (e *Encoder) compileInt16() (EncodeOp, error) {
return func(enc *Encoder, typ *rtype, p uintptr) error {
enc.encodeInt16(e.ptrToInt16(p))
return nil
}, nil
}
func (e *Encoder) compileInt32() (EncodeOp, error) {
return func(enc *Encoder, typ *rtype, p uintptr) error {
enc.encodeInt32(e.ptrToInt32(p))
return nil
}, nil
}
func (e *Encoder) compileInt64() (EncodeOp, error) {
return func(enc *Encoder, typ *rtype, p uintptr) error {
enc.encodeInt64(e.ptrToInt64(p))
return nil
}, nil
}
func (e *Encoder) compileUint() (EncodeOp, error) {
return func(enc *Encoder, typ *rtype, p uintptr) error {
enc.encodeUint(e.ptrToUint(p))
return nil
}, nil
}
func (e *Encoder) compileUint8() (EncodeOp, error) {
return func(enc *Encoder, typ *rtype, p uintptr) error {
enc.encodeUint8(e.ptrToUint8(p))
return nil
}, nil
}
func (e *Encoder) compileUint16() (EncodeOp, error) {
return func(enc *Encoder, typ *rtype, p uintptr) error {
enc.encodeUint16(e.ptrToUint16(p))
return nil
}, nil
}
func (e *Encoder) compileUint32() (EncodeOp, error) {
return func(enc *Encoder, typ *rtype, p uintptr) error {
enc.encodeUint32(e.ptrToUint32(p))
return nil
}, nil
}
func (e *Encoder) compileUint64() (EncodeOp, error) {
return func(enc *Encoder, typ *rtype, p uintptr) error {
enc.encodeUint64(e.ptrToUint64(p))
return nil
}, nil
}
func (e *Encoder) compileFloat32() (EncodeOp, error) {
return func(enc *Encoder, typ *rtype, p uintptr) error {
enc.encodeFloat32(e.ptrToFloat32(p))
return nil
}, nil
}
func (e *Encoder) compileFloat64() (EncodeOp, error) {
return func(enc *Encoder, typ *rtype, p uintptr) error {
enc.encodeFloat64(e.ptrToFloat64(p))
return nil
}, nil
}
func (e *Encoder) compileString() (EncodeOp, error) {
return func(enc *Encoder, typ *rtype, p uintptr) error {
enc.encodeEscapedString(e.ptrToString(p))
return nil
}, nil
}
func (e *Encoder) compileBool() (EncodeOp, error) {
return func(enc *Encoder, typ *rtype, p uintptr) error {
enc.encodeBool(e.ptrToBool(p))
return nil
}, nil
}
func (e *Encoder) compileSlice(typ *rtype) (EncodeOp, error) {
elem := typ.Elem()
size := elem.Size()
op, err := e.compile(elem)
if err != nil {
return nil, err
}
return func(enc *Encoder, typ *rtype, base uintptr) error {
if base == 0 {
enc.encodeString("null")
return nil
}
enc.encodeByte('[')
slice := (*reflect.SliceHeader)(unsafe.Pointer(base))
num := slice.Len
for i := 0; i < num; i++ {
if err := op(enc, elem, slice.Data+uintptr(i)*size); err != nil {
return err
}
if i != num-1 {
enc.encodeByte(',')
}
}
enc.encodeByte(']')
return nil
}, nil
}
func (e *Encoder) compileSliceSlowPath(typ *rtype) (EncodeOp, error) {
op, err := e.compileSlowPath(typ.Elem())
if err != nil {
return nil, err
}
return func(enc *Encoder, typ *rtype, base uintptr) error {
if base == 0 {
enc.encodeString("null")
return nil
}
size := typ.Elem().Size()
enc.encodeByte('[')
slice := (*reflect.SliceHeader)(unsafe.Pointer(base))
num := slice.Len
for i := 0; i < num; i++ {
if err := op(enc, typ.Elem(), slice.Data+uintptr(i)*size); err != nil {
return err
}
if i != num-1 {
enc.encodeByte(',')
}
}
enc.encodeByte(']')
return nil
}, nil
}
func (e *Encoder) compileArray(typ *rtype) (EncodeOp, error) {
elem := typ.Elem()
alen := typ.Len()
size := elem.Size()
op, err := e.compile(elem)
if err != nil {
return nil, err
}
return func(enc *Encoder, typ *rtype, base uintptr) error {
if base == 0 {
enc.encodeString("null")
return nil
}
enc.encodeByte('[')
for i := 0; i < alen; i++ {
if i != 0 {
enc.encodeByte(',')
}
if err := op(enc, elem, base+uintptr(i)*size); err != nil {
return err
}
}
enc.encodeByte(']')
return nil
}, nil
}
func (e *Encoder) compileArraySlowPath(typ *rtype) (EncodeOp, error) {
elem := typ.Elem()
alen := typ.Len()
op, err := e.compileSlowPath(elem)
if err != nil {
return nil, err
}
return func(enc *Encoder, typ *rtype, base uintptr) error {
if base == 0 {
enc.encodeString("null")
return nil
}
elem := typ.Elem()
size := elem.Size()
enc.encodeByte('[')
for i := 0; i < alen; i++ {
if i != 0 {
enc.encodeByte(',')
}
if err := op(enc, elem, base+uintptr(i)*size); err != nil {
return err
}
}
enc.encodeByte(']')
return nil
}, nil
}
func (e *Encoder) getTag(field reflect.StructField) string {
return field.Tag.Get("json")
}
func (e *Encoder) isIgnoredStructField(field reflect.StructField) bool {
if field.PkgPath != "" && !field.Anonymous {
// private field
return true
}
tag := e.getTag(field)
if tag == "-" {
return true
}
return false
}
type encodeStructField struct {
op EncodeOp
fieldIndex int
}
func (e *Encoder) compileStruct(typ *rtype) (EncodeOp, error) {
fieldNum := typ.NumField()
opQueue := make([]*encodeStructField, 0, fieldNum)
for i := 0; i < fieldNum; i++ {
field := typ.Field(i)
if e.isIgnoredStructField(field) {
continue
}
keyName := field.Name
tag := e.getTag(field)
opts := strings.Split(tag, ",")
if len(opts) > 0 {
if opts[0] != "" {
keyName = opts[0]
}
}
fieldType := type2rtype(field.Type)
op, err := e.compile(fieldType)
if err != nil {
return nil, err
}
key := fmt.Sprintf(`"%s":`, keyName)
structField := &encodeStructField{fieldIndex: i}
structField.op = func(enc *Encoder, typ *rtype, base uintptr) error {
enc.encodeString(key)
return op(enc, fieldType, base+field.Offset)
}
opQueue = append(opQueue, structField)
}
queueNum := len(opQueue)
return func(enc *Encoder, typ *rtype, base uintptr) error {
if base == 0 {
enc.encodeString("null")
return nil
}
enc.encodeByte('{')
for i := 0; i < queueNum; i++ {
if err := opQueue[i].op(enc, typ, base); err != nil {
return err
}
if i != queueNum-1 {
enc.encodeByte(',')
}
}
enc.encodeByte('}')
return nil
}, nil
}
func (e *Encoder) compileStructSlowPath(typ *rtype) (EncodeOp, error) {
fieldNum := typ.NumField()
opQueue := make([]*encodeStructField, 0, fieldNum)
for i := 0; i < fieldNum; i++ {
field := typ.Field(i)
if e.isIgnoredStructField(field) {
continue
}
keyName := field.Name
tag := e.getTag(field)
opts := strings.Split(tag, ",")
if len(opts) > 0 {
if opts[0] != "" {
keyName = opts[0]
}
}
fieldType := type2rtype(field.Type)
op, err := e.compileSlowPath(fieldType)
if err != nil {
return nil, err
}
key := fmt.Sprintf(`"%s":`, keyName)
structField := &encodeStructField{fieldIndex: i}
structField.op = func(enc *Encoder, typ *rtype, base uintptr) error {
enc.encodeString(key)
fieldType := type2rtype(typ.Field(structField.fieldIndex).Type)
return op(enc, fieldType, base+field.Offset)
}
opQueue = append(opQueue, structField)
}
queueNum := len(opQueue)
return func(enc *Encoder, typ *rtype, base uintptr) error {
if base == 0 {
enc.encodeString("null")
return nil
}
enc.encodeByte('{')
for i := 0; i < queueNum; i++ {
if err := opQueue[i].op(enc, typ, base); err != nil {
return err
}
if i != queueNum-1 {
enc.encodeByte(',')
}
}
enc.encodeByte('}')
return nil
}, nil
}
//go:linkname mapiterinit reflect.mapiterinit
//go:noescape
func mapiterinit(mapType *rtype, m unsafe.Pointer) unsafe.Pointer
//go:linkname mapiterkey reflect.mapiterkey
//go:noescape
func mapiterkey(it unsafe.Pointer) unsafe.Pointer
//go:linkname mapiternext reflect.mapiternext
//go:noescape
func mapiternext(it unsafe.Pointer)
//go:linkname maplen reflect.maplen
//go:noescape
func maplen(m unsafe.Pointer) int
type valueType struct {
typ unsafe.Pointer
ptr unsafe.Pointer
}
func (e *Encoder) compileMap(typ *rtype) (EncodeOp, error) {
keyType := typ.Key()
keyOp, err := e.compile(keyType)
if err != nil {
return nil, err
}
valueType := typ.Elem()
valueOp, err := e.compile(valueType)
if err != nil {
return nil, err
}
return func(enc *Encoder, typ *rtype, base uintptr) error {
if base == 0 {
enc.encodeString("null")
return nil
}
enc.encodeByte('{')
mlen := maplen(unsafe.Pointer(base))
iter := mapiterinit(typ, unsafe.Pointer(base))
for i := 0; i < mlen; i++ {
key := mapiterkey(iter)
if i != 0 {
enc.encodeByte(',')
}
value := mapitervalue(iter)
keyptr := uintptr(key)
if err := keyOp(enc, keyType, keyptr); err != nil {
return err
}
enc.encodeByte(':')
valueptr := uintptr(value)
if err := valueOp(enc, valueType, valueptr); err != nil {
return err
}
mapiternext(iter)
}
enc.encodeByte('}')
return nil
}, nil
}
func (e *Encoder) compileMapSlowPath(typ *rtype) (EncodeOp, error) {
keyOp, err := e.compileSlowPath(typ.Key())
if err != nil {
return nil, err
}
valueOp, err := e.compileSlowPath(typ.Elem())
if err != nil {
return nil, err
}
return func(enc *Encoder, typ *rtype, base uintptr) error {
if base == 0 {
enc.encodeString("null")
return nil
}
enc.encodeByte('{')
mlen := maplen(unsafe.Pointer(base))
iter := mapiterinit(typ, unsafe.Pointer(base))
for i := 0; i < mlen; i++ {
key := mapiterkey(iter)
if i != 0 {
enc.encodeByte(',')
}
value := mapitervalue(iter)
keyptr := uintptr(key)
if err := keyOp(enc, typ.Key(), keyptr); err != nil {
return err
}
enc.encodeByte(':')
valueptr := uintptr(value)
if err := valueOp(enc, typ.Elem(), valueptr); err != nil {
return err
}
mapiternext(iter)
}
enc.encodeByte('}')
return nil
}, nil
}
func (e *Encoder) compileInterface() (EncodeOp, error) {
return func(enc *Encoder, typ *rtype, base uintptr) error {
v := *(*interface{})(unsafe.Pointer(&interfaceHeader{
typ: typ,
ptr: unsafe.Pointer(base),
}))
vv := reflect.ValueOf(v).Interface()
header := (*interfaceHeader)(unsafe.Pointer(&vv))
t := header.typ
if t.Kind() == reflect.Ptr {
t = t.Elem()
}
op, err := e.compileSlowPath(t)
if err != nil {
return err
}
return op(enc, t, uintptr(header.ptr))
}, nil
}
func (e *Encoder) ptrToPtr(p uintptr) uintptr { return *(*uintptr)(unsafe.Pointer(p)) }
func (e *Encoder) ptrToInt(p uintptr) int { return *(*int)(unsafe.Pointer(p)) }
func (e *Encoder) ptrToInt8(p uintptr) int8 { return *(*int8)(unsafe.Pointer(p)) }
func (e *Encoder) ptrToInt16(p uintptr) int16 { return *(*int16)(unsafe.Pointer(p)) }
func (e *Encoder) ptrToInt32(p uintptr) int32 { return *(*int32)(unsafe.Pointer(p)) }
func (e *Encoder) ptrToInt64(p uintptr) int64 { return *(*int64)(unsafe.Pointer(p)) }
func (e *Encoder) ptrToUint(p uintptr) uint { return *(*uint)(unsafe.Pointer(p)) }
func (e *Encoder) ptrToUint8(p uintptr) uint8 { return *(*uint8)(unsafe.Pointer(p)) }
func (e *Encoder) ptrToUint16(p uintptr) uint16 { return *(*uint16)(unsafe.Pointer(p)) }
func (e *Encoder) ptrToUint32(p uintptr) uint32 { return *(*uint32)(unsafe.Pointer(p)) }
func (e *Encoder) ptrToUint64(p uintptr) uint64 { return *(*uint64)(unsafe.Pointer(p)) }
func (e *Encoder) ptrToFloat32(p uintptr) float32 { return *(*float32)(unsafe.Pointer(p)) }
func (e *Encoder) ptrToFloat64(p uintptr) float64 { return *(*float64)(unsafe.Pointer(p)) }
func (e *Encoder) ptrToBool(p uintptr) bool { return *(*bool)(unsafe.Pointer(p)) }
func (e *Encoder) ptrToByte(p uintptr) byte { return *(*byte)(unsafe.Pointer(p)) }
func (e *Encoder) ptrToBytes(p uintptr) []byte { return *(*[]byte)(unsafe.Pointer(p)) }
func (e *Encoder) ptrToString(p uintptr) string { return *(*string)(unsafe.Pointer(p)) }

409
encode_compile.go Normal file
View File

@ -0,0 +1,409 @@
package json
import (
"fmt"
"reflect"
"strings"
"unsafe"
"golang.org/x/xerrors"
)
func (e *Encoder) compile(typ *rtype) (*opcode, error) {
switch typ.Kind() {
case reflect.Ptr:
return e.compilePtr(typ)
case reflect.Slice:
return e.compileSlice(typ)
case reflect.Array:
return e.compileArray(typ)
case reflect.Map:
return e.compileMap(typ)
case reflect.Struct:
return e.compileStruct(typ)
case reflect.Int:
return e.compileInt(typ)
case reflect.Int8:
return e.compileInt8(typ)
case reflect.Int16:
return e.compileInt16(typ)
case reflect.Int32:
return e.compileInt32(typ)
case reflect.Int64:
return e.compileInt64(typ)
case reflect.Uint:
return e.compileUint(typ)
case reflect.Uint8:
return e.compileUint8(typ)
case reflect.Uint16:
return e.compileUint16(typ)
case reflect.Uint32:
return e.compileUint32(typ)
case reflect.Uint64:
return e.compileUint64(typ)
case reflect.Uintptr:
return e.compileUint(typ)
case reflect.Float32:
return e.compileFloat32(typ)
case reflect.Float64:
return e.compileFloat64(typ)
case reflect.String:
return e.compileString(typ)
case reflect.Bool:
return e.compileBool(typ)
case reflect.Interface:
return e.compileInterface(typ)
}
return nil, xerrors.Errorf("failed to encode type %s: %w", typ.String(), ErrUnsupportedType)
}
func (e *Encoder) optimizeStructFieldPtrHead(typ *rtype, code *opcode) *opcode {
switch code.op {
case opStructFieldHead:
code.op = opStructFieldPtrHead
case opStructFieldHeadInt:
code.op = opStructFieldPtrHeadInt
case opStructFieldHeadInt8:
code.op = opStructFieldPtrHeadInt8
case opStructFieldHeadInt16:
code.op = opStructFieldPtrHeadInt16
case opStructFieldHeadInt32:
code.op = opStructFieldPtrHeadInt32
case opStructFieldHeadInt64:
code.op = opStructFieldPtrHeadInt64
case opStructFieldHeadUint:
code.op = opStructFieldPtrHeadUint
case opStructFieldHeadUint8:
code.op = opStructFieldPtrHeadUint8
case opStructFieldHeadUint16:
code.op = opStructFieldPtrHeadUint16
case opStructFieldHeadUint32:
code.op = opStructFieldPtrHeadUint32
case opStructFieldHeadUint64:
code.op = opStructFieldPtrHeadUint64
case opStructFieldHeadFloat32:
code.op = opStructFieldPtrHeadFloat32
case opStructFieldHeadFloat64:
code.op = opStructFieldPtrHeadFloat64
case opStructFieldHeadString:
code.op = opStructFieldPtrHeadString
case opStructFieldHeadBool:
code.op = opStructFieldPtrHeadBool
default:
return newOpCode(opPtr, typ, code)
}
return code
}
func (e *Encoder) compilePtr(typ *rtype) (*opcode, error) {
code, err := e.compile(typ.Elem())
if err != nil {
return nil, err
}
return e.optimizeStructFieldPtrHead(typ, code), nil
}
func (e *Encoder) compileInt(typ *rtype) (*opcode, error) {
return newOpCode(opInt, typ, newEndOp()), nil
}
func (e *Encoder) compileInt8(typ *rtype) (*opcode, error) {
return newOpCode(opInt8, typ, newEndOp()), nil
}
func (e *Encoder) compileInt16(typ *rtype) (*opcode, error) {
return newOpCode(opInt16, typ, newEndOp()), nil
}
func (e *Encoder) compileInt32(typ *rtype) (*opcode, error) {
return newOpCode(opInt32, typ, newEndOp()), nil
}
func (e *Encoder) compileInt64(typ *rtype) (*opcode, error) {
return newOpCode(opInt64, typ, newEndOp()), nil
}
func (e *Encoder) compileUint(typ *rtype) (*opcode, error) {
return newOpCode(opUint, typ, newEndOp()), nil
}
func (e *Encoder) compileUint8(typ *rtype) (*opcode, error) {
return newOpCode(opUint8, typ, newEndOp()), nil
}
func (e *Encoder) compileUint16(typ *rtype) (*opcode, error) {
return newOpCode(opUint16, typ, newEndOp()), nil
}
func (e *Encoder) compileUint32(typ *rtype) (*opcode, error) {
return newOpCode(opUint32, typ, newEndOp()), nil
}
func (e *Encoder) compileUint64(typ *rtype) (*opcode, error) {
return newOpCode(opUint64, typ, newEndOp()), nil
}
func (e *Encoder) compileFloat32(typ *rtype) (*opcode, error) {
return newOpCode(opFloat32, typ, newEndOp()), nil
}
func (e *Encoder) compileFloat64(typ *rtype) (*opcode, error) {
return newOpCode(opFloat64, typ, newEndOp()), nil
}
func (e *Encoder) compileString(typ *rtype) (*opcode, error) {
return newOpCode(opString, typ, newEndOp()), nil
}
func (e *Encoder) compileBool(typ *rtype) (*opcode, error) {
return newOpCode(opBool, typ, newEndOp()), nil
}
func (e *Encoder) compileInterface(typ *rtype) (*opcode, error) {
return newOpCode(opInterface, typ, newEndOp()), nil
}
func (e *Encoder) compileSlice(typ *rtype) (*opcode, error) {
elem := typ.Elem()
size := elem.Size()
code, err := e.compile(elem)
if err != nil {
return nil, err
}
// header => opcode => elem => end
// ^ |
// |________|
header := newSliceHeaderCode()
elemCode := &sliceElemCode{opcodeHeader: &opcodeHeader{op: opSliceElem}, size: size}
end := newOpCode(opSliceEnd, nil, newEndOp())
header.elem = elemCode
header.end = end
header.next = code
code.beforeLastCode().next = (*opcode)(unsafe.Pointer(elemCode))
elemCode.next = code
elemCode.end = end
return (*opcode)(unsafe.Pointer(header)), nil
}
func (e *Encoder) compileArray(typ *rtype) (*opcode, error) {
elem := typ.Elem()
alen := typ.Len()
size := elem.Size()
code, err := e.compile(elem)
if err != nil {
return nil, err
}
// header => opcode => elem => end
// ^ |
// |________|
header := newArrayHeaderCode(alen)
elemCode := &arrayElemCode{
opcodeHeader: &opcodeHeader{
op: opArrayElem,
},
len: uintptr(alen),
size: size,
}
end := newOpCode(opArrayEnd, nil, newEndOp())
header.elem = elemCode
header.end = end
header.next = code
code.beforeLastCode().next = (*opcode)(unsafe.Pointer(elemCode))
elemCode.next = code
elemCode.end = end
return (*opcode)(unsafe.Pointer(header)), nil
}
//go:linkname mapiterinit reflect.mapiterinit
//go:noescape
func mapiterinit(mapType *rtype, m unsafe.Pointer) unsafe.Pointer
//go:linkname mapiterkey reflect.mapiterkey
//go:noescape
func mapiterkey(it unsafe.Pointer) unsafe.Pointer
//go:linkname mapiternext reflect.mapiternext
//go:noescape
func mapiternext(it unsafe.Pointer)
//go:linkname maplen reflect.maplen
//go:noescape
func maplen(m unsafe.Pointer) int
func (e *Encoder) compileMap(typ *rtype) (*opcode, error) {
// header => code => value => code => key => code => value => code => end
// ^ |
// |_______________________|
keyType := typ.Key()
keyCode, err := e.compile(keyType)
if err != nil {
return nil, err
}
valueType := typ.Elem()
valueCode, err := e.compile(valueType)
if err != nil {
return nil, err
}
header := newMapHeaderCode(typ)
key := newMapKeyCode()
value := newMapValueCode()
header.key = key
header.value = value
end := newOpCode(opMapEnd, nil, newEndOp())
header.next = keyCode
keyCode.beforeLastCode().next = (*opcode)(unsafe.Pointer(value))
value.next = valueCode
valueCode.beforeLastCode().next = (*opcode)(unsafe.Pointer(key))
key.next = keyCode
header.end = end
key.end = end
return (*opcode)(unsafe.Pointer(header)), nil
}
func (e *Encoder) getTag(field reflect.StructField) string {
return field.Tag.Get("json")
}
func (e *Encoder) isIgnoredStructField(field reflect.StructField) bool {
if field.PkgPath != "" && !field.Anonymous {
// private field
return true
}
tag := e.getTag(field)
if tag == "-" {
return true
}
return false
}
func (e *Encoder) compileStruct(typ *rtype) (*opcode, error) {
// header => code => structField => code => end
// ^ |
// |__________|
fieldNum := typ.NumField()
fieldIdx := 0
var (
head *structFieldCode
code *opcode
prevField *structFieldCode
)
for i := 0; i < fieldNum; i++ {
field := typ.Field(i)
if e.isIgnoredStructField(field) {
continue
}
keyName := field.Name
tag := e.getTag(field)
opts := strings.Split(tag, ",")
if len(opts) > 0 {
if opts[0] != "" {
keyName = opts[0]
}
}
fieldType := type2rtype(field.Type)
valueCode, err := e.compile(fieldType)
if err != nil {
return nil, err
}
key := fmt.Sprintf(`"%s":`, keyName)
fieldCode := &structFieldCode{
opcodeHeader: &opcodeHeader{
typ: fieldType,
next: valueCode,
},
key: []byte(key),
offset: field.Offset,
}
if fieldIdx == 0 {
fieldCode.op = opStructFieldHead
head = fieldCode
code = (*opcode)(unsafe.Pointer(fieldCode))
prevField = fieldCode
switch valueCode.op {
case opInt:
fieldCode.op = opStructFieldHeadInt
case opInt8:
fieldCode.op = opStructFieldHeadInt8
case opInt16:
fieldCode.op = opStructFieldHeadInt16
case opInt32:
fieldCode.op = opStructFieldHeadInt32
case opInt64:
fieldCode.op = opStructFieldHeadInt64
case opUint:
fieldCode.op = opStructFieldHeadUint
case opUint8:
fieldCode.op = opStructFieldHeadUint8
case opUint16:
fieldCode.op = opStructFieldHeadUint16
case opUint32:
fieldCode.op = opStructFieldHeadUint32
case opUint64:
fieldCode.op = opStructFieldHeadUint64
case opFloat32:
fieldCode.op = opStructFieldHeadFloat32
case opFloat64:
fieldCode.op = opStructFieldHeadFloat64
case opString:
fieldCode.op = opStructFieldHeadString
case opBool:
fieldCode.op = opStructFieldHeadBool
default:
code = valueCode.beforeLastCode()
}
} else {
fieldCode.op = opStructField
code.next = (*opcode)(unsafe.Pointer(fieldCode))
prevField.nextField = (*opcode)(unsafe.Pointer(fieldCode))
prevField = fieldCode
code = (*opcode)(unsafe.Pointer(fieldCode))
switch valueCode.op {
case opInt:
fieldCode.op = opStructFieldInt
case opInt8:
fieldCode.op = opStructFieldInt8
case opInt16:
fieldCode.op = opStructFieldInt16
case opInt32:
fieldCode.op = opStructFieldInt32
case opInt64:
fieldCode.op = opStructFieldInt64
case opUint:
fieldCode.op = opStructFieldUint
case opUint8:
fieldCode.op = opStructFieldUint8
case opUint16:
fieldCode.op = opStructFieldUint16
case opUint32:
fieldCode.op = opStructFieldUint32
case opUint64:
fieldCode.op = opStructFieldUint64
case opFloat32:
fieldCode.op = opStructFieldFloat32
case opFloat64:
fieldCode.op = opStructFieldFloat64
case opString:
fieldCode.op = opStructFieldString
case opBool:
fieldCode.op = opStructFieldBool
default:
code = valueCode.beforeLastCode()
}
}
prevField.nextField = newEndOp()
fieldIdx++
}
structEndCode := newOpCode(opStructEnd, nil, nil)
head.end = structEndCode
code.next = structEndCode
structEndCode.next = newEndOp()
return (*opcode)(unsafe.Pointer(head)), nil
}

451
encode_opcode.go Normal file
View File

@ -0,0 +1,451 @@
package json
import (
"fmt"
"reflect"
"strings"
"unsafe"
)
type opType int
const (
opEnd opType = iota
opInt
opInt8
opInt16
opInt32
opInt64
opUint
opUint8
opUint16
opUint32
opUint64
opFloat32
opFloat64
opString
opBool
opInterface
opPtr
opSliceHead
opSliceElem
opSliceEnd
opArrayHead
opArrayElem
opArrayEnd
opMapHead
opMapKey
opMapValue
opMapEnd
opStructFieldHead
opStructFieldHeadInt
opStructFieldHeadInt8
opStructFieldHeadInt16
opStructFieldHeadInt32
opStructFieldHeadInt64
opStructFieldHeadUint
opStructFieldHeadUint8
opStructFieldHeadUint16
opStructFieldHeadUint32
opStructFieldHeadUint64
opStructFieldHeadFloat32
opStructFieldHeadFloat64
opStructFieldHeadString
opStructFieldHeadBool
opStructFieldPtrHead
opStructFieldPtrHeadInt
opStructFieldPtrHeadInt8
opStructFieldPtrHeadInt16
opStructFieldPtrHeadInt32
opStructFieldPtrHeadInt64
opStructFieldPtrHeadUint
opStructFieldPtrHeadUint8
opStructFieldPtrHeadUint16
opStructFieldPtrHeadUint32
opStructFieldPtrHeadUint64
opStructFieldPtrHeadFloat32
opStructFieldPtrHeadFloat64
opStructFieldPtrHeadString
opStructFieldPtrHeadBool
opStructField
opStructFieldInt
opStructFieldInt8
opStructFieldInt16
opStructFieldInt32
opStructFieldInt64
opStructFieldUint
opStructFieldUint8
opStructFieldUint16
opStructFieldUint32
opStructFieldUint64
opStructFieldFloat32
opStructFieldFloat64
opStructFieldString
opStructFieldBool
opStructEnd
)
func (t opType) String() string {
switch t {
case opEnd:
return "END"
case opInt:
return "INT"
case opInt8:
return "INT8"
case opInt16:
return "INT16"
case opInt32:
return "INT32"
case opInt64:
return "INT64"
case opUint:
return "UINT"
case opUint8:
return "UINT8"
case opUint16:
return "UINT16"
case opUint32:
return "UINT32"
case opUint64:
return "UINT64"
case opFloat32:
return "FLOAT32"
case opFloat64:
return "FLOAT64"
case opString:
return "STRING"
case opBool:
return "BOOL"
case opInterface:
return "INTERFACE"
case opPtr:
return "PTR"
case opSliceHead:
return "SLICE_HEAD"
case opSliceElem:
return "SLICE_ELEM"
case opSliceEnd:
return "SLICE_END"
case opArrayHead:
return "ARRAY_HEAD"
case opArrayElem:
return "ARRAY_ELEM"
case opArrayEnd:
return "ARRAY_END"
case opMapHead:
return "MAP_HEAD"
case opMapKey:
return "MAP_KEY"
case opMapValue:
return "MAP_VALUE"
case opMapEnd:
return "MAP_END"
case opStructFieldHead:
return "STRUCT_FIELD_HEAD"
case opStructFieldHeadInt:
return "STRUCT_FIELD_HEAD_INT"
case opStructFieldHeadInt8:
return "STRUCT_FIELD_HEAD_INT8"
case opStructFieldHeadInt16:
return "STRUCT_FIELD_HEAD_INT16"
case opStructFieldHeadInt32:
return "STRUCT_FIELD_HEAD_INT32"
case opStructFieldHeadInt64:
return "STRUCT_FIELD_HEAD_INT64"
case opStructFieldHeadUint:
return "STRUCT_FIELD_HEAD_UINT"
case opStructFieldHeadUint8:
return "STRUCT_FIELD_HEAD_UINT8"
case opStructFieldHeadUint16:
return "STRUCT_FIELD_HEAD_UINT16"
case opStructFieldHeadUint32:
return "STRUCT_FIELD_HEAD_UINT32"
case opStructFieldHeadUint64:
return "STRUCT_FIELD_HEAD_UINT64"
case opStructFieldHeadFloat32:
return "STRUCT_FIELD_HEAD_FLOAT32"
case opStructFieldHeadFloat64:
return "STRUCT_FIELD_HEAD_FLOAT64"
case opStructFieldHeadString:
return "STRUCT_FIELD_HEAD_STRING"
case opStructFieldHeadBool:
return "STRUCT_FIELD_HEAD_BOOL"
case opStructFieldPtrHead:
return "STRUCT_FIELD_PTR_HEAD"
case opStructFieldPtrHeadInt:
return "STRUCT_FIELD_PTR_HEAD_INT"
case opStructFieldPtrHeadInt8:
return "STRUCT_FIELD_PTR_HEAD_INT8"
case opStructFieldPtrHeadInt16:
return "STRUCT_FIELD_PTR_HEAD_INT16"
case opStructFieldPtrHeadInt32:
return "STRUCT_FIELD_PTR_HEAD_INT32"
case opStructFieldPtrHeadInt64:
return "STRUCT_FIELD_PTR_HEAD_INT64"
case opStructFieldPtrHeadUint:
return "STRUCT_FIELD_PTR_HEAD_UINT"
case opStructFieldPtrHeadUint8:
return "STRUCT_FIELD_PTR_HEAD_UINT8"
case opStructFieldPtrHeadUint16:
return "STRUCT_FIELD_PTR_HEAD_UINT16"
case opStructFieldPtrHeadUint32:
return "STRUCT_FIELD_PTR_HEAD_UINT32"
case opStructFieldPtrHeadUint64:
return "STRUCT_FIELD_PTR_HEAD_UINT64"
case opStructFieldPtrHeadFloat32:
return "STRUCT_FIELD_PTR_HEAD_FLOAT32"
case opStructFieldPtrHeadFloat64:
return "STRUCT_FIELD_PTR_HEAD_FLOAT64"
case opStructFieldPtrHeadString:
return "STRUCT_FIELD_PTR_HEAD_STRING"
case opStructFieldPtrHeadBool:
return "STRUCT_FIELD_PTR_HEAD_BOOL"
case opStructField:
return "STRUCT_FIELD"
case opStructFieldInt:
return "STRUCT_FIELD_INT"
case opStructFieldInt8:
return "STRUCT_FIELD_INT8"
case opStructFieldInt16:
return "STRUCT_FIELD_INT16"
case opStructFieldInt32:
return "STRUCT_FIELD_INT32"
case opStructFieldInt64:
return "STRUCT_FIELD_INT64"
case opStructFieldUint:
return "STRUCT_FIELD_UINT"
case opStructFieldUint8:
return "STRUCT_FIELD_UINT8"
case opStructFieldUint16:
return "STRUCT_FIELD_UINT16"
case opStructFieldUint32:
return "STRUCT_FIELD_UINT32"
case opStructFieldUint64:
return "STRUCT_FIELD_UINT64"
case opStructFieldFloat32:
return "STRUCT_FIELD_FLOAT32"
case opStructFieldFloat64:
return "STRUCT_FIELD_FLOAT64"
case opStructFieldString:
return "STRUCT_FIELD_STRING"
case opStructFieldBool:
return "STRUCT_FIELD_BOOL"
case opStructEnd:
return "STRUCT_END"
}
return ""
}
type opcodeHeader struct {
op opType
typ *rtype
ptr uintptr
next *opcode
}
type opcode struct {
*opcodeHeader
}
func newOpCode(op opType, typ *rtype, next *opcode) *opcode {
return &opcode{
opcodeHeader: &opcodeHeader{
op: op,
typ: typ,
next: next,
},
}
}
func newEndOp() *opcode {
return newOpCode(opEnd, nil, nil)
}
func (c *opcode) beforeLastCode() *opcode {
code := c
for {
var nextCode *opcode
switch code.op {
case opArrayElem:
nextCode = code.toArrayElemCode().end
case opSliceElem:
nextCode = code.toSliceElemCode().end
case opMapKey:
nextCode = code.toMapKeyCode().end
default:
nextCode = code.next
}
if nextCode.op == opEnd {
return code
}
code = nextCode
}
return nil
}
func (c *opcode) dump() string {
codes := []string{}
for code := c; code.op != opEnd; {
codes = append(codes, fmt.Sprintf("%s", code.op))
switch code.op {
case opArrayElem:
code = code.toArrayElemCode().end
case opSliceElem:
code = code.toSliceElemCode().end
case opMapKey:
code = code.toMapKeyCode().end
default:
code = code.next
}
}
return strings.Join(codes, "\n")
}
func (c *opcode) toSliceHeaderCode() *sliceHeaderCode {
return (*sliceHeaderCode)(unsafe.Pointer(c))
}
func (c *opcode) toSliceElemCode() *sliceElemCode {
return (*sliceElemCode)(unsafe.Pointer(c))
}
func (c *opcode) toArrayHeaderCode() *arrayHeaderCode {
return (*arrayHeaderCode)(unsafe.Pointer(c))
}
func (c *opcode) toArrayElemCode() *arrayElemCode {
return (*arrayElemCode)(unsafe.Pointer(c))
}
func (c *opcode) toStructFieldCode() *structFieldCode {
return (*structFieldCode)(unsafe.Pointer(c))
}
func (c *opcode) toMapHeadCode() *mapHeaderCode {
return (*mapHeaderCode)(unsafe.Pointer(c))
}
func (c *opcode) toMapKeyCode() *mapKeyCode {
return (*mapKeyCode)(unsafe.Pointer(c))
}
func (c *opcode) toMapValueCode() *mapValueCode {
return (*mapValueCode)(unsafe.Pointer(c))
}
type sliceHeaderCode struct {
*opcodeHeader
elem *sliceElemCode
end *opcode
}
func newSliceHeaderCode() *sliceHeaderCode {
return &sliceHeaderCode{
opcodeHeader: &opcodeHeader{
op: opSliceHead,
},
}
}
type sliceElemCode struct {
*opcodeHeader
idx uintptr
len uintptr
size uintptr
data uintptr
end *opcode
}
func (c *sliceElemCode) set(header *reflect.SliceHeader) {
c.idx = uintptr(0)
c.len = uintptr(header.Len)
c.data = header.Data
}
type arrayHeaderCode struct {
*opcodeHeader
len uintptr
elem *arrayElemCode
end *opcode
}
func newArrayHeaderCode(alen int) *arrayHeaderCode {
return &arrayHeaderCode{
opcodeHeader: &opcodeHeader{
op: opArrayHead,
},
len: uintptr(alen),
}
}
type arrayElemCode struct {
*opcodeHeader
idx uintptr
len uintptr
size uintptr
end *opcode
}
type structFieldCode struct {
*opcodeHeader
key []byte
offset uintptr
nextField *opcode
end *opcode
}
type mapHeaderCode struct {
*opcodeHeader
key *mapKeyCode
value *mapValueCode
end *opcode
}
type mapKeyCode struct {
*opcodeHeader
idx int
len int
iter unsafe.Pointer
end *opcode
}
func (c *mapKeyCode) set(len int, iter unsafe.Pointer) {
c.idx = 0
c.len = len
c.iter = iter
}
type mapValueCode struct {
*opcodeHeader
iter unsafe.Pointer
}
func (c *mapValueCode) set(iter unsafe.Pointer) {
c.iter = iter
}
func newMapHeaderCode(typ *rtype) *mapHeaderCode {
return &mapHeaderCode{
opcodeHeader: &opcodeHeader{
op: opMapHead,
typ: typ,
},
}
}
func newMapKeyCode() *mapKeyCode {
return &mapKeyCode{
opcodeHeader: &opcodeHeader{
op: opMapKey,
},
}
}
func newMapValueCode() *mapValueCode {
return &mapValueCode{
opcodeHeader: &opcodeHeader{
op: opMapValue,
},
}
}

View File

@ -93,10 +93,18 @@ func Test_Encoder(t *testing.T) {
assertEq(t, "struct", `{"a":-1,"b":1,"c":"hello world"}`, string(bytes))
})
t.Run("slice", func(t *testing.T) {
t.Run("[]int", func(t *testing.T) {
bytes, err := json.Marshal([]int{1, 2, 3, 4})
assertErr(t, err)
assertEq(t, "slice", `[1,2,3,4]`, string(bytes))
assertEq(t, "[]int", `[1,2,3,4]`, string(bytes))
})
t.Run("[]interface{}", func(t *testing.T) {
bytes, err := json.Marshal([]interface{}{1, 2.1, "hello"})
assertErr(t, err)
assertEq(t, "[]interface{}", `[1,2.1,"hello"]`, string(bytes))
})
})
t.Run("array", func(t *testing.T) {
bytes, err := json.Marshal([4]int{1, 2, 3, 4})
assertErr(t, err)

545
encode_vm.go Normal file
View File

@ -0,0 +1,545 @@
package json
import (
"reflect"
"unsafe"
)
func (e *Encoder) run(code *opcode) error {
for {
switch code.op {
case opPtr:
ptr := code.ptr
code = code.next
code.ptr = e.ptrToPtr(ptr)
case opInt:
e.encodeInt(e.ptrToInt(code.ptr))
code = code.next
case opInt8:
e.encodeInt8(e.ptrToInt8(code.ptr))
code = code.next
case opInt16:
e.encodeInt16(e.ptrToInt16(code.ptr))
code = code.next
case opInt32:
e.encodeInt32(e.ptrToInt32(code.ptr))
code = code.next
case opInt64:
e.encodeInt64(e.ptrToInt64(code.ptr))
code = code.next
case opUint:
e.encodeUint(e.ptrToUint(code.ptr))
code = code.next
case opUint8:
e.encodeUint8(e.ptrToUint8(code.ptr))
code = code.next
case opUint16:
e.encodeUint16(e.ptrToUint16(code.ptr))
code = code.next
case opUint32:
e.encodeUint32(e.ptrToUint32(code.ptr))
code = code.next
case opUint64:
e.encodeUint64(e.ptrToUint64(code.ptr))
code = code.next
case opFloat32:
e.encodeFloat32(e.ptrToFloat32(code.ptr))
code = code.next
case opFloat64:
e.encodeFloat64(e.ptrToFloat64(code.ptr))
code = code.next
case opString:
e.encodeEscapedString(e.ptrToString(code.ptr))
code = code.next
case opBool:
e.encodeBool(e.ptrToBool(code.ptr))
code = code.next
case opInterface:
ptr := code.ptr
v := *(*interface{})(unsafe.Pointer(&interfaceHeader{
typ: code.typ,
ptr: unsafe.Pointer(ptr),
}))
vv := reflect.ValueOf(v).Interface()
header := (*interfaceHeader)(unsafe.Pointer(&vv))
typ := header.typ
if typ.Kind() == reflect.Ptr {
typ = typ.Elem()
}
c, err := e.compile(typ)
if err != nil {
return err
}
c.ptr = uintptr(header.ptr)
c.beforeLastCode().next = code.next
code = c
case opSliceHead:
p := code.ptr
headerCode := code.toSliceHeaderCode()
if p == 0 {
e.encodeString("null")
code = headerCode.end.next
} else {
e.encodeByte('[')
header := (*reflect.SliceHeader)(unsafe.Pointer(p))
headerCode.elem.set(header)
if header.Len > 0 {
code = code.next
code.ptr = header.Data
} else {
e.encodeByte(']')
code = headerCode.end.next
}
}
case opSliceElem:
c := code.toSliceElemCode()
c.idx++
if c.idx < c.len {
e.encodeByte(',')
code = code.next
code.ptr = c.data + c.idx*c.size
} else {
e.encodeByte(']')
code = c.end.next
}
case opArrayHead:
p := code.ptr
headerCode := code.toArrayHeaderCode()
if p == 0 {
e.encodeString("null")
code = headerCode.end.next
} else {
e.encodeByte('[')
if headerCode.len > 0 {
code = code.next
code.ptr = p
headerCode.elem.ptr = p
} else {
e.encodeByte(']')
code = headerCode.end.next
}
}
case opArrayElem:
c := code.toArrayElemCode()
c.idx++
if c.idx < c.len {
e.encodeByte(',')
code = code.next
code.ptr = c.ptr + c.idx*c.size
} else {
e.encodeByte(']')
code = c.end.next
}
case opMapHead:
ptr := code.ptr
mapHeadCode := code.toMapHeadCode()
if ptr == 0 {
e.encodeString("null")
code = mapHeadCode.end.next
} else {
e.encodeByte('{')
mlen := maplen(unsafe.Pointer(ptr))
if mlen > 0 {
iter := mapiterinit(code.typ, unsafe.Pointer(ptr))
mapHeadCode.key.set(mlen, iter)
mapHeadCode.value.set(iter)
key := mapiterkey(iter)
code.next.ptr = uintptr(key)
code = code.next
} else {
e.encodeByte('}')
code = mapHeadCode.end.next
}
}
case opMapKey:
c := code.toMapKeyCode()
c.idx++
if c.idx < c.len {
e.encodeByte(',')
key := mapiterkey(c.iter)
c.next.ptr = uintptr(key)
code = c.next
} else {
e.encodeByte('}')
code = c.end.next
}
case opMapValue:
e.encodeByte(':')
c := code.toMapValueCode()
value := mapitervalue(c.iter)
c.next.ptr = uintptr(value)
mapiternext(c.iter)
code = c.next
case opStructFieldPtrHead:
code.ptr = e.ptrToPtr(code.ptr)
fallthrough
case opStructFieldHead:
field := code.toStructFieldCode()
ptr := field.ptr
if ptr == 0 {
e.encodeString("null")
code = field.end
} else {
e.encodeByte('{')
e.encodeBytes(field.key)
code = field.next
code.ptr = field.ptr + field.offset
field.nextField.ptr = field.ptr
}
case opStructFieldPtrHeadInt:
code.ptr = e.ptrToPtr(code.ptr)
fallthrough
case opStructFieldHeadInt:
field := code.toStructFieldCode()
ptr := field.ptr
if ptr == 0 {
e.encodeString("null")
code = field.end
} else {
e.encodeByte('{')
e.encodeBytes(field.key)
e.encodeInt(e.ptrToInt(field.ptr + field.offset))
field.nextField.ptr = field.ptr
code = field.next
}
case opStructFieldPtrHeadInt8:
code.ptr = e.ptrToPtr(code.ptr)
fallthrough
case opStructFieldHeadInt8:
field := code.toStructFieldCode()
ptr := field.ptr
if ptr == 0 {
e.encodeString("null")
code = field.end
} else {
e.encodeByte('{')
e.encodeBytes(field.key)
e.encodeInt8(e.ptrToInt8(field.ptr + field.offset))
field.nextField.ptr = field.ptr
code = field.next
}
case opStructFieldPtrHeadInt16:
code.ptr = e.ptrToPtr(code.ptr)
fallthrough
case opStructFieldHeadInt16:
field := code.toStructFieldCode()
ptr := field.ptr
if ptr == 0 {
e.encodeString("null")
code = field.end
} else {
e.encodeByte('{')
e.encodeBytes(field.key)
e.encodeInt16(e.ptrToInt16(field.ptr + field.offset))
field.nextField.ptr = field.ptr
code = field.next
}
case opStructFieldPtrHeadInt32:
code.ptr = e.ptrToPtr(code.ptr)
fallthrough
case opStructFieldHeadInt32:
field := code.toStructFieldCode()
ptr := field.ptr
if ptr == 0 {
e.encodeString("null")
code = field.end
} else {
e.encodeByte('{')
e.encodeBytes(field.key)
e.encodeInt32(e.ptrToInt32(field.ptr + field.offset))
field.nextField.ptr = field.ptr
code = field.next
}
case opStructFieldPtrHeadInt64:
code.ptr = e.ptrToPtr(code.ptr)
fallthrough
case opStructFieldHeadInt64:
field := code.toStructFieldCode()
ptr := field.ptr
if ptr == 0 {
e.encodeString("null")
code = field.end
} else {
e.encodeByte('{')
e.encodeBytes(field.key)
e.encodeInt64(e.ptrToInt64(field.ptr + field.offset))
field.nextField.ptr = field.ptr
code = field.next
}
case opStructFieldPtrHeadUint:
code.ptr = e.ptrToPtr(code.ptr)
fallthrough
case opStructFieldHeadUint:
field := code.toStructFieldCode()
ptr := field.ptr
if ptr == 0 {
e.encodeString("null")
code = field.end
} else {
e.encodeByte('{')
e.encodeBytes(field.key)
e.encodeUint(e.ptrToUint(field.ptr + field.offset))
field.nextField.ptr = field.ptr
code = field.next
}
case opStructFieldPtrHeadUint8:
code.ptr = e.ptrToPtr(code.ptr)
fallthrough
case opStructFieldHeadUint8:
field := code.toStructFieldCode()
ptr := field.ptr
if ptr == 0 {
e.encodeString("null")
code = field.end
} else {
e.encodeByte('{')
e.encodeBytes(field.key)
e.encodeUint8(e.ptrToUint8(field.ptr + field.offset))
field.nextField.ptr = field.ptr
code = field.next
}
case opStructFieldPtrHeadUint16:
code.ptr = e.ptrToPtr(code.ptr)
fallthrough
case opStructFieldHeadUint16:
field := code.toStructFieldCode()
ptr := field.ptr
if ptr == 0 {
e.encodeString("null")
code = field.end
} else {
e.encodeByte('{')
e.encodeBytes(field.key)
e.encodeUint16(e.ptrToUint16(field.ptr + field.offset))
field.nextField.ptr = field.ptr
code = field.next
}
case opStructFieldPtrHeadUint32:
code.ptr = e.ptrToPtr(code.ptr)
fallthrough
case opStructFieldHeadUint32:
field := code.toStructFieldCode()
ptr := field.ptr
if ptr == 0 {
e.encodeString("null")
code = field.end
} else {
e.encodeByte('{')
e.encodeBytes(field.key)
e.encodeUint32(e.ptrToUint32(field.ptr + field.offset))
field.nextField.ptr = field.ptr
code = field.next
}
case opStructFieldPtrHeadUint64:
code.ptr = e.ptrToPtr(code.ptr)
fallthrough
case opStructFieldHeadUint64:
field := code.toStructFieldCode()
ptr := field.ptr
if ptr == 0 {
e.encodeString("null")
code = field.end
} else {
e.encodeByte('{')
e.encodeBytes(field.key)
e.encodeUint64(e.ptrToUint64(field.ptr + field.offset))
field.nextField.ptr = field.ptr
code = field.next
}
case opStructFieldPtrHeadFloat32:
code.ptr = e.ptrToPtr(code.ptr)
fallthrough
case opStructFieldHeadFloat32:
field := code.toStructFieldCode()
ptr := field.ptr
if ptr == 0 {
e.encodeString("null")
code = field.end
} else {
e.encodeByte('{')
e.encodeBytes(field.key)
e.encodeFloat32(e.ptrToFloat32(field.ptr + field.offset))
field.nextField.ptr = field.ptr
code = field.next
}
case opStructFieldPtrHeadFloat64:
code.ptr = e.ptrToPtr(code.ptr)
fallthrough
case opStructFieldHeadFloat64:
field := code.toStructFieldCode()
ptr := field.ptr
if ptr == 0 {
e.encodeString("null")
code = field.end
} else {
e.encodeByte('{')
e.encodeBytes(field.key)
e.encodeFloat64(e.ptrToFloat64(field.ptr + field.offset))
field.nextField.ptr = field.ptr
code = field.next
}
case opStructFieldPtrHeadString:
code.ptr = e.ptrToPtr(code.ptr)
fallthrough
case opStructFieldHeadString:
field := code.toStructFieldCode()
ptr := field.ptr
if ptr == 0 {
e.encodeString("null")
code = field.end
} else {
e.encodeByte('{')
e.encodeBytes(field.key)
e.encodeEscapedString(e.ptrToString(field.ptr + field.offset))
field.nextField.ptr = field.ptr
code = field.next
}
case opStructFieldPtrHeadBool:
code.ptr = e.ptrToPtr(code.ptr)
fallthrough
case opStructFieldHeadBool:
field := code.toStructFieldCode()
ptr := field.ptr
if ptr == 0 {
e.encodeString("null")
code = field.end
} else {
e.encodeByte('{')
e.encodeBytes(field.key)
e.encodeBool(e.ptrToBool(field.ptr + field.offset))
field.nextField.ptr = field.ptr
code = field.next
}
case opStructField:
e.encodeByte(',')
c := code.toStructFieldCode()
e.encodeBytes(c.key)
code = code.next
code.ptr = c.ptr + c.offset
c.nextField.ptr = c.ptr
case opStructFieldInt:
e.encodeByte(',')
c := code.toStructFieldCode()
c.nextField.ptr = c.ptr
e.encodeBytes(c.key)
e.encodeInt(e.ptrToInt(c.ptr + c.offset))
code = code.next
case opStructFieldInt8:
e.encodeByte(',')
c := code.toStructFieldCode()
c.nextField.ptr = c.ptr
e.encodeBytes(c.key)
e.encodeInt8(e.ptrToInt8(c.ptr + c.offset))
code = code.next
case opStructFieldInt16:
e.encodeByte(',')
c := code.toStructFieldCode()
c.nextField.ptr = c.ptr
e.encodeBytes(c.key)
e.encodeInt16(e.ptrToInt16(c.ptr + c.offset))
code = code.next
case opStructFieldInt32:
e.encodeByte(',')
c := code.toStructFieldCode()
c.nextField.ptr = c.ptr
e.encodeBytes(c.key)
e.encodeInt32(e.ptrToInt32(c.ptr + c.offset))
code = code.next
case opStructFieldInt64:
e.encodeByte(',')
c := code.toStructFieldCode()
c.nextField.ptr = c.ptr
e.encodeBytes(c.key)
e.encodeInt64(e.ptrToInt64(c.ptr + c.offset))
code = code.next
case opStructFieldUint:
e.encodeByte(',')
c := code.toStructFieldCode()
c.nextField.ptr = c.ptr
e.encodeBytes(c.key)
e.encodeUint(e.ptrToUint(c.ptr + c.offset))
code = code.next
case opStructFieldUint8:
e.encodeByte(',')
c := code.toStructFieldCode()
c.nextField.ptr = c.ptr
e.encodeBytes(c.key)
e.encodeUint8(e.ptrToUint8(c.ptr + c.offset))
code = code.next
case opStructFieldUint16:
e.encodeByte(',')
c := code.toStructFieldCode()
c.nextField.ptr = c.ptr
e.encodeBytes(c.key)
e.encodeUint16(e.ptrToUint16(c.ptr + c.offset))
code = code.next
case opStructFieldUint32:
e.encodeByte(',')
c := code.toStructFieldCode()
c.nextField.ptr = c.ptr
e.encodeBytes(c.key)
e.encodeUint32(e.ptrToUint32(c.ptr + c.offset))
code = code.next
case opStructFieldUint64:
e.encodeByte(',')
c := code.toStructFieldCode()
c.nextField.ptr = c.ptr
e.encodeBytes(c.key)
e.encodeUint64(e.ptrToUint64(c.ptr + c.offset))
code = code.next
case opStructFieldFloat32:
e.encodeByte(',')
c := code.toStructFieldCode()
c.nextField.ptr = c.ptr
e.encodeBytes(c.key)
e.encodeFloat32(e.ptrToFloat32(c.ptr + c.offset))
code = code.next
case opStructFieldFloat64:
e.encodeByte(',')
c := code.toStructFieldCode()
c.nextField.ptr = c.ptr
e.encodeBytes(c.key)
e.encodeFloat64(e.ptrToFloat64(c.ptr + c.offset))
code = code.next
case opStructFieldString:
e.encodeByte(',')
c := code.toStructFieldCode()
c.nextField.ptr = c.ptr
e.encodeBytes(c.key)
e.encodeEscapedString(e.ptrToString(c.ptr + c.offset))
code = code.next
case opStructFieldBool:
e.encodeByte(',')
c := code.toStructFieldCode()
c.nextField.ptr = c.ptr
e.encodeBytes(c.key)
e.encodeBool(e.ptrToBool(c.ptr + c.offset))
code = code.next
case opStructEnd:
e.encodeByte('}')
code = code.next
case opEnd:
goto END
}
}
END:
return nil
}
func (e *Encoder) ptrToPtr(p uintptr) uintptr { return *(*uintptr)(unsafe.Pointer(p)) }
func (e *Encoder) ptrToInt(p uintptr) int { return *(*int)(unsafe.Pointer(p)) }
func (e *Encoder) ptrToInt8(p uintptr) int8 { return *(*int8)(unsafe.Pointer(p)) }
func (e *Encoder) ptrToInt16(p uintptr) int16 { return *(*int16)(unsafe.Pointer(p)) }
func (e *Encoder) ptrToInt32(p uintptr) int32 { return *(*int32)(unsafe.Pointer(p)) }
func (e *Encoder) ptrToInt64(p uintptr) int64 { return *(*int64)(unsafe.Pointer(p)) }
func (e *Encoder) ptrToUint(p uintptr) uint { return *(*uint)(unsafe.Pointer(p)) }
func (e *Encoder) ptrToUint8(p uintptr) uint8 { return *(*uint8)(unsafe.Pointer(p)) }
func (e *Encoder) ptrToUint16(p uintptr) uint16 { return *(*uint16)(unsafe.Pointer(p)) }
func (e *Encoder) ptrToUint32(p uintptr) uint32 { return *(*uint32)(unsafe.Pointer(p)) }
func (e *Encoder) ptrToUint64(p uintptr) uint64 { return *(*uint64)(unsafe.Pointer(p)) }
func (e *Encoder) ptrToFloat32(p uintptr) float32 { return *(*float32)(unsafe.Pointer(p)) }
func (e *Encoder) ptrToFloat64(p uintptr) float64 { return *(*float64)(unsafe.Pointer(p)) }
func (e *Encoder) ptrToBool(p uintptr) bool { return *(*bool)(unsafe.Pointer(p)) }
func (e *Encoder) ptrToByte(p uintptr) byte { return *(*byte)(unsafe.Pointer(p)) }
func (e *Encoder) ptrToBytes(p uintptr) []byte { return *(*[]byte)(unsafe.Pointer(p)) }
func (e *Encoder) ptrToString(p uintptr) string { return *(*string)(unsafe.Pointer(p)) }