diff --git a/README.md b/README.md index 25a4194..f199bbc 100644 --- a/README.md +++ b/README.md @@ -70,7 +70,7 @@ WIP - [ ] `InvalidUTF8Error` - [x] `InvalidUnmarshalError` - [x] `MarshalerError` -- [ ] `SyntaxError` +- [x] `SyntaxError` - [ ] `UnmarshalFieldError` - [ ] `UnmarshalTypeError` - [x] `UnsupportedTypeError` diff --git a/benchmarks/go.mod b/benchmarks/go.mod index 533d17c..b7e683c 100644 --- a/benchmarks/go.mod +++ b/benchmarks/go.mod @@ -6,7 +6,6 @@ require ( github.com/francoispqt/gojay v1.2.13 github.com/goccy/go-json v0.0.0-00010101000000-000000000000 github.com/json-iterator/go v1.1.9 - github.com/mailru/easyjson v0.7.1 ) replace github.com/goccy/go-json => ../ diff --git a/benchmarks/go.sum b/benchmarks/go.sum index 2a6b8fb..714d88f 100644 --- a/benchmarks/go.sum +++ b/benchmarks/go.sum @@ -56,8 +56,6 @@ github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.7.1 h1:mdxE1MF9o53iCb2Ghj1VfWvh7ZOwHpnVG/xwXrV90U8= -github.com/mailru/easyjson v0.7.1/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -149,8 +147,6 @@ golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y= diff --git a/decode_slice.go b/decode_slice.go index 8c7f2e6..d82c0b7 100644 --- a/decode_slice.go +++ b/decode_slice.go @@ -13,6 +13,15 @@ type sliceDecoder struct { arrayPool sync.Pool } +// If use reflect.SliceHeader, data type is uintptr. +// In this case, Go compiler cannot trace reference created by newArray(). +// So, define using unsafe.Pointer as data type +type sliceHeader struct { + data unsafe.Pointer + len int + cap int +} + func newSliceDecoder(dec decoder, elemType *rtype, size uintptr) *sliceDecoder { return &sliceDecoder{ valueDecoder: dec, @@ -21,23 +30,23 @@ func newSliceDecoder(dec decoder, elemType *rtype, size uintptr) *sliceDecoder { arrayPool: sync.Pool{ New: func() interface{} { cap := 2 - return &reflect.SliceHeader{ - Data: uintptr(newArray(elemType, cap)), - Len: 0, - Cap: cap, + return &sliceHeader{ + data: newArray(elemType, cap), + len: 0, + cap: cap, } }, }, } } -func (d *sliceDecoder) newSlice() *reflect.SliceHeader { - slice := d.arrayPool.Get().(*reflect.SliceHeader) - slice.Len = 0 +func (d *sliceDecoder) newSlice() *sliceHeader { + slice := d.arrayPool.Get().(*sliceHeader) + slice.len = 0 return slice } -func (d *sliceDecoder) releaseSlice(p *reflect.SliceHeader) { +func (d *sliceDecoder) releaseSlice(p *sliceHeader) { d.arrayPool.Put(p) } @@ -126,18 +135,18 @@ func (d *sliceDecoder) decode(buf []byte, cursor int64, p uintptr) (int64, error case '[': idx := 0 slice := d.newSlice() - cap := slice.Cap - data := slice.Data + cap := slice.cap + data := slice.data for { cursor++ if cap <= idx { - src := reflect.SliceHeader{Data: data, Len: idx, Cap: cap} + src := reflect.SliceHeader{Data: uintptr(data), Len: idx, Cap: cap} cap *= 2 - data = uintptr(newArray(d.elemType, cap)) - dst := reflect.SliceHeader{Data: data, Len: idx, Cap: cap} + data = newArray(d.elemType, cap) + dst := reflect.SliceHeader{Data: uintptr(data), Len: idx, Cap: cap} copySlice(d.elemType, dst, src) } - c, err := d.valueDecoder.decode(buf, cursor, data+uintptr(idx)*d.size) + c, err := d.valueDecoder.decode(buf, cursor, uintptr(data)+uintptr(idx)*d.size) if err != nil { return 0, err } @@ -145,16 +154,20 @@ func (d *sliceDecoder) decode(buf []byte, cursor int64, p uintptr) (int64, error cursor = skipWhiteSpace(buf, cursor) switch buf[cursor] { case ']': - slice.Cap = cap - slice.Len = idx + 1 - slice.Data = data + slice.cap = cap + slice.len = idx + 1 + slice.data = data dstCap := idx + 1 dst := reflect.SliceHeader{ Data: uintptr(newArray(d.elemType, dstCap)), Len: idx + 1, Cap: dstCap, } - copySlice(d.elemType, dst, *slice) + copySlice(d.elemType, dst, reflect.SliceHeader{ + Data: uintptr(slice.data), + Len: slice.len, + Cap: slice.cap, + }) *(*reflect.SliceHeader)(unsafe.Pointer(p)) = dst d.releaseSlice(slice) cursor++ @@ -163,8 +176,8 @@ func (d *sliceDecoder) decode(buf []byte, cursor int64, p uintptr) (int64, error idx++ continue default: - slice.Cap = cap - slice.Data = data + slice.cap = cap + slice.data = data d.releaseSlice(slice) return 0, errInvalidCharacter(buf[cursor], "slice", cursor) }