From 4edbe3a346546e13e88b127002757bcaa80eebe5 Mon Sep 17 00:00:00 2001 From: Masaaki Goshima Date: Thu, 30 Apr 2020 13:52:24 +0900 Subject: [PATCH] Refactor encoder --- encode.go | 639 ++-------------------------------------------- encode_compile.go | 128 ++++++---- encode_vm.go | 20 +- 3 files changed, 114 insertions(+), 673 deletions(-) diff --git a/encode.go b/encode.go index 8f7cb17..0ecd1e2 100644 --- a/encode.go +++ b/encode.go @@ -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) *opcode { //EncodeOp { +func (m *opcodeMap) Get(k string) *opcode { if v, ok := m.Load(k); ok { - return v.(*opcode) //(EncodeOp) + return v.(*opcode) } return nil } -func (m *EncodeOpMap) Set(k string, op *opcode) { // 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") + encPool sync.Pool + cachedOpcode opcodeMap ) func init() { @@ -55,7 +48,7 @@ func init() { } }, } - cachedEncodeOp = EncodeOpMap{} + cachedOpcode = opcodeMap{} } // NewEncoder returns a new encoder that writes to w. @@ -183,624 +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.ptr = p - if err := e.run(op); err != nil { + code.ptr = p + if err := e.run(code); err != nil { return err } - //op(e, typ, p) return nil } - op, err := e.compileOp(typ) + code, err := e.compile(typ) if err != nil { - if err == errCompileSlowPath { - /* - slowOp, err := e.compileSlowPath(typ) - if err != nil { - return err - } - op = slowOp - */ - } else { - return err - } + return err } if name != "" { - cachedEncodeOp.Set(name, op) + cachedOpcode.Set(name, code) } p := uintptr(header.ptr) - op.ptr = p - e.run(op) - //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)) } diff --git a/encode_compile.go b/encode_compile.go index 503ac4d..8d1aebd 100644 --- a/encode_compile.go +++ b/encode_compile.go @@ -9,50 +9,50 @@ import ( "golang.org/x/xerrors" ) -func (e *Encoder) compileOp(typ *rtype) (*opcode, error) { +func (e *Encoder) compile(typ *rtype) (*opcode, error) { switch typ.Kind() { case reflect.Ptr: - return e.compilePtrOp(typ) + return e.compilePtr(typ) case reflect.Slice: - return e.compileSliceOp(typ) + return e.compileSlice(typ) case reflect.Array: - return e.compileArrayOp(typ) + return e.compileArray(typ) case reflect.Map: - return e.compileMapOp(typ) + return e.compileMap(typ) case reflect.Struct: - return e.compileStructOp(typ) + return e.compileStruct(typ) case reflect.Int: - return e.compileIntOp(typ) + return e.compileInt(typ) case reflect.Int8: - return e.compileInt8Op(typ) + return e.compileInt8(typ) case reflect.Int16: - return e.compileInt16Op(typ) + return e.compileInt16(typ) case reflect.Int32: - return e.compileInt32Op(typ) + return e.compileInt32(typ) case reflect.Int64: - return e.compileInt64Op(typ) + return e.compileInt64(typ) case reflect.Uint: - return e.compileUintOp(typ) + return e.compileUint(typ) case reflect.Uint8: - return e.compileUint8Op(typ) + return e.compileUint8(typ) case reflect.Uint16: - return e.compileUint16Op(typ) + return e.compileUint16(typ) case reflect.Uint32: - return e.compileUint32Op(typ) + return e.compileUint32(typ) case reflect.Uint64: - return e.compileUint64Op(typ) + return e.compileUint64(typ) case reflect.Uintptr: - return e.compileUintOp(typ) + return e.compileUint(typ) case reflect.Float32: - return e.compileFloat32Op(typ) + return e.compileFloat32(typ) case reflect.Float64: - return e.compileFloat64Op(typ) + return e.compileFloat64(typ) case reflect.String: - return e.compileStringOp(typ) + return e.compileString(typ) case reflect.Bool: - return e.compileBoolOp(typ) + return e.compileBool(typ) case reflect.Interface: - return e.compileInterfaceOp(typ) + return e.compileInterface(typ) } return nil, xerrors.Errorf("failed to encode type %s: %w", typ.String(), ErrUnsupportedType) } @@ -95,78 +95,78 @@ func (e *Encoder) optimizeStructFieldPtrHead(typ *rtype, code *opcode) *opcode { return code } -func (e *Encoder) compilePtrOp(typ *rtype) (*opcode, error) { - code, err := e.compileOp(typ.Elem()) +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) compileIntOp(typ *rtype) (*opcode, error) { +func (e *Encoder) compileInt(typ *rtype) (*opcode, error) { return newOpCode(opInt, typ, newEndOp()), nil } -func (e *Encoder) compileInt8Op(typ *rtype) (*opcode, error) { +func (e *Encoder) compileInt8(typ *rtype) (*opcode, error) { return newOpCode(opInt8, typ, newEndOp()), nil } -func (e *Encoder) compileInt16Op(typ *rtype) (*opcode, error) { +func (e *Encoder) compileInt16(typ *rtype) (*opcode, error) { return newOpCode(opInt16, typ, newEndOp()), nil } -func (e *Encoder) compileInt32Op(typ *rtype) (*opcode, error) { +func (e *Encoder) compileInt32(typ *rtype) (*opcode, error) { return newOpCode(opInt32, typ, newEndOp()), nil } -func (e *Encoder) compileInt64Op(typ *rtype) (*opcode, error) { +func (e *Encoder) compileInt64(typ *rtype) (*opcode, error) { return newOpCode(opInt64, typ, newEndOp()), nil } -func (e *Encoder) compileUintOp(typ *rtype) (*opcode, error) { +func (e *Encoder) compileUint(typ *rtype) (*opcode, error) { return newOpCode(opUint, typ, newEndOp()), nil } -func (e *Encoder) compileUint8Op(typ *rtype) (*opcode, error) { +func (e *Encoder) compileUint8(typ *rtype) (*opcode, error) { return newOpCode(opUint8, typ, newEndOp()), nil } -func (e *Encoder) compileUint16Op(typ *rtype) (*opcode, error) { +func (e *Encoder) compileUint16(typ *rtype) (*opcode, error) { return newOpCode(opUint16, typ, newEndOp()), nil } -func (e *Encoder) compileUint32Op(typ *rtype) (*opcode, error) { +func (e *Encoder) compileUint32(typ *rtype) (*opcode, error) { return newOpCode(opUint32, typ, newEndOp()), nil } -func (e *Encoder) compileUint64Op(typ *rtype) (*opcode, error) { +func (e *Encoder) compileUint64(typ *rtype) (*opcode, error) { return newOpCode(opUint64, typ, newEndOp()), nil } -func (e *Encoder) compileFloat32Op(typ *rtype) (*opcode, error) { +func (e *Encoder) compileFloat32(typ *rtype) (*opcode, error) { return newOpCode(opFloat32, typ, newEndOp()), nil } -func (e *Encoder) compileFloat64Op(typ *rtype) (*opcode, error) { +func (e *Encoder) compileFloat64(typ *rtype) (*opcode, error) { return newOpCode(opFloat64, typ, newEndOp()), nil } -func (e *Encoder) compileStringOp(typ *rtype) (*opcode, error) { +func (e *Encoder) compileString(typ *rtype) (*opcode, error) { return newOpCode(opString, typ, newEndOp()), nil } -func (e *Encoder) compileBoolOp(typ *rtype) (*opcode, error) { +func (e *Encoder) compileBool(typ *rtype) (*opcode, error) { return newOpCode(opBool, typ, newEndOp()), nil } -func (e *Encoder) compileInterfaceOp(typ *rtype) (*opcode, error) { +func (e *Encoder) compileInterface(typ *rtype) (*opcode, error) { return newOpCode(opInterface, typ, newEndOp()), nil } -func (e *Encoder) compileSliceOp(typ *rtype) (*opcode, error) { +func (e *Encoder) compileSlice(typ *rtype) (*opcode, error) { elem := typ.Elem() size := elem.Size() - code, err := e.compileOp(elem) + code, err := e.compile(elem) if err != nil { return nil, err } @@ -188,11 +188,11 @@ func (e *Encoder) compileSliceOp(typ *rtype) (*opcode, error) { return (*opcode)(unsafe.Pointer(header)), nil } -func (e *Encoder) compileArrayOp(typ *rtype) (*opcode, error) { +func (e *Encoder) compileArray(typ *rtype) (*opcode, error) { elem := typ.Elem() alen := typ.Len() size := elem.Size() - code, err := e.compileOp(elem) + code, err := e.compile(elem) if err != nil { return nil, err } @@ -219,17 +219,33 @@ func (e *Encoder) compileArrayOp(typ *rtype) (*opcode, error) { return (*opcode)(unsafe.Pointer(header)), nil } -func (e *Encoder) compileMapOp(typ *rtype) (*opcode, error) { +//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.compileOp(keyType) + keyCode, err := e.compile(keyType) if err != nil { return nil, err } valueType := typ.Elem() - valueCode, err := e.compileOp(valueType) + valueCode, err := e.compile(valueType) if err != nil { return nil, err } @@ -252,7 +268,23 @@ func (e *Encoder) compileMapOp(typ *rtype) (*opcode, error) { return (*opcode)(unsafe.Pointer(header)), nil } -func (e *Encoder) compileStructOp(typ *rtype) (*opcode, error) { +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 // ^ | // |__________| @@ -277,7 +309,7 @@ func (e *Encoder) compileStructOp(typ *rtype) (*opcode, error) { } } fieldType := type2rtype(field.Type) - valueCode, err := e.compileOp(fieldType) + valueCode, err := e.compile(fieldType) if err != nil { return nil, err } diff --git a/encode_vm.go b/encode_vm.go index 2c05b79..07de78c 100644 --- a/encode_vm.go +++ b/encode_vm.go @@ -66,7 +66,7 @@ func (e *Encoder) run(code *opcode) error { if typ.Kind() == reflect.Ptr { typ = typ.Elem() } - c, err := e.compileOp(typ) + c, err := e.compile(typ) if err != nil { return err } @@ -525,3 +525,21 @@ func (e *Encoder) run(code *opcode) error { 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)) }