@@ -2278,6 +2278,25 @@ func makeMapMarshaler(f *reflect.StructField) (sizer, marshaler) {
2278
2278
// value.
2279
2279
// Key cannot be pointer-typed.
2280
2280
valIsPtr := valType .Kind () == reflect .Ptr
2281
+
2282
+ // If value is a message with nested maps, calling
2283
+ // valSizer in marshal may be quadratic. We should use
2284
+ // cached version in marshal (but not in size).
2285
+ // If value is not message type, we don't have size cache,
2286
+ // but it cannot be nested either. Just use valSizer.
2287
+ valCachedSizer := valSizer
2288
+ if valIsPtr && valType .Elem ().Kind () == reflect .Struct {
2289
+ u := getMarshalInfo (valType .Elem ())
2290
+ valCachedSizer = func (ptr pointer , tagsize int ) int {
2291
+ // Same as message sizer, but use cache.
2292
+ p := ptr .getPointer ()
2293
+ if p .isNil () {
2294
+ return 0
2295
+ }
2296
+ siz := u .cachedsize (p )
2297
+ return siz + SizeVarint (uint64 (siz )) + tagsize
2298
+ }
2299
+ }
2281
2300
return func (ptr pointer , tagsize int ) int {
2282
2301
m := ptr .asPointerTo (t ).Elem () // the map
2283
2302
n := 0
@@ -2304,7 +2323,7 @@ func makeMapMarshaler(f *reflect.StructField) (sizer, marshaler) {
2304
2323
kaddr := toAddrPointer (& ki , false ) // pointer to key
2305
2324
vaddr := toAddrPointer (& vi , valIsPtr ) // pointer to value
2306
2325
b = appendVarint (b , tag )
2307
- siz := keySizer (kaddr , 1 ) + valSizer (vaddr , 1 ) // tag of key = 1 (size=1), tag of val = 2 (size=1)
2326
+ siz := keySizer (kaddr , 1 ) + valCachedSizer (vaddr , 1 ) // tag of key = 1 (size=1), tag of val = 2 (size=1)
2308
2327
b = appendVarint (b , uint64 (siz ))
2309
2328
b , err = keyMarshaler (b , kaddr , keyWireTag , deterministic )
2310
2329
if err != nil {
0 commit comments