Skip to content

Commit 396975c

Browse files
json: codec is passed as a pointer
1 parent 40c79bc commit 396975c

File tree

1 file changed

+83
-67
lines changed

1 file changed

+83
-67
lines changed

json/codec.go

Lines changed: 83 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,9 @@ type (
7878
// Note: using a uintptr as key instead of reflect.Type shaved ~15ns off of
7979
// the ~30ns Marhsal/Unmarshal functions which were dominated by the map
8080
// lookup time for simple types like bool, int, etc..
81-
var cache atomic.Pointer[map[unsafe.Pointer]codec]
81+
var cache atomic.Pointer[map[unsafe.Pointer]*codec]
8282

83-
func cachedCodec(t reflect.Type) codec {
83+
func cachedCodec(t reflect.Type) *codec {
8484
cache := cacheLoad()
8585

8686
c, found := cache[typeid(t)]
@@ -91,7 +91,7 @@ func cachedCodec(t reflect.Type) codec {
9191
return c
9292
}
9393

94-
func cacheLoad() map[unsafe.Pointer]codec {
94+
func cacheLoad() map[unsafe.Pointer]*codec {
9595
p := cache.Load()
9696
if p == nil {
9797
return nil
@@ -100,8 +100,8 @@ func cacheLoad() map[unsafe.Pointer]codec {
100100
return *p
101101
}
102102

103-
func cacheStore(typ reflect.Type, cod codec, oldCodecs map[unsafe.Pointer]codec) {
104-
newCodecs := make(map[unsafe.Pointer]codec, len(oldCodecs)+1)
103+
func cacheStore(typ reflect.Type, cod *codec, oldCodecs map[unsafe.Pointer]*codec) {
104+
newCodecs := make(map[unsafe.Pointer]*codec, len(oldCodecs)+1)
105105
maps.Copy(newCodecs, oldCodecs)
106106
newCodecs[typeid(typ)] = cod
107107

@@ -112,7 +112,7 @@ func typeid(t reflect.Type) unsafe.Pointer {
112112
return (*iface)(unsafe.Pointer(&t)).ptr
113113
}
114114

115-
func constructCachedCodec(t reflect.Type, cache map[unsafe.Pointer]codec) codec {
115+
func constructCachedCodec(t reflect.Type, cache map[unsafe.Pointer]*codec) *codec {
116116
seen := make(seenMap)
117117
c := constructCodec(t, seen, t.Kind() == reflect.Ptr)
118118

@@ -131,79 +131,81 @@ type seenType struct {
131131

132132
type seenMap map[reflect.Type]seenType
133133

134-
func constructCodec(t reflect.Type, seen seenMap, canAddr bool) (c codec) {
134+
func constructCodec(t reflect.Type, seen seenMap, canAddr bool) *codec {
135+
var c *codec
136+
135137
switch t {
136138
case nullType, nil:
137-
c = codec{encode: encoder.encodeNull, decode: decoder.decodeNull}
139+
c = &codec{encode: encoder.encodeNull, decode: decoder.decodeNull}
138140

139141
case numberType:
140-
c = codec{encode: encoder.encodeNumber, decode: decoder.decodeNumber}
142+
c = &codec{encode: encoder.encodeNumber, decode: decoder.decodeNumber}
141143

142144
case bytesType:
143-
c = codec{encode: encoder.encodeBytes, decode: decoder.decodeBytes}
145+
c = &codec{encode: encoder.encodeBytes, decode: decoder.decodeBytes}
144146

145147
case durationType:
146-
c = codec{encode: encoder.encodeDuration, decode: decoder.decodeDuration}
148+
c = &codec{encode: encoder.encodeDuration, decode: decoder.decodeDuration}
147149

148150
case timeType:
149-
c = codec{encode: encoder.encodeTime, decode: decoder.decodeTime}
151+
c = &codec{encode: encoder.encodeTime, decode: decoder.decodeTime}
150152

151153
case interfaceType:
152-
c = codec{encode: encoder.encodeInterface, decode: decoder.decodeInterface}
154+
c = &codec{encode: encoder.encodeInterface, decode: decoder.decodeInterface}
153155

154156
case rawMessageType:
155-
c = codec{encode: encoder.encodeRawMessage, decode: decoder.decodeRawMessage}
157+
c = &codec{encode: encoder.encodeRawMessage, decode: decoder.decodeRawMessage}
156158
}
157159

158-
if c.encode != nil {
159-
return
160+
if c != nil {
161+
return c
160162
}
161163

162164
switch t.Kind() {
163165
case reflect.Bool:
164-
c = codec{encode: encoder.encodeBool, decode: decoder.decodeBool}
166+
c = &codec{encode: encoder.encodeBool, decode: decoder.decodeBool}
165167

166168
case reflect.Int:
167-
c = codec{encode: encoder.encodeInt, decode: decoder.decodeInt}
169+
c = &codec{encode: encoder.encodeInt, decode: decoder.decodeInt}
168170

169171
case reflect.Int8:
170-
c = codec{encode: encoder.encodeInt8, decode: decoder.decodeInt8}
172+
c = &codec{encode: encoder.encodeInt8, decode: decoder.decodeInt8}
171173

172174
case reflect.Int16:
173-
c = codec{encode: encoder.encodeInt16, decode: decoder.decodeInt16}
175+
c = &codec{encode: encoder.encodeInt16, decode: decoder.decodeInt16}
174176

175177
case reflect.Int32:
176-
c = codec{encode: encoder.encodeInt32, decode: decoder.decodeInt32}
178+
c = &codec{encode: encoder.encodeInt32, decode: decoder.decodeInt32}
177179

178180
case reflect.Int64:
179-
c = codec{encode: encoder.encodeInt64, decode: decoder.decodeInt64}
181+
c = &codec{encode: encoder.encodeInt64, decode: decoder.decodeInt64}
180182

181183
case reflect.Uint:
182-
c = codec{encode: encoder.encodeUint, decode: decoder.decodeUint}
184+
c = &codec{encode: encoder.encodeUint, decode: decoder.decodeUint}
183185

184186
case reflect.Uintptr:
185-
c = codec{encode: encoder.encodeUintptr, decode: decoder.decodeUintptr}
187+
c = &codec{encode: encoder.encodeUintptr, decode: decoder.decodeUintptr}
186188

187189
case reflect.Uint8:
188-
c = codec{encode: encoder.encodeUint8, decode: decoder.decodeUint8}
190+
c = &codec{encode: encoder.encodeUint8, decode: decoder.decodeUint8}
189191

190192
case reflect.Uint16:
191-
c = codec{encode: encoder.encodeUint16, decode: decoder.decodeUint16}
193+
c = &codec{encode: encoder.encodeUint16, decode: decoder.decodeUint16}
192194

193195
case reflect.Uint32:
194-
c = codec{encode: encoder.encodeUint32, decode: decoder.decodeUint32}
196+
c = &codec{encode: encoder.encodeUint32, decode: decoder.decodeUint32}
195197

196198
case reflect.Uint64:
197-
c = codec{encode: encoder.encodeUint64, decode: decoder.decodeUint64}
199+
c = &codec{encode: encoder.encodeUint64, decode: decoder.decodeUint64}
198200

199201
case reflect.Float32:
200-
c = codec{encode: encoder.encodeFloat32, decode: decoder.decodeFloat32}
202+
c = &codec{encode: encoder.encodeFloat32, decode: decoder.decodeFloat32}
201203

202204
case reflect.Float64:
203-
c = codec{encode: encoder.encodeFloat64, decode: decoder.decodeFloat64}
205+
c = &codec{encode: encoder.encodeFloat64, decode: decoder.decodeFloat64}
204206

205207
case reflect.String:
206-
c = codec{encode: encoder.encodeString, decode: decoder.decodeString}
208+
c = &codec{encode: encoder.encodeString, decode: decoder.decodeString}
207209

208210
case reflect.Interface:
209211
c = constructInterfaceCodec(t)
@@ -252,12 +254,12 @@ func constructCodec(t reflect.Type, seen seenMap, canAddr bool) (c codec) {
252254
c.decode = constructTextUnmarshalerDecodeFunc(t, true)
253255
}
254256

255-
return
257+
return c
256258
}
257259

258-
func constructStringCodec(t reflect.Type, seen seenMap, canAddr bool) codec {
260+
func constructStringCodec(t reflect.Type, seen seenMap, canAddr bool) *codec {
259261
c := constructCodec(t, seen, canAddr)
260-
return codec{
262+
return &codec{
261263
encode: constructStringEncodeFunc(c.encode),
262264
decode: constructStringDecodeFunc(c.decode),
263265
}
@@ -281,11 +283,11 @@ func constructStringToIntDecodeFunc(t reflect.Type, decode decodeFunc) decodeFun
281283
}
282284
}
283285

284-
func constructArrayCodec(t reflect.Type, seen seenMap, canAddr bool) codec {
286+
func constructArrayCodec(t reflect.Type, seen seenMap, canAddr bool) *codec {
285287
e := t.Elem()
286288
c := constructCodec(e, seen, canAddr)
287289
s := alignedSize(e)
288-
return codec{
290+
return &codec{
289291
encode: constructArrayEncodeFunc(s, t, c.encode),
290292
decode: constructArrayDecodeFunc(s, t, c.decode),
291293
}
@@ -305,7 +307,18 @@ func constructArrayDecodeFunc(size uintptr, t reflect.Type, decode decodeFunc) d
305307
}
306308
}
307309

308-
func constructSliceCodec(t reflect.Type, seen seenMap) codec {
310+
func constructSliceCodec(t reflect.Type, seen seenMap) *codec {
311+
// Detect slice type recursion (and prevent stack overflow).
312+
seenInfo := seen[t]
313+
c := seenInfo.codec
314+
if c != nil {
315+
return c
316+
}
317+
318+
c = new(codec)
319+
seenInfo.codec = c
320+
seen[t] = seenInfo
321+
309322
e := t.Elem()
310323
s := alignedSize(e)
311324

@@ -314,7 +327,6 @@ func constructSliceCodec(t reflect.Type, seen seenMap) codec {
314327
// default encoding and decoding behaviors by implementing marshaler and
315328
// unmarshaler interfaces.
316329
p := reflect.PointerTo(e)
317-
c := codec{}
318330

319331
switch {
320332
case e.Implements(jsonMarshalerType):
@@ -353,11 +365,11 @@ func constructSliceCodec(t reflect.Type, seen seenMap) codec {
353365
return c
354366
}
355367

356-
c := constructCodec(e, seen, true)
357-
return codec{
358-
encode: constructSliceEncodeFunc(s, t, c.encode),
359-
decode: constructSliceDecodeFunc(s, t, c.decode),
360-
}
368+
inner := constructCodec(e, seen, true)
369+
c.encode = constructSliceEncodeFunc(s, t, inner.encode)
370+
c.decode = constructSliceDecodeFunc(s, t, inner.decode)
371+
372+
return c
361373
}
362374

363375
func constructSliceEncodeFunc(size uintptr, t reflect.Type, encode encodeFunc) encodeFunc {
@@ -372,50 +384,52 @@ func constructSliceDecodeFunc(size uintptr, t reflect.Type, decode decodeFunc) d
372384
}
373385
}
374386

375-
func constructMapCodec(t reflect.Type, seen seenMap) codec {
387+
func constructMapCodec(t reflect.Type, seen seenMap) *codec {
376388
var sortKeys sortFunc
377389
k := t.Key()
378390
v := t.Elem()
379391

380392
// Faster implementations for some common cases.
381393
switch {
382394
case k == stringType && v == interfaceType:
383-
return codec{
395+
return &codec{
384396
encode: encoder.encodeMapStringInterface,
385397
decode: decoder.decodeMapStringInterface,
386398
}
387399

388400
case k == stringType && v == rawMessageType:
389-
return codec{
401+
return &codec{
390402
encode: encoder.encodeMapStringRawMessage,
391403
decode: decoder.decodeMapStringRawMessage,
392404
}
393405

394406
case k == stringType && v == stringType:
395-
return codec{
407+
return &codec{
396408
encode: encoder.encodeMapStringString,
397409
decode: decoder.decodeMapStringString,
398410
}
399411

400412
case k == stringType && v == stringsType:
401-
return codec{
413+
return &codec{
402414
encode: encoder.encodeMapStringStringSlice,
403415
decode: decoder.decodeMapStringStringSlice,
404416
}
405417

406418
case k == stringType && v == boolType:
407-
return codec{
419+
return &codec{
408420
encode: encoder.encodeMapStringBool,
409421
decode: decoder.decodeMapStringBool,
410422
}
411423
}
412424

413-
kc := codec{}
425+
var kc *codec
414426
vc := constructCodec(v, seen, false)
415427

416428
if k.Implements(textMarshalerType) || reflect.PointerTo(k).Implements(textUnmarshalerType) {
417-
kc.encode = constructTextMarshalerEncodeFunc(k, false)
418-
kc.decode = constructTextUnmarshalerDecodeFunc(k, true)
429+
kc = &codec{
430+
encode: constructTextMarshalerEncodeFunc(k, false),
431+
decode: constructTextUnmarshalerDecodeFunc(k, true),
432+
}
419433

420434
sortKeys = func(keys []reflect.Value) {
421435
sort.Slice(keys, func(i, j int) bool {
@@ -429,8 +443,10 @@ func constructMapCodec(t reflect.Type, seen seenMap) codec {
429443
} else {
430444
switch k.Kind() {
431445
case reflect.String:
432-
kc.encode = encoder.encodeString
433-
kc.decode = decoder.decodeString
446+
kc = &codec{
447+
encode: encoder.encodeString,
448+
decode: decoder.decodeString,
449+
}
434450

435451
sortKeys = func(keys []reflect.Value) {
436452
sort.Slice(keys, func(i, j int) bool { return keys[i].String() < keys[j].String() })
@@ -468,7 +484,7 @@ func constructMapCodec(t reflect.Type, seen seenMap) codec {
468484
vc.encode = constructInlineValueEncodeFunc(vc.encode)
469485
}
470486

471-
return codec{
487+
return &codec{
472488
encode: constructMapEncodeFunc(t, kc.encode, vc.encode, sortKeys),
473489
decode: constructMapDecodeFunc(t, kc.decode, vc.decode),
474490
}
@@ -490,9 +506,9 @@ func constructMapDecodeFunc(t reflect.Type, decodeKey, decodeValue decodeFunc) d
490506
}
491507
}
492508

493-
func constructStructCodec(t reflect.Type, seen seenMap, canAddr bool) codec {
509+
func constructStructCodec(t reflect.Type, seen seenMap, canAddr bool) *codec {
494510
st := constructStructType(t, seen, canAddr)
495-
return codec{
511+
return &codec{
496512
encode: constructStructEncodeFunc(st),
497513
decode: constructStructDecodeFunc(st),
498514
}
@@ -502,7 +518,7 @@ func constructStructType(t reflect.Type, seen seenMap, canAddr bool) *structType
502518
// Used for preventing infinite recursion on types that have pointers to
503519
// themselves.
504520
seenInfo := seen[t]
505-
st := seen[t].structType
521+
st := seenInfo.structType
506522

507523
if st == nil {
508524
st = &structType{
@@ -555,8 +571,8 @@ func constructStructDecodeFunc(st *structType) decodeFunc {
555571
}
556572
}
557573

558-
func constructEmbeddedStructPointerCodec(t reflect.Type, unexported bool, offset uintptr, field codec) codec {
559-
return codec{
574+
func constructEmbeddedStructPointerCodec(t reflect.Type, unexported bool, offset uintptr, field *codec) *codec {
575+
return &codec{
560576
encode: constructEmbeddedStructPointerEncodeFunc(t, unexported, offset, field.encode),
561577
decode: constructEmbeddedStructPointerDecodeFunc(t, unexported, offset, field.decode),
562578
}
@@ -775,10 +791,10 @@ func encodeKeyFragment(s string, flags AppendFlags) string {
775791
return *(*string)(unsafe.Pointer(&b))
776792
}
777793

778-
func constructPointerCodec(t reflect.Type, seen seenMap) codec {
794+
func constructPointerCodec(t reflect.Type, seen seenMap) *codec {
779795
e := t.Elem()
780796
c := constructCodec(e, seen, true)
781-
return codec{
797+
return &codec{
782798
encode: constructPointerEncodeFunc(e, c.encode),
783799
decode: constructPointerDecodeFunc(e, c.decode),
784800
}
@@ -796,8 +812,8 @@ func constructPointerDecodeFunc(t reflect.Type, decode decodeFunc) decodeFunc {
796812
}
797813
}
798814

799-
func constructInterfaceCodec(t reflect.Type) codec {
800-
return codec{
815+
func constructInterfaceCodec(t reflect.Type) *codec {
816+
return &codec{
801817
encode: constructMaybeEmptyInterfaceEncoderFunc(t),
802818
decode: constructMaybeEmptyInterfaceDecoderFunc(t),
803819
}
@@ -815,8 +831,8 @@ func constructMaybeEmptyInterfaceDecoderFunc(t reflect.Type) decodeFunc {
815831
}
816832
}
817833

818-
func constructUnsupportedTypeCodec(t reflect.Type) codec {
819-
return codec{
834+
func constructUnsupportedTypeCodec(t reflect.Type) *codec {
835+
return &codec{
820836
encode: constructUnsupportedTypeEncodeFunc(t),
821837
decode: constructUnsupportedTypeDecodeFunc(t),
822838
}
@@ -1000,7 +1016,7 @@ type structType struct {
10001016
}
10011017

10021018
type structField struct {
1003-
codec codec
1019+
codec *codec
10041020
offset uintptr
10051021
empty emptyFunc
10061022
tag bool

0 commit comments

Comments
 (0)