@@ -394,16 +394,13 @@ type interfaceType struct {
394
394
// mapType represents a map type.
395
395
type mapType struct {
396
396
rtype
397
- key * rtype // map key type
398
- elem * rtype // map element (value) type
399
- bucket * rtype // internal bucket structure
400
- keysize uint8 // size of key slot
401
- indirectkey uint8 // store ptr to key instead of key itself
402
- valuesize uint8 // size of value slot
403
- indirectvalue uint8 // store ptr to value instead of value itself
404
- bucketsize uint16 // size of bucket
405
- reflexivekey bool // true if k==k for all keys
406
- needkeyupdate bool // true if we need to update key on an overwrite
397
+ key * rtype // map key type
398
+ elem * rtype // map element (value) type
399
+ bucket * rtype // internal bucket structure
400
+ keysize uint8 // size of key slot
401
+ valuesize uint8 // size of value slot
402
+ bucketsize uint16 // size of bucket
403
+ flags uint32
407
404
}
408
405
409
406
// ptrType represents a pointer type.
@@ -593,6 +590,7 @@ const (
593
590
kindMask = (1 << 5 ) - 1
594
591
)
595
592
593
+ // String returns the name of k.
596
594
func (k Kind ) String () string {
597
595
if int (k ) < len (kindNames ) {
598
596
return kindNames [k ]
@@ -1858,6 +1856,8 @@ func MapOf(key, elem Type) Type {
1858
1856
}
1859
1857
1860
1858
// Make a map type.
1859
+ // Note: flag values must match those used in the TMAP case
1860
+ // in ../cmd/compile/internal/gc/reflect.go:dtypesym.
1861
1861
var imap interface {} = (map [unsafe.Pointer ]unsafe.Pointer )(nil )
1862
1862
mt := * * (* * mapType )(unsafe .Pointer (& imap ))
1863
1863
mt .str = resolveReflectName (newName (s , "" , false ))
@@ -1866,29 +1866,37 @@ func MapOf(key, elem Type) Type {
1866
1866
mt .key = ktyp
1867
1867
mt .elem = etyp
1868
1868
mt .bucket = bucketOf (ktyp , etyp )
1869
+ mt .flags = 0
1869
1870
if ktyp .size > maxKeySize {
1870
1871
mt .keysize = uint8 (ptrSize )
1871
- mt .indirectkey = 1
1872
+ mt .flags | = 1 // indirect key
1872
1873
} else {
1873
1874
mt .keysize = uint8 (ktyp .size )
1874
- mt .indirectkey = 0
1875
1875
}
1876
1876
if etyp .size > maxValSize {
1877
1877
mt .valuesize = uint8 (ptrSize )
1878
- mt .indirectvalue = 1
1878
+ mt .flags |= 2 // indirect value
1879
1879
} else {
1880
1880
mt .valuesize = uint8 (etyp .size )
1881
- mt .indirectvalue = 0
1882
1881
}
1883
1882
mt .bucketsize = uint16 (mt .bucket .size )
1884
- mt .reflexivekey = isReflexive (ktyp )
1885
- mt .needkeyupdate = needKeyUpdate (ktyp )
1883
+ if isReflexive (ktyp ) {
1884
+ mt .flags |= 4
1885
+ }
1886
+ if needKeyUpdate (ktyp ) {
1887
+ mt .flags |= 8
1888
+ }
1889
+ if hashMightPanic (ktyp ) {
1890
+ mt .flags |= 16
1891
+ }
1886
1892
mt .ptrToThis = 0
1887
1893
1888
1894
ti , _ := lookupCache .LoadOrStore (ckey , & mt .rtype )
1889
1895
return ti .(Type )
1890
1896
}
1891
1897
1898
+ // TODO(crawshaw): as these funcTypeFixedN structs have no methods,
1899
+ // they could be defined at runtime using the StructOf function.
1892
1900
type funcTypeFixed4 struct {
1893
1901
funcType
1894
1902
args [4 ]* rtype
@@ -2119,6 +2127,27 @@ func needKeyUpdate(t *rtype) bool {
2119
2127
}
2120
2128
}
2121
2129
2130
+ // hashMightPanic reports whether the hash of a map key of type t might panic.
2131
+ func hashMightPanic (t * rtype ) bool {
2132
+ switch t .Kind () {
2133
+ case Interface :
2134
+ return true
2135
+ case Array :
2136
+ tt := (* arrayType )(unsafe .Pointer (t ))
2137
+ return hashMightPanic (tt .elem )
2138
+ case Struct :
2139
+ tt := (* structType )(unsafe .Pointer (t ))
2140
+ for _ , f := range tt .fields {
2141
+ if hashMightPanic (f .typ ) {
2142
+ return true
2143
+ }
2144
+ }
2145
+ return false
2146
+ default :
2147
+ return false
2148
+ }
2149
+ }
2150
+
2122
2151
// Make sure these routines stay in sync with ../../runtime/map.go!
2123
2152
// These types exist only for GC, so we only fill out GC relevant info.
2124
2153
// Currently, that's just size and the GC program. We also fill in string
@@ -2278,43 +2307,7 @@ type structTypeUncommon struct {
2278
2307
u uncommonType
2279
2308
}
2280
2309
2281
- // A *rtype representing a struct is followed directly in memory by an
2282
- // array of method objects representing the methods attached to the
2283
- // struct. To get the same layout for a run time generated type, we
2284
- // need an array directly following the uncommonType memory. The types
2285
- // structTypeFixed4, ...structTypeFixedN are used to do this.
2286
- //
2287
- // A similar strategy is used for funcTypeFixed4, ...funcTypeFixedN.
2288
-
2289
- // TODO(crawshaw): as these structTypeFixedN and funcTypeFixedN structs
2290
- // have no methods, they could be defined at runtime using the StructOf
2291
- // function.
2292
-
2293
- type structTypeFixed4 struct {
2294
- structType
2295
- u uncommonType
2296
- m [4 ]method
2297
- }
2298
-
2299
- type structTypeFixed8 struct {
2300
- structType
2301
- u uncommonType
2302
- m [8 ]method
2303
- }
2304
-
2305
- type structTypeFixed16 struct {
2306
- structType
2307
- u uncommonType
2308
- m [16 ]method
2309
- }
2310
-
2311
- type structTypeFixed32 struct {
2312
- structType
2313
- u uncommonType
2314
- m [32 ]method
2315
- }
2316
-
2317
- // isLetter returns true if a given 'rune' is classified as a Letter.
2310
+ // isLetter reports whether a given 'rune' is classified as a Letter.
2318
2311
func isLetter (ch rune ) bool {
2319
2312
return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '_' || ch >= utf8 .RuneSelf && unicode .IsLetter (ch )
2320
2313
}
@@ -2571,33 +2564,26 @@ func StructOf(fields []StructField) Type {
2571
2564
var typ * structType
2572
2565
var ut * uncommonType
2573
2566
2574
- switch {
2575
- case len (methods ) == 0 :
2567
+ if len (methods ) == 0 {
2576
2568
t := new (structTypeUncommon )
2577
2569
typ = & t .structType
2578
2570
ut = & t .u
2579
- case len (methods ) <= 4 :
2580
- t := new (structTypeFixed4 )
2581
- typ = & t .structType
2582
- ut = & t .u
2583
- copy (t .m [:], methods )
2584
- case len (methods ) <= 8 :
2585
- t := new (structTypeFixed8 )
2586
- typ = & t .structType
2587
- ut = & t .u
2588
- copy (t .m [:], methods )
2589
- case len (methods ) <= 16 :
2590
- t := new (structTypeFixed16 )
2591
- typ = & t .structType
2592
- ut = & t .u
2593
- copy (t .m [:], methods )
2594
- case len (methods ) <= 32 :
2595
- t := new (structTypeFixed32 )
2596
- typ = & t .structType
2597
- ut = & t .u
2598
- copy (t .m [:], methods )
2599
- default :
2600
- panic ("reflect.StructOf: too many methods" )
2571
+ } else {
2572
+ // A *rtype representing a struct is followed directly in memory by an
2573
+ // array of method objects representing the methods attached to the
2574
+ // struct. To get the same layout for a run time generated type, we
2575
+ // need an array directly following the uncommonType memory.
2576
+ // A similar strategy is used for funcTypeFixed4, ...funcTypeFixedN.
2577
+ tt := New (StructOf ([]StructField {
2578
+ {Name : "S" , Type : TypeOf (structType {})},
2579
+ {Name : "U" , Type : TypeOf (uncommonType {})},
2580
+ {Name : "M" , Type : ArrayOf (len (methods ), TypeOf (methods [0 ]))},
2581
+ }))
2582
+
2583
+ typ = (* structType )(unsafe .Pointer (tt .Elem ().Field (0 ).UnsafeAddr ()))
2584
+ ut = (* uncommonType )(unsafe .Pointer (tt .Elem ().Field (1 ).UnsafeAddr ()))
2585
+
2586
+ copy (tt .Elem ().Field (2 ).Slice (0 , len (methods )).Interface ().([]method ), methods )
2601
2587
}
2602
2588
// TODO(sbinet): Once we allow embedding multiple types,
2603
2589
// methods will need to be sorted like the compiler does.
0 commit comments