mirror of https://github.com/goccy/go-json.git
Merge pull request #213 from jxskiss/compact_type_cache
Add type addrShift to enable bigger encoder/decoder cache
This commit is contained in:
commit
102554cbcd
17
codec.go
17
codec.go
|
@ -16,6 +16,7 @@ var (
|
||||||
cachedDecoderMap unsafe.Pointer // map[uintptr]decoder
|
cachedDecoderMap unsafe.Pointer // map[uintptr]decoder
|
||||||
baseTypeAddr uintptr
|
baseTypeAddr uintptr
|
||||||
maxTypeAddr uintptr
|
maxTypeAddr uintptr
|
||||||
|
typeAddrShift uintptr
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:linkname typelinks reflect.typelinks
|
//go:linkname typelinks reflect.typelinks
|
||||||
|
@ -37,6 +38,8 @@ func setupCodec() error {
|
||||||
var (
|
var (
|
||||||
min uintptr = uintptr(^uint(0))
|
min uintptr = uintptr(^uint(0))
|
||||||
max uintptr = 0
|
max uintptr = 0
|
||||||
|
isAligned64 = true
|
||||||
|
isAligned32 = true
|
||||||
)
|
)
|
||||||
for i := 0; i < len(offset); i++ {
|
for i := 0; i < len(offset); i++ {
|
||||||
typ := (*rtype)(rtypeOff(section, offset[i]))
|
typ := (*rtype)(rtypeOff(section, offset[i]))
|
||||||
|
@ -56,15 +59,25 @@ func setupCodec() error {
|
||||||
max = addr
|
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
|
addrRange := max - min
|
||||||
if addrRange == 0 {
|
if addrRange == 0 {
|
||||||
return fmt.Errorf("failed to get address range of types")
|
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)
|
return fmt.Errorf("too big address range %d", addrRange)
|
||||||
}
|
}
|
||||||
cachedDecoder = make([]decoder, addrRange)
|
cachedDecoder = make([]decoder, cacheSize)
|
||||||
baseTypeAddr = min
|
baseTypeAddr = min
|
||||||
maxTypeAddr = max
|
maxTypeAddr = max
|
||||||
return nil
|
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)
|
return decodeCompileToGetDecoderSlowPath(typeptr, typ)
|
||||||
}
|
}
|
||||||
|
|
||||||
index := typeptr - baseTypeAddr
|
index := (typeptr - baseTypeAddr) >> typeAddrShift
|
||||||
if dec := cachedDecoder[index]; dec != nil {
|
if dec := cachedDecoder[index]; dec != nil {
|
||||||
return dec, nil
|
return dec, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ func decodeCompileToGetDecoder(typ *rtype) (decoder, error) {
|
||||||
return decodeCompileToGetDecoderSlowPath(typeptr, typ)
|
return decodeCompileToGetDecoderSlowPath(typeptr, typ)
|
||||||
}
|
}
|
||||||
|
|
||||||
index := typeptr - baseTypeAddr
|
index := (typeptr - baseTypeAddr) >> typeAddrShift
|
||||||
decMu.RLock()
|
decMu.RLock()
|
||||||
if dec := cachedDecoder[index]; dec != nil {
|
if dec := cachedDecoder[index]; dec != nil {
|
||||||
decMu.RUnlock()
|
decMu.RUnlock()
|
||||||
|
|
|
@ -27,7 +27,7 @@ func init() {
|
||||||
if typeAddr == nil {
|
if typeAddr == nil {
|
||||||
typeAddr = &runtime.TypeAddr{}
|
typeAddr = &runtime.TypeAddr{}
|
||||||
}
|
}
|
||||||
cachedOpcodeSets = make([]*OpcodeSet, typeAddr.AddrRange)
|
cachedOpcodeSets = make([]*OpcodeSet, typeAddr.AddrRange>>typeAddr.AddrShift)
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadOpcodeMap() map[uintptr]*OpcodeSet {
|
func loadOpcodeMap() map[uintptr]*OpcodeSet {
|
||||||
|
|
|
@ -12,7 +12,7 @@ func CompileToGetCodeSet(typeptr uintptr) (*OpcodeSet, error) {
|
||||||
if typeptr > typeAddr.MaxTypeAddr {
|
if typeptr > typeAddr.MaxTypeAddr {
|
||||||
return compileToGetCodeSetSlowPath(typeptr)
|
return compileToGetCodeSetSlowPath(typeptr)
|
||||||
}
|
}
|
||||||
index := typeptr - typeAddr.BaseTypeAddr
|
index := (typeptr - typeAddr.BaseTypeAddr) >> typeAddr.AddrShift
|
||||||
if codeSet := cachedOpcodeSets[index]; codeSet != nil {
|
if codeSet := cachedOpcodeSets[index]; codeSet != nil {
|
||||||
return codeSet, nil
|
return codeSet, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ func CompileToGetCodeSet(typeptr uintptr) (*OpcodeSet, error) {
|
||||||
if typeptr > typeAddr.MaxTypeAddr {
|
if typeptr > typeAddr.MaxTypeAddr {
|
||||||
return compileToGetCodeSetSlowPath(typeptr)
|
return compileToGetCodeSetSlowPath(typeptr)
|
||||||
}
|
}
|
||||||
index := typeptr - typeAddr.BaseTypeAddr
|
index := (typeptr - typeAddr.BaseTypeAddr) >> typeAddr.AddrShift
|
||||||
setsMu.RLock()
|
setsMu.RLock()
|
||||||
if codeSet := cachedOpcodeSets[index]; codeSet != nil {
|
if codeSet := cachedOpcodeSets[index]; codeSet != nil {
|
||||||
setsMu.RUnlock()
|
setsMu.RUnlock()
|
||||||
|
|
|
@ -19,6 +19,7 @@ type TypeAddr struct {
|
||||||
BaseTypeAddr uintptr
|
BaseTypeAddr uintptr
|
||||||
MaxTypeAddr uintptr
|
MaxTypeAddr uintptr
|
||||||
AddrRange uintptr
|
AddrRange uintptr
|
||||||
|
AddrShift uintptr
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -51,6 +52,8 @@ func AnalyzeTypeAddr() *TypeAddr {
|
||||||
var (
|
var (
|
||||||
min uintptr = uintptr(^uint(0))
|
min uintptr = uintptr(^uint(0))
|
||||||
max uintptr = 0
|
max uintptr = 0
|
||||||
|
isAligned64 = true
|
||||||
|
isAligned32 = true
|
||||||
)
|
)
|
||||||
for i := 0; i < len(offset); i++ {
|
for i := 0; i < len(offset); i++ {
|
||||||
typ := (*Type)(rtypeOff(section, offset[i]))
|
typ := (*Type)(rtypeOff(section, offset[i]))
|
||||||
|
@ -70,18 +73,28 @@ func AnalyzeTypeAddr() *TypeAddr {
|
||||||
max = addr
|
max = addr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
isAligned64 = isAligned64 && (addr-min)&63 == 0
|
||||||
|
isAligned32 = isAligned32 && (addr-min)&31 == 0
|
||||||
}
|
}
|
||||||
addrRange := max - min
|
addrRange := max - min
|
||||||
if addrRange == 0 {
|
if addrRange == 0 {
|
||||||
return nil
|
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
|
return nil
|
||||||
}
|
}
|
||||||
typeAddr = &TypeAddr{
|
typeAddr = &TypeAddr{
|
||||||
BaseTypeAddr: min,
|
BaseTypeAddr: min,
|
||||||
MaxTypeAddr: max,
|
MaxTypeAddr: max,
|
||||||
AddrRange: addrRange,
|
AddrRange: addrRange,
|
||||||
|
AddrShift: addrShift,
|
||||||
}
|
}
|
||||||
return typeAddr
|
return typeAddr
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue