mirror of https://github.com/goccy/go-json.git
Add type addrShift to enable bigger encoder/decoder cache
Change-Id: I630fa501f3b96702b69a40bc0b2f79f4db2a57eb
This commit is contained in:
parent
835c00e18b
commit
7e03a13225
21
codec.go
21
codec.go
|
@ -16,6 +16,7 @@ var (
|
|||
cachedDecoderMap unsafe.Pointer // map[uintptr]decoder
|
||||
baseTypeAddr uintptr
|
||||
maxTypeAddr uintptr
|
||||
typeAddrShift uintptr
|
||||
)
|
||||
|
||||
//go:linkname typelinks reflect.typelinks
|
||||
|
@ -35,8 +36,10 @@ func setupCodec() error {
|
|||
section := sections[0]
|
||||
offset := offsets[0]
|
||||
var (
|
||||
min uintptr = uintptr(^uint(0))
|
||||
max uintptr = 0
|
||||
min uintptr = uintptr(^uint(0))
|
||||
max uintptr = 0
|
||||
isAligned64 = true
|
||||
isAligned32 = true
|
||||
)
|
||||
for i := 0; i < len(offset); i++ {
|
||||
typ := (*rtype)(rtypeOff(section, offset[i]))
|
||||
|
@ -56,15 +59,25 @@ func setupCodec() error {
|
|||
max = addr
|
||||
}
|
||||
}
|
||||
|
||||
// check every address is aligned from the base address
|
||||
isAligned64 = isAligned64 && (addr-min)&63 == 0
|
||||
isAligned32 = isAligned32 && (addr-min)&31 == 0
|
||||
}
|
||||
addrRange := max - min
|
||||
if addrRange == 0 {
|
||||
return fmt.Errorf("failed to get address range of types")
|
||||
}
|
||||
if addrRange > maxAcceptableTypeAddrRange {
|
||||
if isAligned64 {
|
||||
typeAddrShift = 6
|
||||
} else if isAligned32 {
|
||||
typeAddrShift = 5
|
||||
}
|
||||
cacheSize := addrRange >> typeAddrShift
|
||||
if cacheSize > maxAcceptableTypeAddrRange {
|
||||
return fmt.Errorf("too big address range %d", addrRange)
|
||||
}
|
||||
cachedDecoder = make([]decoder, addrRange)
|
||||
cachedDecoder = make([]decoder, cacheSize)
|
||||
baseTypeAddr = min
|
||||
maxTypeAddr = max
|
||||
return nil
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
// +build go1.16
|
||||
|
||||
package json
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestTypeAddressAligned32(t *testing.T) {
|
||||
if typeAddrShift != 5 {
|
||||
t.Fatalf("unexpected type address shift %d, want 5", typeAddrShift)
|
||||
}
|
||||
}
|
|
@ -10,7 +10,7 @@ func decodeCompileToGetDecoder(typ *rtype) (decoder, error) {
|
|||
return decodeCompileToGetDecoderSlowPath(typeptr, typ)
|
||||
}
|
||||
|
||||
index := typeptr - baseTypeAddr
|
||||
index := (typeptr - baseTypeAddr) >> typeAddrShift
|
||||
if dec := cachedDecoder[index]; dec != nil {
|
||||
return dec, nil
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ func decodeCompileToGetDecoder(typ *rtype) (decoder, error) {
|
|||
return decodeCompileToGetDecoderSlowPath(typeptr, typ)
|
||||
}
|
||||
|
||||
index := typeptr - baseTypeAddr
|
||||
index := (typeptr - baseTypeAddr) >> typeAddrShift
|
||||
decMu.RLock()
|
||||
if dec := cachedDecoder[index]; dec != nil {
|
||||
decMu.RUnlock()
|
||||
|
|
|
@ -27,7 +27,7 @@ func init() {
|
|||
if typeAddr == nil {
|
||||
typeAddr = &runtime.TypeAddr{}
|
||||
}
|
||||
cachedOpcodeSets = make([]*OpcodeSet, typeAddr.AddrRange)
|
||||
cachedOpcodeSets = make([]*OpcodeSet, typeAddr.AddrRange>>typeAddr.AddrShift)
|
||||
}
|
||||
|
||||
func loadOpcodeMap() map[uintptr]*OpcodeSet {
|
||||
|
|
|
@ -12,7 +12,7 @@ func CompileToGetCodeSet(typeptr uintptr) (*OpcodeSet, error) {
|
|||
if typeptr > typeAddr.MaxTypeAddr {
|
||||
return compileToGetCodeSetSlowPath(typeptr)
|
||||
}
|
||||
index := typeptr - typeAddr.BaseTypeAddr
|
||||
index := (typeptr - typeAddr.BaseTypeAddr) >> typeAddr.AddrShift
|
||||
if codeSet := cachedOpcodeSets[index]; codeSet != nil {
|
||||
return codeSet, nil
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ func CompileToGetCodeSet(typeptr uintptr) (*OpcodeSet, error) {
|
|||
if typeptr > typeAddr.MaxTypeAddr {
|
||||
return compileToGetCodeSetSlowPath(typeptr)
|
||||
}
|
||||
index := typeptr - typeAddr.BaseTypeAddr
|
||||
index := (typeptr - typeAddr.BaseTypeAddr) >> typeAddr.AddrShift
|
||||
setsMu.RLock()
|
||||
if codeSet := cachedOpcodeSets[index]; codeSet != nil {
|
||||
setsMu.RUnlock()
|
||||
|
|
|
@ -19,6 +19,7 @@ type TypeAddr struct {
|
|||
BaseTypeAddr uintptr
|
||||
MaxTypeAddr uintptr
|
||||
AddrRange uintptr
|
||||
AddrShift uintptr
|
||||
}
|
||||
|
||||
var (
|
||||
|
@ -49,8 +50,10 @@ func AnalyzeTypeAddr() *TypeAddr {
|
|||
section := sections[0]
|
||||
offset := offsets[0]
|
||||
var (
|
||||
min uintptr = uintptr(^uint(0))
|
||||
max uintptr = 0
|
||||
min uintptr = uintptr(^uint(0))
|
||||
max uintptr = 0
|
||||
isAligned64 = true
|
||||
isAligned32 = true
|
||||
)
|
||||
for i := 0; i < len(offset); i++ {
|
||||
typ := (*Type)(rtypeOff(section, offset[i]))
|
||||
|
@ -70,18 +73,28 @@ func AnalyzeTypeAddr() *TypeAddr {
|
|||
max = addr
|
||||
}
|
||||
}
|
||||
isAligned64 = isAligned64 && (addr-min)&63 == 0
|
||||
isAligned32 = isAligned32 && (addr-min)&31 == 0
|
||||
}
|
||||
addrRange := max - min
|
||||
if addrRange == 0 {
|
||||
return nil
|
||||
}
|
||||
if addrRange > maxAcceptableTypeAddrRange {
|
||||
var addrShift uintptr
|
||||
if isAligned64 {
|
||||
addrShift = 6
|
||||
} else if isAligned32 {
|
||||
addrShift = 5
|
||||
}
|
||||
cacheSize := addrRange >> addrShift
|
||||
if cacheSize > maxAcceptableTypeAddrRange {
|
||||
return nil
|
||||
}
|
||||
typeAddr = &TypeAddr{
|
||||
BaseTypeAddr: min,
|
||||
MaxTypeAddr: max,
|
||||
AddrRange: addrRange,
|
||||
AddrShift: addrShift,
|
||||
}
|
||||
return typeAddr
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue