Skip to content

Commit 71a03f1

Browse files
committed
Switch to lazy init() in decoder and encoder
This will prevent go-json from consuming heap unless it is used.
1 parent 5e2ae3f commit 71a03f1

File tree

10 files changed

+916
-861
lines changed

10 files changed

+916
-861
lines changed

internal/decoder/compile.go

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"fmt"
66
"reflect"
77
"strings"
8+
"sync"
89
"sync/atomic"
910
"unicode"
1011
"unsafe"
@@ -17,22 +18,27 @@ var (
1718
typeAddr *runtime.TypeAddr
1819
cachedDecoderMap unsafe.Pointer // map[uintptr]decoder
1920
cachedDecoder []Decoder
21+
initOnce sync.Once
2022
)
2123

22-
func init() {
23-
typeAddr = runtime.AnalyzeTypeAddr()
24-
if typeAddr == nil {
25-
typeAddr = &runtime.TypeAddr{}
26-
}
27-
cachedDecoder = make([]Decoder, typeAddr.AddrRange>>typeAddr.AddrShift+1)
24+
func initDecoder() {
25+
initOnce.Do(func() {
26+
typeAddr = runtime.AnalyzeTypeAddr()
27+
if typeAddr == nil {
28+
typeAddr = &runtime.TypeAddr{}
29+
}
30+
cachedDecoder = make([]Decoder, typeAddr.AddrRange>>typeAddr.AddrShift+1)
31+
})
2832
}
2933

3034
func loadDecoderMap() map[uintptr]Decoder {
35+
initDecoder()
3136
p := atomic.LoadPointer(&cachedDecoderMap)
3237
return *(*map[uintptr]Decoder)(unsafe.Pointer(&p))
3338
}
3439

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

internal/decoder/compile_norace.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
)
1111

