diff --git a/decoder/assembler_amd64.go b/decoder/assembler_amd64.go index 7cf3edb..8b0f17b 100644 --- a/decoder/assembler_amd64.go +++ b/decoder/assembler_amd64.go @@ -17,6 +17,7 @@ package decoder import ( + `encoding/json` `fmt` `math` `reflect` @@ -88,8 +89,10 @@ const ( _LB_error = "_error" _LB_im_error = "_im_error" _LB_eof_error = "_eof_error" + _LB_type_error = "_type_error" _LB_field_error = "_field_error" _LB_range_error = "_range_error" + _LB_stack_error = "_stack_error" _LB_base64_error = "_base64_error" _LB_unquote_error = "_unquote_error" _LB_parsing_error = "_parsing_error" @@ -201,8 +204,10 @@ func (self *_Assembler) compile() { self.prologue() self.instrs() self.epilogue() + self.type_error() self.field_error() self.range_error() + self.stack_error() self.base64_error() self.parsing_error() } @@ -211,6 +216,7 @@ func (self *_Assembler) compile() { var _OpFuncTab = [256]func(*_Assembler, *_Instr) { _OP_any : (*_Assembler)._asm_OP_any, + _OP_dyn : (*_Assembler)._asm_OP_dyn, _OP_str : (*_Assembler)._asm_OP_str, _OP_bin : (*_Assembler)._asm_OP_bin, _OP_bool : (*_Assembler)._asm_OP_bool, @@ -373,6 +379,7 @@ func (self *_Assembler) call_vf(fn obj.Addr) { var ( _F_convT64 = jit.Func(convT64) _F_error_wrap = jit.Func(error_wrap) + _F_error_type = jit.Func(error_type) _F_error_field = jit.Func(error_field) _F_error_value = jit.Func(error_value) ) @@ -392,6 +399,20 @@ var ( _I_base64_CorruptInputError = jit.Itab(_T_error, base64CorruptInputError) ) +var ( + _V_stackOverflow = jit.Imm(int64(uintptr(unsafe.Pointer(&stackOverflow)))) + _I_json_UnsupportedValueError = jit.Itab(_T_error, reflect.TypeOf(new(json.UnsupportedValueError))) +) + +func (self *_Assembler) type_error() { + self.Link(_LB_type_error) // _type_error: + self.Emit("MOVQ", _ET, jit.Ptr(_SP, 0)) // MOVQ ET, (SP) + self.call_go(_F_error_type) // CALL_GO error_type + self.Emit("MOVQ", jit.Ptr(_SP, 8), _ET) // MOVQ 8(SP), ET + self.Emit("MOVQ", jit.Ptr(_SP, 16), _EP) // MOVQ 16(SP), EP + self.Sjmp("JMP" , _LB_error) // JMP _error +} + func (self *_Assembler) field_error() { self.Link(_LB_field_error) // _field_error: self.Emit("MOVOU", _VAR_sv, _X0) // MOVOU sv, X0 @@ -415,6 +436,13 @@ func (self *_Assembler) range_error() { self.Sjmp("JMP" , _LB_error) // JMP _error } +func (self *_Assembler) stack_error() { + self.Link(_LB_stack_error) // _stack_error: + self.Emit("MOVQ", _V_stackOverflow, _EP) // MOVQ ${_V_stackOverflow}, EP + self.Emit("MOVQ", _I_json_UnsupportedValueError, _ET) // MOVQ ${_I_json_UnsupportedValueError}, ET + self.Sjmp("JMP" , _LB_error) // JMP _error +} + func (self *_Assembler) base64_error() { self.Link(_LB_base64_error) self.Emit("NEGQ", _AX) // NEGQ AX @@ -697,13 +725,13 @@ func (self *_Assembler) mem_clear_fn(ptrfree bool) { } func (self *_Assembler) mem_clear_rem(size int64, ptrfree bool) { - self.Emit("MOVQ" , jit.Imm(size), _CX) // MOVQ ${size}, CX - self.Emit("MOVQ" , jit.Ptr(_ST, 0), _AX) // MOVQ (ST), AX - self.Emit("MOVQ" , jit.Sib(_ST, _AX, 1, 0), _AX) // MOVQ (ST)(AX), AX - self.Emit("SUBQ" , _VP, _AX) // SUBQ VP, AX - self.Emit("ADDQ" , _AX, _CX) // ADDQ AX, CX - self.Emit("MOVQ" , _VP, jit.Ptr(_SP, 0)) // MOVQ VP, (SP) - self.Emit("MOVQ" , _CX, jit.Ptr(_SP, 8)) // MOVQ CX, 8(SP) + self.Emit("MOVQ", jit.Imm(size), _CX) // MOVQ ${size}, CX + self.Emit("MOVQ", jit.Ptr(_ST, 0), _AX) // MOVQ (ST), AX + self.Emit("MOVQ", jit.Sib(_ST, _AX, 1, 0), _AX) // MOVQ (ST)(AX), AX + self.Emit("SUBQ", _VP, _AX) // SUBQ VP, AX + self.Emit("ADDQ", _AX, _CX) // ADDQ AX, CX + self.Emit("MOVQ", _VP, jit.Ptr(_SP, 0)) // MOVQ VP, (SP) + self.Emit("MOVQ", _CX, jit.Ptr(_SP, 8)) // MOVQ CX, 8(SP) self.mem_clear_fn(ptrfree) // CALL_GO memclr{Has,NoHeap}Pointers } @@ -859,6 +887,33 @@ func (self *_Assembler) unmarshal_func(t reflect.Type, fn obj.Addr, deref bool) self.Sjmp("JNZ" , _LB_error) // JNZ _error } +/** Dynamic Decoding Routine **/ + +var ( + _F_decodeTypedPointer obj.Addr +) + +func init() { + _F_decodeTypedPointer = jit.Func(decodeTypedPointer) +} + +func (self *_Assembler) decode_dynamic(vt obj.Addr, vp obj.Addr) { + self.Emit("MOVQ" , _ARG_fv, _CX) // MOVQ fv, CX + self.Emit("MOVOU", _ARG_sp, _X0) // MOVOU sp, X0 + self.Emit("MOVOU", _X0, jit.Ptr(_SP, 0)) // MOVOU X0, (SP) + self.Emit("MOVQ" , _IC, jit.Ptr(_SP, 16)) // MOVQ IC, 16(SP) + self.Emit("MOVQ" , vt, jit.Ptr(_SP, 24)) // MOVQ ${vt}, 24(SP) + self.Emit("MOVQ" , vp, jit.Ptr(_SP, 32)) // MOVQ ${vp}, 32(SP) + self.Emit("MOVQ" , _ST, jit.Ptr(_SP, 40)) // MOVQ ST, 40(SP) + self.Emit("MOVQ" , _CX, jit.Ptr(_SP, 48)) // MOVQ CX, 48(SP) + self.call_go(_F_decodeTypedPointer) // CALL_GO decodeTypedPointer + self.Emit("MOVQ" , jit.Ptr(_SP, 64), _ET) // MOVQ 64(SP), ET + self.Emit("MOVQ" , jit.Ptr(_SP, 72), _EP) // MOVQ 72(SP), EP + self.Emit("TESTQ", _ET, _ET) // TESTQ ET, ET + self.Sjmp("JNZ" , _LB_error) // JNZ _error + self.Emit("MOVQ" , jit.Ptr(_SP, 56), _IC) // MOVQ 56(SP), IC +} + /** OpCode Assembler Functions **/ var ( @@ -885,7 +940,6 @@ var ( ) var ( - _F_decodeTypedPointer obj.Addr _F_FieldMap_GetCaseInsensitive obj.Addr ) @@ -895,16 +949,50 @@ const ( _Fe_Hash = int64(unsafe.Offsetof(caching.FieldEntry{}.Hash)) ) +const ( + _Vk_Ptr = int64(reflect.Ptr) + _Gt_KindFlags = int64(unsafe.Offsetof(rt.GoType{}.KindFlags)) +) + func init() { - _F_decodeTypedPointer = jit.Func(decodeTypedPointer) _F_FieldMap_GetCaseInsensitive = jit.Func((*caching.FieldMap).GetCaseInsensitive) } func (self *_Assembler) _asm_OP_any(_ *_Instr) { - self.Emit("MOVQ" , _ARG_fv, _DF) // MOVQ fv, DF - self.call(_F_decodeValue) // CALL decodeValue - self.Emit("TESTQ", _EP, _EP) // TESTQ EP, EP - self.Sjmp("JNZ" , _LB_parsing_error) // JNZ _parsing_error + self.Emit("MOVQ" , jit.Ptr(_VP, 8), _CX) // MOVQ 8(VP), CX + self.Emit("TESTQ" , _CX, _CX) // TESTQ CX, CX + self.Sjmp("JZ" , "_decode_{n}") // JZ _decode_{n} + self.Emit("CMPQ" , _CX, _VP) // CMPQ CX, VP + self.Sjmp("JE" , "_decode_{n}") // JE _decode_{n} + self.Emit("MOVQ" , jit.Ptr(_VP, 0), _AX) // MOVQ (VP), AX + self.Emit("MOVBLZX", jit.Ptr(_AX, _Gt_KindFlags), _DX) // MOVBLZX _Gt_KindFlags(AX), DX + self.Emit("ANDL" , jit.Imm(rt.F_kind_mask), _DX) // ANDL ${F_kind_mask}, DX + self.Emit("CMPL" , _DX, jit.Imm(_Vk_Ptr)) // CMPL DX, ${reflect.Ptr} + self.Sjmp("JNE" , "_decode_{n}") // JNE _decode_{n} + self.Emit("LEAQ" , jit.Ptr(_VP, 8), _DI) // LEAQ 8(VP), DI + self.decode_dynamic(_AX, _DI) // DECODE AX, DI + self.Sjmp("JMP" , "_decode_end_{n}") // JMP _decode_end_{n} + self.Link("_decode_{n}") // _decode_{n}: + self.Emit("MOVQ" , _ARG_fv, _DF) // MOVQ fv, DF + self.call(_F_decodeValue) // CALL decodeValue + self.Emit("TESTQ" , _EP, _EP) // TESTQ EP, EP + self.Sjmp("JNZ" , _LB_parsing_error) // JNZ _parsing_error + self.Link("_decode_end_{n}") // _decode_end_{n}: +} + +func (self *_Assembler) _asm_OP_dyn(p *_Instr) { + self.Emit("MOVQ" , jit.Type(p.vt()), _ET) // MOVQ ${p.vt()}, ET + self.Emit("CMPQ" , jit.Ptr(_VP, 8), jit.Imm(0)) // CMPQ 8(VP), $0 + self.Sjmp("JE" , _LB_type_error) // JE _type_error + self.Emit("MOVQ" , jit.Ptr(_VP, 0), _AX) // MOVQ (VP), AX + self.Emit("MOVQ" , jit.Ptr(_AX, 8), _AX) // MOVQ 8(AX), AX + self.Emit("MOVBLZX", jit.Ptr(_AX, _Gt_KindFlags), _DX) // MOVBLZX _Gt_KindFlags(AX), DX + self.Emit("ANDL" , jit.Imm(rt.F_kind_mask), _DX) // ANDL ${F_kind_mask}, DX + self.Emit("CMPL" , _DX, jit.Imm(_Vk_Ptr)) // CMPL DX, ${reflect.Ptr} + self.Sjmp("JNE" , _LB_type_error) // JNE _type_error + self.Emit("LEAQ" , jit.Ptr(_VP, 8), _DI) // LEAQ 8(VP), DI + self.decode_dynamic(_AX, _DI) // DECODE AX, DI + self.Link("_decode_end_{n}") // _decode_end_{n}: } func (self *_Assembler) _asm_OP_str(_ *_Instr) { @@ -1374,6 +1462,8 @@ func (self *_Assembler) _asm_OP_load(_ *_Instr) { func (self *_Assembler) _asm_OP_save(_ *_Instr) { self.Emit("MOVQ", jit.Ptr(_ST, 0), _AX) // MOVQ (ST), AX + self.Emit("CMPQ", _AX, jit.Imm(_MaxStack)) // CMPQ AX, ${_MaxStack} + self.Sjmp("JA" , _LB_stack_error) // JA _stack_error self.Emit("MOVQ", _VP, jit.Sib(_ST, _AX, 1, 8)) // MOVQ VP, 8(ST)(AX) self.Emit("ADDQ", jit.Imm(8), _AX) // ADDQ $8, AX self.Emit("MOVQ", _AX, jit.Ptr(_ST, 0)) // MOVQ AX, (ST) @@ -1398,21 +1488,8 @@ func (self *_Assembler) _asm_OP_drop_2(_ *_Instr) { } func (self *_Assembler) _asm_OP_recurse(p *_Instr) { - self.Emit("MOVQ" , jit.Type(p.vt()), _AX) // MOVQ ${p.vt()}, AX - self.Emit("MOVQ" , _ARG_fv, _CX) // MOVQ fv, cx - self.Emit("MOVOU", _ARG_sp, _X0) // MOVOU sp, X0 - self.Emit("MOVOU", _X0, jit.Ptr(_SP, 0)) // MOVOU X0, (SP) - self.Emit("MOVQ" , _IC, jit.Ptr(_SP, 16)) // MOVQ IC, 16(SP) - self.Emit("MOVQ" , _AX, jit.Ptr(_SP, 24)) // MOVQ AX, 24(SP) - self.Emit("MOVQ" , _VP, jit.Ptr(_SP, 32)) // MOVQ VP, 32(SP) - self.Emit("MOVQ" , _ST, jit.Ptr(_SP, 40)) // MOVQ ST, 40(SP) - self.Emit("MOVQ" , _CX, jit.Ptr(_SP, 48)) // MOVQ CX, 48(SP) - self.call_go(_F_decodeTypedPointer) // CALL_GO decodeTypedPointer - self.Emit("MOVQ" , jit.Ptr(_SP, 64), _ET) // MOVQ 64(SP), ET - self.Emit("MOVQ" , jit.Ptr(_SP, 72), _EP) // MOVQ 72(SP), EP - self.Emit("TESTQ", _ET, _ET) // TESTQ ET, ET - self.Sjmp("JNZ" , _LB_error) // JNZ _error - self.Emit("MOVQ" , jit.Ptr(_SP, 56), _IC) // MOVQ 56(SP), IC + self.Emit("MOVQ", jit.Type(p.vt()), _AX) // MOVQ ${p.vt()}, AX + self.decode_dynamic(_AX, _VP) // DECODE AX, VP } func (self *_Assembler) _asm_OP_goto(p *_Instr) { diff --git a/decoder/compiler.go b/decoder/compiler.go index a6db614..23b433e 100644 --- a/decoder/compiler.go +++ b/decoder/compiler.go @@ -17,6 +17,7 @@ package decoder import ( + `encoding/json` `fmt` `reflect` `sort` @@ -33,6 +34,7 @@ type _Op uint8 const ( _OP_any _Op = iota + 1 + _OP_dyn _OP_str _OP_bin _OP_bool @@ -104,6 +106,7 @@ const ( var _OpNames = [256]string { _OP_any : "any", + _OP_dyn : "dyn", _OP_str : "str", _OP_bin : "bin", _OP_bool : "bool", @@ -295,7 +298,7 @@ func (self _Instr) i64() int64 { } func (self _Instr) vlen() int { - return (*rt.GoType)(self.p).Size() + return int((*rt.GoType)(self.p).Size) } func (self _Instr) isBranch() bool { @@ -310,6 +313,7 @@ func (self _Instr) isBranch() bool { func (self _Instr) disassemble() string { switch self.op() { + case _OP_dyn : fallthrough case _OP_deref : fallthrough case _OP_map_key_i8 : fallthrough case _OP_map_key_i16 : fallthrough @@ -573,7 +577,7 @@ func (self *_Compiler) compileOps(p *_Program, sp int, vt reflect.Type) { case reflect.Ptr : self.compilePtr (p, sp, vt) case reflect.Slice : self.compileSlice (p, sp, vt.Elem()) case reflect.Struct : self.compileStruct (p, sp, vt) - default : panic (error_type(vt)) + default : panic (&json.UnmarshalTypeError{Type: vt}) } } @@ -603,7 +607,7 @@ func (self *_Compiler) compileMapUt(p *_Program, sp int, vt reflect.Type) { case reflect.Float32 : self.compileMapOp(p, sp, vt, _OP_map_key_f32) case reflect.Float64 : self.compileMapOp(p, sp, vt, _OP_map_key_f64) case reflect.String : self.compileMapOp(p, sp, vt, _OP_map_key_str) - default : panic(error_type(vt)) + default : panic(&json.UnmarshalTypeError{Type: vt}) } } @@ -708,7 +712,7 @@ func (self *_Compiler) compileArray(p *_Program, sp int, vt reflect.Type) { p.rel(v) /* check for pointer data */ - if rt.UnpackType(vt.Elem()).NoPtr() { + if rt.UnpackType(vt.Elem()).PtrData == 0 { p.int(_OP_array_clear, int(vt.Size())) } else { p.int(_OP_array_clear_p, int(vt.Size())) @@ -991,16 +995,16 @@ func (self *_Compiler) compileStructFieldStr(p *_Program, sp int, vt reflect.Typ func (self *_Compiler) compileInterface(p *_Program, vt reflect.Type) { i := p.pc() - n := vt.NumMethod() + p.add(_OP_is_null) - /* only empty interface is acceptable */ - if n != 0 { - panic(error_type(vt)) + /* check for empty interface */ + if vt.NumMethod() == 0 { + p.add(_OP_any) + } else { + p.rtt(_OP_dyn, vt) } - /* check for nil, and compile the interface */ - p.add(_OP_is_null) - p.add(_OP_any) + /* finish the OpCode */ j := p.pc() p.add(_OP_goto) p.pin(i) @@ -1034,30 +1038,33 @@ func (self *_Compiler) compileUnmarshalEnd(p *_Program, vt reflect.Type, i int) func (self *_Compiler) compileUnmarshalJson(p *_Program, vt reflect.Type) { i := p.pc() + v := _OP_unmarshal p.add(_OP_is_null) - /* must not be an interface */ + /* check for dynamic interface */ if vt.Kind() == reflect.Interface { - panic(error_type(vt)) + v = _OP_dyn } /* call the unmarshaler */ - p.rtt(_OP_unmarshal, vt) + p.rtt(v, vt) self.compileUnmarshalEnd(p, vt, i) } func (self *_Compiler) compileUnmarshalText(p *_Program, vt reflect.Type) { i := p.pc() + v := _OP_unmarshal_text p.add(_OP_is_null) - p.chr(_OP_match_char, '"') - /* must not be an interface */ + /* check for dynamic interface */ if vt.Kind() == reflect.Interface { - panic(error_type(vt)) + v = _OP_dyn + } else { + p.chr(_OP_match_char, '"') } /* call the unmarshaler */ - p.rtt(_OP_unmarshal_text, vt) + p.rtt(v, vt) self.compileUnmarshalEnd(p, vt, i) } diff --git a/decoder/errors.go b/decoder/errors.go index ae5f07d..5276035 100644 --- a/decoder/errors.go +++ b/decoder/errors.go @@ -25,6 +25,7 @@ import ( `strings` `github.com/bytedance/sonic/internal/native/types` + `github.com/bytedance/sonic/internal/rt` ) type SyntaxError struct { @@ -86,6 +87,14 @@ func clamp_zero(v int) int { } } +/** JIT Error Helpers **/ + +var stackOverflow = &json.UnsupportedValueError { + Str : "Value nesting too deep", + Value : reflect.ValueOf("..."), +} + +//go:nosplit func error_wrap(src string, pos int, code types.ParsingError) error { return SyntaxError { Pos : pos, @@ -94,10 +103,12 @@ func error_wrap(src string, pos int, code types.ParsingError) error { } } -func error_type(vtype reflect.Type) error { - return &json.UnmarshalTypeError{Type: vtype} +//go:nosplit +func error_type(vt *rt.GoType) error { + return &json.UnmarshalTypeError{Type: vt.Pack()} } +//go:nosplit func error_field(name string) error { return errors.New("json: unknown field " + strconv.Quote(name)) } diff --git a/encoder/compiler.go b/encoder/compiler.go index 10df4fa..a8c3c3c 100644 --- a/encoder/compiler.go +++ b/encoder/compiler.go @@ -239,7 +239,7 @@ func (self _Instr) i64() int64 { } func (self _Instr) vlen() int { - return (*rt.GoType)(self.p).Size() + return int((*rt.GoType)(self.p).Size) } func (self _Instr) isBranch() bool { diff --git a/encoder/primitives.go b/encoder/primitives.go index 364f2a6..5742918 100644 --- a/encoder/primitives.go +++ b/encoder/primitives.go @@ -71,7 +71,7 @@ func encodeTypedPointer(buf *[]byte, vt *rt.GoType, vp *unsafe.Pointer, sb *_Sta return encodeNil(buf) } else if fn, err := findOrCompile(vt); err != nil { return err - } else if vt.Indir() { + } else if (vt.KindFlags & rt.F_direct) == 0 { return fn(buf, *vp, sb) } else { return fn(buf, unsafe.Pointer(vp), sb) @@ -95,7 +95,7 @@ func encodeTextMarshaler(buf *[]byte, val encoding.TextMarshaler) error { } func isZeroSafe(p unsafe.Pointer, vt *rt.GoType) bool { - if native.Lzero(p, vt.Size()) == 0 { + if native.Lzero(p, int(vt.Size)) == 0 { return true } else { return isZeroTyped(p, vt) diff --git a/encoder/stubs.go b/encoder/stubs.go index 8478eb2..ad69c2b 100644 --- a/encoder/stubs.go +++ b/encoder/stubs.go @@ -29,34 +29,34 @@ var _subr__b64encode uintptr //go:noescape //go:linkname memmove runtime.memmove -//goland:noinspection ALL +//goland:noinspection GoUnusedParameter func memmove(to unsafe.Pointer, from unsafe.Pointer, n uintptr) //go:linkname newobject runtime.newobject -//goland:noinspection ALL +//goland:noinspection GoUnusedParameter func newobject(typ *rt.GoType) unsafe.Pointer //go:linkname growslice runtime.growslice -//goland:noinspection ALL +//goland:noinspection GoUnusedParameter func growslice(et *rt.GoType, old rt.GoSlice, cap int) rt.GoSlice //go:linkname assertI2I runtime.assertI2I -//goland:noinspection ALL +//goland:noinspection GoUnusedParameter func assertI2I(inter *rt.GoType, i rt.GoIface) rt.GoIface //go:linkname mapiternext runtime.mapiternext -//goland:noinspection ALL +//goland:noinspection GoUnusedParameter func mapiternext(it unsafe.Pointer) //go:linkname mapiterinit runtime.mapiterinit -//goland:noinspection ALL +//goland:noinspection GoUnusedParameter func mapiterinit(t *rt.GoType, m unsafe.Pointer, it *rt.GoMapIterator) //go:linkname isValidNumber encoding/json.isValidNumber -//goland:noinspection ALL +//goland:noinspection GoUnusedParameter func isValidNumber(s string) bool //go:noescape //go:linkname memclrNoHeapPointers runtime.memclrNoHeapPointers -//goland:noinspection ALL +//goland:noinspection GoUnusedParameter func memclrNoHeapPointers(ptr unsafe.Pointer, n uintptr) diff --git a/internal/caching/pcache.go b/internal/caching/pcache.go index 275fbee..a9ec4e7 100644 --- a/internal/caching/pcache.go +++ b/internal/caching/pcache.go @@ -52,7 +52,7 @@ func newProgramMap() *_ProgramMap { func (self *_ProgramMap) get(vt *rt.GoType) interface{} { i := self.m + 1 - p := vt.Hash() & self.m + p := vt.Hash & self.m /* linear probing */ for ; i > 0; i-- { @@ -99,7 +99,7 @@ func (self *_ProgramMap) rehash() *_ProgramMap { } func (self *_ProgramMap) insert(vt *rt.GoType, fn interface{}) { - h := vt.Hash() + h := vt.Hash p := h & self.m /* linear probing */ diff --git a/internal/rt/fastvalue.go b/internal/rt/fastvalue.go index 9268488..519b0aa 100644 --- a/internal/rt/fastvalue.go +++ b/internal/rt/fastvalue.go @@ -21,37 +21,31 @@ import ( `unsafe` ) -var reflectRtypeItab = findReflectRtypeItab() +var ( + reflectRtypeItab = findReflectRtypeItab() +) const ( - _KindMask = (1 << 5) - 1 - _DirectIface = 1 << 5 + F_direct = 1 << 5 + F_kind_mask = (1 << 5) - 1 ) type GoType struct { - nb uintptr - ptrd uintptr - hash uint32 - tflags uint8 - align uint8 - falign uint8 - kflags uint8 - traits unsafe.Pointer - gcdata *byte - str int32 - p int32 -} - -func (self *GoType) Size() int { - return int(self.nb) -} - -func (self *GoType) Hash() uint32 { - return self.hash + Size uintptr + PtrData uintptr + Hash uint32 + Flags uint8 + Align uint8 + FieldAlign uint8 + KindFlags uint8 + Traits unsafe.Pointer + GCData *byte + Str int32 + PtrToSelf int32 } func (self *GoType) Kind() reflect.Kind { - return reflect.Kind(self.kflags & _KindMask) + return reflect.Kind(self.KindFlags & F_kind_mask) } func (self *GoType) Pack() (t reflect.Type) { @@ -60,14 +54,6 @@ func (self *GoType) Pack() (t reflect.Type) { return } -func (self *GoType) NoPtr() bool { - return self.ptrd == 0 -} - -func (self *GoType) Indir() bool { - return (self.kflags & _DirectIface) == 0 -} - func (self *GoType) String() string { return self.Pack().String() } diff --git a/issue39_test.go b/issue39_test.go new file mode 100644 index 0000000..be846eb --- /dev/null +++ b/issue39_test.go @@ -0,0 +1,111 @@ +/* + * Copyright 2021 ByteDance Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package sonic + +import ( + `testing` + + `github.com/bytedance/sonic/decoder` + `github.com/stretchr/testify/require` +) + +type normalIfaceIssue39 interface { + Foo() +} + +type normalWrapIssue39 struct { + F normalIfaceIssue39 +} + +type normalImplIssue39 struct { + X int +} + +func (_ *normalImplIssue39) Foo() {} + +type jsonIfaceIssue39 interface { + UnmarshalJSON(b []byte) error +} + +type jsonWrapIssue39 struct { + F jsonIfaceIssue39 +} + +type jsonImplIssue39 struct { + a string +} + +func (self *jsonImplIssue39) UnmarshalJSON(b []byte) error{ + self.a = string(b) + return nil +} + +type textIfaceIssue39 interface { + UnmarshalText(b []byte) error +} + +type textWrapIssue39 struct { + F textIfaceIssue39 +} + +type textImplIssue39 struct { + a string +} + +func (self *textImplIssue39) UnmarshalText(b []byte) error{ + self.a = string(b) + return nil +} + +func TestIssue39_Iface(t *testing.T) { + p := new(normalImplIssue39) + obj := normalWrapIssue39{F: p} + err := Unmarshal([]byte(`{"F":{"X":123}}`), &obj) + if err != nil { + if v, ok := err.(decoder.SyntaxError); ok { + println(v.Description()) + } + require.NoError(t, err) + } + require.Equal(t, 123, p.X) +} + +func TestIssue39_UnmarshalJSON(t *testing.T) { + p := &jsonImplIssue39{} + obj := jsonWrapIssue39{F: p} + err := Unmarshal([]byte(`{"F":"xx"}`), &obj) + if err != nil { + if v, ok := err.(decoder.SyntaxError); ok { + println(v.Description()) + } + require.NoError(t, err) + } + require.Equal(t, `"xx"`, p.a) +} + +func TestIssue39_UnmarshalText(t *testing.T) { + p := &textImplIssue39{} + obj := textWrapIssue39{F: p} + err := Unmarshal([]byte(`{"F":"xx"}`), &obj) + if err != nil { + if v, ok := err.(decoder.SyntaxError); ok { + println(v.Description()) + } + require.NoError(t, err) + } + require.Equal(t, `xx`, p.a) +} diff --git a/issue5_test.go b/issue5_test.go new file mode 100644 index 0000000..740a191 --- /dev/null +++ b/issue5_test.go @@ -0,0 +1,31 @@ +/* + * Copyright 2021 ByteDance Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package sonic + +import ( + `testing` + + `github.com/stretchr/testify/require` +) + +func TestIssue5(t *testing.T) { + var x int + var i interface{} = &x + err := Unmarshal([]byte(`1`), &i) + require.NoError(t, err) + require.Equal(t, 1, x) +} \ No newline at end of file