Skip to content

Commit

Permalink
Add type addrShift to enable bigger encoder/decoder cache
Browse files Browse the repository at this point in the history
Change-Id: I630fa501f3b96702b69a40bc0b2f79f4db2a57eb
  • Loading branch information
jxskiss committed May 4, 2021
1 parent 31951a1 commit 8c813a4
Show file tree
Hide file tree
Showing 7 changed files with 65 additions and 12 deletions.
34 changes: 30 additions & 4 deletions codec.go
Expand Up @@ -3,6 +3,7 @@ package json
import (
"fmt"
"reflect"
"sort"
"sync/atomic"
"unsafe"
)
Expand All @@ -16,6 +17,7 @@ var (
cachedDecoderMap unsafe.Pointer // map[uintptr]decoder
baseTypeAddr uintptr
maxTypeAddr uintptr
typeAddrShift uintptr
)

//go:linkname typelinks reflect.typelinks
Expand All @@ -35,8 +37,9 @@ 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
addrs = make([]int, 0, 4*1024)
)
for i := 0; i < len(offset); i++ {
typ := (*rtype)(rtypeOff(section, offset[i]))
Expand All @@ -56,20 +59,43 @@ func setupCodec() error {
max = addr
}
}
addrs = append(addrs, int(addr))
}
addrRange := max - min
if addrRange == 0 {
return fmt.Errorf("failed to get address range of types")
}
if addrRange > maxAcceptableTypeAddrRange {
sort.Ints(addrs)
typeAddrShift = calcTypeOffsetShift(addrs)
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
}

func calcTypeOffsetShift(addrs []int) uintptr {
offset64 := true
offset32 := true
for i := 1; i < len(addrs); i++ {
if incr := addrs[i] - addrs[i-1]; incr&63 != 0 {
offset64 = false
} else if incr&31 != 0 {
offset32 = false
}
}
if offset64 {
return 6
}
if offset32 {
return 5
}
return 0
}

func init() {
_ = setupCodec()
}
Expand Down
2 changes: 1 addition & 1 deletion decode_compile_norace.go
Expand Up @@ -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
}
Expand Down
2 changes: 1 addition & 1 deletion decode_compile_race.go
Expand Up @@ -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()
Expand Down
2 changes: 1 addition & 1 deletion internal/encoder/compiler.go
Expand Up @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion internal/encoder/compiler_norace.go
Expand Up @@ -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
}
Expand Down
2 changes: 1 addition & 1 deletion internal/encoder/compiler_race.go
Expand Up @@ -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()
Expand Down
33 changes: 30 additions & 3 deletions internal/runtime/type.go
Expand Up @@ -2,6 +2,7 @@ package runtime

import (
"reflect"
"sort"
"unsafe"
)

Expand All @@ -19,6 +20,7 @@ type TypeAddr struct {
BaseTypeAddr uintptr
MaxTypeAddr uintptr
AddrRange uintptr
AddrShift uintptr
}

var (
Expand Down Expand Up @@ -49,8 +51,9 @@ 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
addrs = make([]int, 0, 4*1024)
)
for i := 0; i < len(offset); i++ {
typ := (*Type)(rtypeOff(section, offset[i]))
Expand All @@ -70,18 +73,42 @@ func AnalyzeTypeAddr() *TypeAddr {
max = addr
}
}
addrs = append(addrs, int(addr))
}
addrRange := max - min
if addrRange == 0 {
return nil
}
if addrRange > maxAcceptableTypeAddrRange {
sort.Ints(addrs)
addrShift := calcTypeOffsetShift(addrs)
cacheSize := addrRange >> addrShift
if cacheSize > maxAcceptableTypeAddrRange {
return nil
}
typeAddr = &TypeAddr{
BaseTypeAddr: min,
MaxTypeAddr: max,
AddrRange: addrRange,
AddrShift: addrShift,
}
return typeAddr
}

func calcTypeOffsetShift(addrs []int) uintptr {
offset64 := true
offset32 := true
for i := 1; i < len(addrs); i++ {
if incr := addrs[i] - addrs[i-1]; incr&63 != 0 {
offset64 = false
} else if incr&31 != 0 {
offset32 = false
}
}
if offset64 {
return 6
}
if offset32 {
return 5
}
return 0
}

0 comments on commit 8c813a4

Please sign in to comment.