Enable noescape trick for decoder

This commit is contained in:
Masaaki Goshima 2021-02-11 01:15:31 +09:00
parent 3f90e88a94
commit 20d1a5ada2
4 changed files with 37 additions and 26 deletions

View File

@ -37,30 +37,11 @@ func unmarshal(data []byte, v interface{}) error {
copy(src, data)
header := (*interfaceHeader)(unsafe.Pointer(&v))
header.typ.escape()
return decode(src, header)
}
func unmarshalNoEscape(data []byte, v interface{}) error {
src := make([]byte, len(data)+1) // append nul byte to the end
copy(src, data)
header := (*interfaceHeader)(unsafe.Pointer(&v))
return decode(src, header)
}
func decode(src []byte, header *interfaceHeader) error {
typ := header.typ
typeptr := uintptr(unsafe.Pointer(typ))
// noescape trick for header.typ ( *reflect.rtype )
copiedType := *(**rtype)(unsafe.Pointer(&typeptr))
ptr := uintptr(header.ptr)
if err := validateType(copiedType, ptr); err != nil {
if err := validateType(header.typ, uintptr(header.ptr)); err != nil {
return err
}
dec, err := decodeCompileToGetDecoder(typeptr, typ)
dec, err := decodeCompileToGetDecoder(header.typ)
if err != nil {
return err
}
@ -70,6 +51,31 @@ func decode(src []byte, header *interfaceHeader) error {
return nil
}
func unmarshalNoEscape(data []byte, v interface{}) error {
src := make([]byte, len(data)+1) // append nul byte to the end
copy(src, data)
header := (*interfaceHeader)(unsafe.Pointer(&v))
if err := validateType(header.typ, uintptr(header.ptr)); err != nil {
return err
}
dec, err := decodeCompileToGetDecoder(header.typ)
if err != nil {
return err
}
if _, err := dec.decode(src, 0, noescape(header.ptr)); err != nil {
return err
}
return nil
}
//go:nosplit
func noescape(p unsafe.Pointer) unsafe.Pointer {
x := uintptr(p)
return unsafe.Pointer(x ^ 0)
}
func validateType(typ *rtype, p uintptr) error {
if typ.Kind() != reflect.Ptr || p == 0 {
return &InvalidUnmarshalError{Type: rtype2type(typ)}
@ -132,7 +138,7 @@ func (d *Decoder) Decode(v interface{}) error {
return err
}
dec, err := decodeCompileToGetDecoder(typeptr, typ)
dec, err := decodeCompileToGetDecoder(typ)
if err != nil {
return err
}

View File

@ -2,7 +2,10 @@
package json
func decodeCompileToGetDecoder(typeptr uintptr, typ *rtype) (decoder, error) {
import "unsafe"
func decodeCompileToGetDecoder(typ *rtype) (decoder, error) {
typeptr := uintptr(unsafe.Pointer(typ))
if typeptr > maxTypeAddr {
return decodeCompileToGetDecoderSlowPath(typeptr, typ)
}

View File

@ -4,11 +4,13 @@ package json
import (
"sync"
"unsafe"
)
var decMu sync.RWMutex
func decodeCompileToGetDecoder(typeptr uintptr, typ *rtype) (decoder, error) {
func decodeCompileToGetDecoder(typ *rtype) (decoder, error) {
typeptr := uintptr(unsafe.Pointer(typ))
if typeptr > maxTypeAddr {
return decodeCompileToGetDecoderSlowPath(typeptr, typ)
}

View File

@ -188,7 +188,7 @@ func (d *interfaceDecoder) decodeStream(s *stream, p unsafe.Pointer) error {
*(*interface{})(p) = nil
return nil
}
decoder, err := decodeCompileToGetDecoder(uintptr(unsafe.Pointer(typ)), typ)
decoder, err := decodeCompileToGetDecoder(typ)
if err != nil {
return err
}
@ -228,7 +228,7 @@ func (d *interfaceDecoder) decode(buf []byte, cursor int64, p unsafe.Pointer) (i
**(**interface{})(unsafe.Pointer(&p)) = nil
return cursor, nil
}
decoder, err := decodeCompileToGetDecoder(uintptr(unsafe.Pointer(typ)), typ)
decoder, err := decodeCompileToGetDecoder(typ)
if err != nil {
return 0, err
}