1212
func CompileToGetDecoder(typ *runtime.Type) (Decoder, error) {
13+
initDecoder()
1314
typeptr := uintptr(unsafe.Pointer(typ))
1415
if typeptr > typeAddr.MaxTypeAddr {
1516
return compileToGetDecoderSlowPath(typeptr, typ)

internal/decoder/compile_race.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
var decMu sync.RWMutex
1414

1515
func CompileToGetDecoder(typ *runtime.Type) (Decoder, error) {
16+
initDecoder()
1617
typeptr := uintptr(unsafe.Pointer(typ))
1718
if typeptr > typeAddr.MaxTypeAddr {
1819
return compileToGetDecoderSlowPath(typeptr, typ)

internal/encoder/compiler.go

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"encoding"
66
"encoding/json"
77
"reflect"
8+
"sync"
89
"sync/atomic"
910
"unsafe"
1011

@@ -24,14 +25,17 @@ var (
2425
cachedOpcodeSets []*OpcodeSet
2526
cachedOpcodeMap unsafe.Pointer // map[uintptr]*OpcodeSet
2627
typeAddr *runtime.TypeAddr
28+
initEncoderOnce sync.Once
2729
)
2830

29-
func init() {
30-
typeAddr = runtime.AnalyzeTypeAddr()
31-
if typeAddr == nil {
32-
typeAddr = &runtime.TypeAddr{}
33-
}
34-
cachedOpcodeSets = make([]*OpcodeSet, typeAddr.AddrRange>>typeAddr.AddrShift+1)
31+
func initEncoder() {
32+
initEncoderOnce.Do(func() {
33+
typeAddr = runtime.AnalyzeTypeAddr()
34+
if typeAddr == nil {
35+
typeAddr = &runtime.TypeAddr{}
36+
}
37+
cachedOpcodeSets = make([]*OpcodeSet, typeAddr.AddrRange>>typeAddr.AddrShift+1)
38+
})
3539
}
3640

3741
func loadOpcodeMap() map[uintptr]*OpcodeSet {

internal/encoder/compiler_norace.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
package encoder
55

66
func CompileToGetCodeSet(ctx *RuntimeContext, typeptr uintptr) (*OpcodeSet, error) {
7+
initEncoder()
78
if typeptr > typeAddr.MaxTypeAddr || typeptr < typeAddr.BaseTypeAddr {
89
codeSet, err := compileToGetCodeSetSlowPath(typeptr)
910
if err != nil {

internal/encoder/compiler_race.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
var setsMu sync.RWMutex
1111

1212
func CompileToGetCodeSet(ctx *RuntimeContext, typeptr uintptr) (*OpcodeSet, error) {
13+
initEncoder()
1314
if typeptr > typeAddr.MaxTypeAddr || typeptr < typeAddr.BaseTypeAddr {
1415
codeSet, err := compileToGetCodeSetSlowPath(typeptr)
1516
if err != nil {

internal/encoder/int.go

Lines changed: 52 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -25,59 +25,70 @@
2525
package encoder
2626

2727
import (
28+
"sync"
2829
"unsafe"
2930
)
3031

31-
var endianness int
32+
var (
33+
endianness int
34+
initIntOnce sync.Once
35+
intLELookup *[100]uint16
36+
intBELookup *[100]uint16
37+
intLookup [2]*[100]uint16
38+
)
3239

33-
func init() {
34-
var b [2]byte
35-
*(*uint16)(unsafe.Pointer(&b)) = uint16(0xABCD)
40+
func initInt() {
41+
initIntOnce.Do(func() {
42+
var b [2]byte
43+
*(*uint16)(unsafe.Pointer(&b)) = uint16(0xABCD)
44+
45+
switch b[0] {
46+
case 0xCD:
47+
endianness = 0 // LE
48+
case 0xAB:
49+
endianness = 1 // BE
50+
default:
51+
panic("could not determine endianness")
52+
}
3653

37-
switch b[0] {
38-
case 0xCD:
39-
endianness = 0 // LE
40-
case 0xAB:
41-
endianness = 1 // BE
42-
default:
43-
panic("could not determine endianness")
44-
}
45-
}
54+
// "00010203...96979899" cast to []uint16
55+
intLELookup = &[100]uint16{
56+
0x3030, 0x3130, 0x3230, 0x3330, 0x3430, 0x3530, 0x3630, 0x3730, 0x3830, 0x3930,
57+
0x3031, 0x3131, 0x3231, 0x3331, 0x3431, 0x3531, 0x3631, 0x3731, 0x3831, 0x3931,
58+
0x3032, 0x3132, 0x3232, 0x3332, 0x3432, 0x3532, 0x3632, 0x3732, 0x3832, 0x3932,
59+
0x3033, 0x3133, 0x3233, 0x3333, 0x3433, 0x3533, 0x3633, 0x3733, 0x3833, 0x3933,
60+
0x3034, 0x3134, 0x3234, 0x3334, 0x3434, 0x3534, 0x3634, 0x3734, 0x3834, 0x3934,
61+
0x3035, 0x3135, 0x3235, 0x3335, 0x3435, 0x3535, 0x3635, 0x3735, 0x3835, 0x3935,
62+
0x3036, 0x3136, 0x3236, 0x3336, 0x3436, 0x3536, 0x3636, 0x3736, 0x3836, 0x3936,
63+
0x3037, 0x3137, 0x3237, 0x3337, 0x3437, 0x3537, 0x3637, 0x3737, 0x3837, 0x3937,
64+
0x3038, 0x3138, 0x3238, 0x3338, 0x3438, 0x3538, 0x3638, 0x3738, 0x3838, 0x3938,
65+
0x3039, 0x3139, 0x3239, 0x3339, 0x3439, 0x3539, 0x3639, 0x3739, 0x3839, 0x3939,
66+
}
4667

47-
// "00010203...96979899" cast to []uint16
48-
var intLELookup = [100]uint16{
49-
0x3030, 0x3130, 0x3230, 0x3330, 0x3430, 0x3530, 0x3630, 0x3730, 0x3830, 0x3930,
50-
0x3031, 0x3131, 0x3231, 0x3331, 0x3431, 0x3531, 0x3631, 0x3731, 0x3831, 0x3931,
51-
0x3032, 0x3132, 0x3232, 0x3332, 0x3432, 0x3532, 0x3632, 0x3732, 0x3832, 0x3932,
52-
0x3033, 0x3133, 0x3233, 0x3333, 0x3433, 0x3533, 0x3633, 0x3733, 0x3833, 0x3933,
53-
0x3034, 0x3134, 0x3234, 0x3334, 0x3434, 0x3534, 0x3634, 0x3734, 0x3834, 0x3934,
54-
0x3035, 0x3135, 0x3235, 0x3335, 0x3435, 0x3535, 0x3635, 0x3735, 0x3835, 0x3935,
55-
0x3036, 0x3136, 0x3236, 0x3336, 0x3436, 0x3536, 0x3636, 0x3736, 0x3836, 0x3936,
56-
0x3037, 0x3137, 0x3237, 0x3337, 0x3437, 0x3537, 0x3637, 0x3737, 0x3837, 0x3937,
57-
0x3038, 0x3138, 0x3238, 0x3338, 0x3438, 0x3538, 0x3638, 0x3738, 0x3838, 0x3938,
58-
0x3039, 0x3139, 0x3239, 0x3339, 0x3439, 0x3539, 0x3639, 0x3739, 0x3839, 0x3939,
59-
}
68+
intBELookup = &[100]uint16{
69+
0x3030, 0x3031, 0x3032, 0x3033, 0x3034, 0x3035, 0x3036, 0x3037, 0x3038, 0x3039,
70+
0x3130, 0x3131, 0x3132, 0x3133, 0x3134, 0x3135, 0x3136, 0x3137, 0x3138, 0x3139,
71+
0x3230, 0x3231, 0x3232, 0x3233, 0x3234, 0x3235, 0x3236, 0x3237, 0x3238, 0x3239,
72+
0x3330, 0x3331, 0x3332, 0x3333, 0x3334, 0x3335, 0x3336, 0x3337, 0x3338, 0x3339,
73+
0x3430, 0x3431, 0x3432, 0x3433, 0x3434, 0x3435, 0x3436, 0x3437, 0x3438, 0x3439,
74+
0x3530, 0x3531, 0x3532, 0x3533, 0x3534, 0x3535, 0x3536, 0x3537, 0x3538, 0x3539,
75+
0x3630, 0x3631, 0x3632, 0x3633, 0x3634, 0x3635, 0x3636, 0x3637, 0x3638, 0x3639,
76+
0x3730, 0x3731, 0x3732, 0x3733, 0x3734, 0x3735, 0x3736, 0x3737, 0x3738, 0x3739,
77+
0x3830, 0x3831, 0x3832, 0x3833, 0x3834, 0x3835, 0x3836, 0x3837, 0x3838, 0x3839,
78+
0x3930, 0x3931, 0x3932, 0x3933, 0x3934, 0x3935, 0x3936, 0x3937, 0x3938, 0x3939,
79+
}
6080

61-
var intBELookup = [100]uint16{
62-
0x3030, 0x3031, 0x3032, 0x3033, 0x3034, 0x3035, 0x3036, 0x3037, 0x3038, 0x3039,
63-
0x3130, 0x3131, 0x3132, 0x3133, 0x3134, 0x3135, 0x3136, 0x3137, 0x3138, 0x3139,
64-
0x3230, 0x3231, 0x3232, 0x3233, 0x3234, 0x3235, 0x3236, 0x3237, 0x3238, 0x3239,
65-
0x3330, 0x3331, 0x3332, 0x3333, 0x3334, 0x3335, 0x3336, 0x3337, 0x3338, 0x3339,
66-
0x3430, 0x3431, 0x3432, 0x3433, 0x3434, 0x3435, 0x3436, 0x3437, 0x3438, 0x3439,
67-
0x3530, 0x3531, 0x3532, 0x3533, 0x3534, 0x3535, 0x3536, 0x3537, 0x3538, 0x3539,
68-
0x3630, 0x3631, 0x3632, 0x3633, 0x3634, 0x3635, 0x3636, 0x3637, 0x3638, 0x3639,
69-
0x3730, 0x3731, 0x3732, 0x3733, 0x3734, 0x3735, 0x3736, 0x3737, 0x3738, 0x3739,
70-
0x3830, 0x3831, 0x3832, 0x3833, 0x3834, 0x3835, 0x3836, 0x3837, 0x3838, 0x3839,
71-
0x3930, 0x3931, 0x3932, 0x3933, 0x3934, 0x3935, 0x3936, 0x3937, 0x3938, 0x3939,
81+
intLookup = [2]*[100]uint16{intLELookup, intBELookup}
82+
})
7283
}
7384

74-
var intLookup = [2]*[100]uint16{&intLELookup, &intBELookup}
75-
7685
func numMask(numBitSize uint8) uint64 {
7786
return 1<<numBitSize - 1
7887
}
7988

8089
func AppendInt(_ *RuntimeContext, out []byte, p uintptr, code *Opcode) []byte {
90+
initInt() // lazy init
91+
8192
var u64 uint64
8293
switch code.NumBitSize {
8394
case 8:
@@ -132,6 +143,8 @@ func AppendInt(_ *RuntimeContext, out []byte, p uintptr, code *Opcode) []byte {
132143
}
133144

134145
func AppendUint(_ *RuntimeContext, out []byte, p uintptr, code *Opcode) []byte {
146+
initInt() // lazy init
147+
135148
var u64 uint64
136149
switch code.NumBitSize {
137150
case 8:

0 commit comments

Comments
 (0)