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
132132type 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
363375func 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
10021018type structField struct {
1003- codec codec
1019+ codec * codec
10041020 offset uintptr
10051021 empty emptyFunc
10061022 tag bool
0 commit comments