mirror of https://github.com/goccy/go-json.git
Switch to lazy init() in decoder and encoder
This will prevent go-json from consuming heap unless it is used.
This commit is contained in:
parent
3e9769d637
commit
f14426c40f
|
@ -5,6 +5,7 @@ import (
|
|||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"unicode"
|
||||
"unsafe"
|
||||
|
@ -17,22 +18,27 @@ var (
|
|||
typeAddr *runtime.TypeAddr
|
||||
cachedDecoderMap unsafe.Pointer // map[uintptr]decoder
|
||||
cachedDecoder []Decoder
|
||||
initOnce sync.Once
|
||||
)
|
||||
|
||||
func init() {
|
||||
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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"encoding"
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"unsafe"
|
||||
|
||||
|
@ -24,14 +25,17 @@ var (
|
|||
cachedOpcodeSets []*OpcodeSet
|
||||
cachedOpcodeMap unsafe.Pointer // map[uintptr]*OpcodeSet
|
||||
typeAddr *runtime.TypeAddr
|
||||
initEncoderOnce sync.Once
|
||||
)
|
||||
|
||||
func init() {
|
||||
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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -25,12 +25,20 @@
|
|||
package encoder
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var endianness int
|
||||
var (
|
||||
endianness int
|
||||
initIntOnce sync.Once
|
||||
intLELookup *[100]uint16
|
||||
intBELookup *[100]uint16
|
||||
intLookup [2]*[100]uint16
|
||||
)
|
||||
|
||||
func init() {
|
||||
func initInt() {
|
||||
initIntOnce.Do(func() {
|
||||
var b [2]byte
|
||||
*(*uint16)(unsafe.Pointer(&b)) = uint16(0xABCD)
|
||||
|
||||
|
@ -42,10 +50,9 @@ func init() {
|
|||
default:
|
||||
panic("could not determine endianness")
|
||||
}
|
||||
}
|
||||
|
||||
// "00010203...96979899" cast to []uint16
|
||||
var intLELookup = [100]uint16{
|
||||
// "00010203...96979899" cast to []uint16
|
||||
intLELookup = &[100]uint16{
|
||||
0x3030, 0x3130, 0x3230, 0x3330, 0x3430, 0x3530, 0x3630, 0x3730, 0x3830, 0x3930,
|
||||
0x3031, 0x3131, 0x3231, 0x3331, 0x3431, 0x3531, 0x3631, 0x3731, 0x3831, 0x3931,
|
||||
0x3032, 0x3132, 0x3232, 0x3332, 0x3432, 0x3532, 0x3632, 0x3732, 0x3832, 0x3932,
|
||||
|
@ -56,9 +63,9 @@ var intLELookup = [100]uint16{
|
|||
0x3037, 0x3137, 0x3237, 0x3337, 0x3437, 0x3537, 0x3637, 0x3737, 0x3837, 0x3937,
|
||||
0x3038, 0x3138, 0x3238, 0x3338, 0x3438, 0x3538, 0x3638, 0x3738, 0x3838, 0x3938,
|
||||
0x3039, 0x3139, 0x3239, 0x3339, 0x3439, 0x3539, 0x3639, 0x3739, 0x3839, 0x3939,
|
||||
}
|
||||
}
|
||||
|
||||
var intBELookup = [100]uint16{
|
||||
intBELookup = &[100]uint16{
|
||||
0x3030, 0x3031, 0x3032, 0x3033, 0x3034, 0x3035, 0x3036, 0x3037, 0x3038, 0x3039,
|
||||
0x3130, 0x3131, 0x3132, 0x3133, 0x3134, 0x3135, 0x3136, 0x3137, 0x3138, 0x3139,
|
||||
0x3230, 0x3231, 0x3232, 0x3233, 0x3234, 0x3235, 0x3236, 0x3237, 0x3238, 0x3239,
|
||||
|
@ -69,15 +76,19 @@ var intBELookup = [100]uint16{
|
|||
0x3730, 0x3731, 0x3732, 0x3733, 0x3734, 0x3735, 0x3736, 0x3737, 0x3738, 0x3739,
|
||||
0x3830, 0x3831, 0x3832, 0x3833, 0x3834, 0x3835, 0x3836, 0x3837, 0x3838, 0x3839,
|
||||
0x3930, 0x3931, 0x3932, 0x3933, 0x3934, 0x3935, 0x3936, 0x3937, 0x3938, 0x3939,
|
||||
}
|
||||
}
|
||||
|
||||
var intLookup = [2]*[100]uint16{&intLELookup, &intBELookup}
|
||||
intLookup = [2]*[100]uint16{intLELookup, intBELookup}
|
||||
})
|
||||
}
|
||||
|
||||
func numMask(numBitSize uint8) uint64 {
|
||||
return 1<<numBitSize - 1
|
||||
}
|
||||
|
||||
func AppendInt(_ *RuntimeContext, out []byte, p uintptr, code *Opcode) []byte {
|
||||
initInt() // lazy init
|
||||
|
||||
var u64 uint64
|
||||
switch code.NumBitSize {
|
||||
case 8:
|
||||
|
@ -132,6 +143,8 @@ func AppendInt(_ *RuntimeContext, out []byte, p uintptr, code *Opcode) []byte {
|
|||
}
|
||||
|
||||
func AppendUint(_ *RuntimeContext, out []byte, p uintptr, code *Opcode) []byte {
|
||||
initInt() // lazy init
|
||||
|
||||
var u64 uint64
|
||||
switch code.NumBitSize {
|
||||
case 8:
|
||||
|
|
|
@ -3,6 +3,7 @@ package encoder
|
|||
|
||||
import (
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type CodeType int
|
||||
|
@ -22,7 +23,14 @@ const (
|
|||
CodeStructEnd CodeType = 11
|
||||
)
|
||||
|
||||
var opTypeStrings = [400]string{
|
||||
var (
|
||||
opTypeStrings *[400]string
|
||||
initOpTypeOnce sync.Once
|
||||
)
|
||||
|
||||
func initOpType() {
|
||||
initOpTypeOnce.Do(func() {
|
||||
opTypeStrings = &[400]string{
|
||||
"End",
|
||||
"Interface",
|
||||
"Ptr",
|
||||
|
@ -423,6 +431,8 @@ var opTypeStrings = [400]string{
|
|||
"StructFieldOmitEmpty",
|
||||
"StructEnd",
|
||||
"StructEndOmitEmpty",
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
type OpType uint16
|
||||
|
@ -831,6 +841,8 @@ const (
|
|||
)
|
||||
|
||||
func (t OpType) String() string {
|
||||
initOpType() // lazy initialization
|
||||
|
||||
if int(t) >= 400 {
|
||||
return ""
|
||||
}
|
||||
|
|
|
@ -47,6 +47,8 @@ func stringToUint64Slice(s string) []uint64 {
|
|||
}
|
||||
|
||||
func AppendString(ctx *RuntimeContext, buf []byte, s string) []byte {
|
||||
initStringTable() // lazy initialization
|
||||
|
||||
if ctx.Option.Flag&HTMLEscapeOption != 0 {
|
||||
if ctx.Option.Flag&NormalizeUTF8Option != 0 {
|
||||
return appendNormalizedHTMLString(buf, s)
|
||||
|
|
|
@ -1,6 +1,18 @@
|
|||
package encoder
|
||||
|
||||
var needEscapeHTMLNormalizeUTF8 = [256]bool{
|
||||
import "sync"
|
||||
|
||||
var (
|
||||
needEscapeHTMLNormalizeUTF8 *[256]bool
|
||||
needEscapeNormalizeUTF8 *[256]bool
|
||||
needEscapeHTML *[256]bool
|
||||
needEscape *[256]bool
|
||||
initStringTableOnce sync.Once
|
||||
)
|
||||
|
||||
func initStringTable() {
|
||||
initStringTableOnce.Do(func() {
|
||||
needEscapeHTMLNormalizeUTF8 = &[256]bool{
|
||||
'"': true,
|
||||
'&': true,
|
||||
'<': true,
|
||||
|
@ -167,9 +179,9 @@ var needEscapeHTMLNormalizeUTF8 = [256]bool{
|
|||
0xfd: true,
|
||||
0xfe: true,
|
||||
0xff: true,
|
||||
}
|
||||
}
|
||||
|
||||
var needEscapeNormalizeUTF8 = [256]bool{
|
||||
needEscapeNormalizeUTF8 = &[256]bool{
|
||||
'"': true,
|
||||
'\\': true,
|
||||
0x00: true,
|
||||
|
@ -333,9 +345,9 @@ var needEscapeNormalizeUTF8 = [256]bool{
|
|||
0xfd: true,
|
||||
0xfe: true,
|
||||
0xff: true,
|
||||
}
|
||||
}
|
||||
|
||||
var needEscapeHTML = [256]bool{
|
||||
needEscapeHTML = &[256]bool{
|
||||
'"': true,
|
||||
'&': true,
|
||||
'<': true,
|
||||
|
@ -374,9 +386,9 @@ var needEscapeHTML = [256]bool{
|
|||
0x1e: true,
|
||||
0x1f: true,
|
||||
/* 0x20 - 0xff */
|
||||
}
|
||||
}
|
||||
|
||||
var needEscape = [256]bool{
|
||||
needEscape = &[256]bool{
|
||||
'"': true,
|
||||
'\\': true,
|
||||
0x00: true,
|
||||
|
@ -412,4 +424,6 @@ var needEscape = [256]bool{
|
|||
0x1e: true,
|
||||
0x1f: true,
|
||||
/* 0x20 - 0xff */
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue