Skip to content

Commit

Permalink
Fix: Switch to lazy init() in decoder and encoder (#490)
Browse files Browse the repository at this point in the history
* Switch to lazy init() in decoder and encoder

This will prevent go-json from consuming heap unless it is used.

* limit changes to initEncoder and initDecoder
  • Loading branch information
toddtreece authored Dec 11, 2024
1 parent 3e9769d commit 279389a
Show file tree
Hide file tree
Showing 6 changed files with 26 additions and 12 deletions.
18 changes: 12 additions & 6 deletions internal/decoder/compile.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"reflect"
"strings"
"sync"
"sync/atomic"
"unicode"
"unsafe"
Expand All @@ -17,22 +18,27 @@ var (
typeAddr *runtime.TypeAddr
cachedDecoderMap unsafe.Pointer // map[uintptr]decoder
cachedDecoder []Decoder
initOnce sync.Once
)

func init() {
typeAddr = runtime.AnalyzeTypeAddr()
if typeAddr == nil {
typeAddr = &runtime.TypeAddr{}
}
cachedDecoder = make([]Decoder, typeAddr.AddrRange>>typeAddr.AddrShift+1)
func initDecoder() {
initOnce.Do(func() {
typeAddr = runtime.AnalyzeTypeAddr()
if typeAddr == nil {
typeAddr = &runtime.TypeAddr{}
}
cachedDecoder = make([]Decoder, typeAddr.AddrRange>>typeAddr.AddrShift+1)
})
}

func loadDecoderMap() map[uintptr]Decoder {
initDecoder()
p := atomic.LoadPointer(&cachedDecoderMap)
return *(*map[uintptr]Decoder)(unsafe.Pointer(&p))
}

func storeDecoder(typ uintptr, dec Decoder, m map[uintptr]Decoder) {
initDecoder()
newDecoderMap := make(map[uintptr]Decoder, len(m)+1)
newDecoderMap[typ] = dec

Expand Down
1 change: 1 addition & 0 deletions internal/decoder/compile_norace.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
)

func CompileToGetDecoder(typ *runtime.Type) (Decoder, error) {
initDecoder()
typeptr := uintptr(unsafe.Pointer(typ))
if typeptr > typeAddr.MaxTypeAddr {
return compileToGetDecoderSlowPath(typeptr, typ)
Expand Down
1 change: 1 addition & 0 deletions internal/decoder/compile_race.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
var decMu sync.RWMutex

func CompileToGetDecoder(typ *runtime.Type) (Decoder, error) {
initDecoder()
typeptr := uintptr(unsafe.Pointer(typ))
if typeptr > typeAddr.MaxTypeAddr {
return compileToGetDecoderSlowPath(typeptr, typ)
Expand Down
16 changes: 10 additions & 6 deletions internal/encoder/compiler.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"encoding"
"encoding/json"
"reflect"
"sync"
"sync/atomic"
"unsafe"

Expand All @@ -24,14 +25,17 @@ var (
cachedOpcodeSets []*OpcodeSet
cachedOpcodeMap unsafe.Pointer // map[uintptr]*OpcodeSet
typeAddr *runtime.TypeAddr
initEncoderOnce sync.Once
)

func init() {
typeAddr = runtime.AnalyzeTypeAddr()
if typeAddr == nil {
typeAddr = &runtime.TypeAddr{}
}
cachedOpcodeSets = make([]*OpcodeSet, typeAddr.AddrRange>>typeAddr.AddrShift+1)
func initEncoder() {
initEncoderOnce.Do(func() {
typeAddr = runtime.AnalyzeTypeAddr()
if typeAddr == nil {
typeAddr = &runtime.TypeAddr{}
}
cachedOpcodeSets = make([]*OpcodeSet, typeAddr.AddrRange>>typeAddr.AddrShift+1)
})
}

func loadOpcodeMap() map[uintptr]*OpcodeSet {
Expand Down
1 change: 1 addition & 0 deletions internal/encoder/compiler_norace.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package encoder

func CompileToGetCodeSet(ctx *RuntimeContext, typeptr uintptr) (*OpcodeSet, error) {
initEncoder()
if typeptr > typeAddr.MaxTypeAddr || typeptr < typeAddr.BaseTypeAddr {
codeSet, err := compileToGetCodeSetSlowPath(typeptr)
if err != nil {
Expand Down
1 change: 1 addition & 0 deletions internal/encoder/compiler_race.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
var setsMu sync.RWMutex

func CompileToGetCodeSet(ctx *RuntimeContext, typeptr uintptr) (*OpcodeSet, error) {
initEncoder()
if typeptr > typeAddr.MaxTypeAddr || typeptr < typeAddr.BaseTypeAddr {
codeSet, err := compileToGetCodeSetSlowPath(typeptr)
if err != nil {
Expand Down

0 comments on commit 279389a

Please sign in to comment.