@@ -120,6 +120,11 @@ type typeCodeAssignmentState struct {
120120 // all. If it is false, namedNonBasicTypesSidetable will contain simple
121121 // monotonically increasing numbers.
122122 needsNamedNonBasicTypesSidetable bool
123+
124+ // These two slices contain the number of methods on named types, and are
125+ // stored in the output binary with similar names.
126+ namedBasicNumMethodSidetable []byte
127+ namedNonBasicNumMethodSidetable []byte
123128}
124129
125130// assignTypeCodes is used to assign a type code to each type in the program
@@ -138,7 +143,7 @@ func assignTypeCodes(mod llvm.Module, typeSlice typeInfoSlice) {
138143 arrayTypes : make (map [string ]int ),
139144 structTypes : make (map [string ]int ),
140145 structNames : make (map [string ]int ),
141- needsNamedNonBasicTypesSidetable : len (getUses (mod .NamedGlobal ("reflect.namedNonBasicTypesSidetable" ))) != 0 ,
146+ needsNamedNonBasicTypesSidetable : len (getUses (mod .NamedGlobal ("reflect.namedNonBasicTypesSidetable" ))) != 0 || len ( getUses ( mod . NamedGlobal ( "reflect.namedNonBasicNumMethodSidetable" ))) != 0 ,
142147 needsStructTypesSidetable : len (getUses (mod .NamedGlobal ("reflect.structTypesSidetable" ))) != 0 ,
143148 needsStructNamesSidetable : len (getUses (mod .NamedGlobal ("reflect.structNamesSidetable" ))) != 0 ,
144149 needsArrayTypesSidetable : len (getUses (mod .NamedGlobal ("reflect.arrayTypesSidetable" ))) != 0 ,
@@ -157,7 +162,21 @@ func assignTypeCodes(mod llvm.Module, typeSlice typeInfoSlice) {
157162
158163 // Only create this sidetable when it is necessary.
159164 if state .needsNamedNonBasicTypesSidetable {
160- global := replaceGlobalIntWithArray (mod , "reflect.namedNonBasicTypesSidetable" , state .namedNonBasicTypesSidetable )
165+ if len (getUses (mod .NamedGlobal ("reflect.namedNonBasicTypesSidetable" ))) != 0 {
166+ global := replaceGlobalIntWithArray (mod , "reflect.namedNonBasicTypesSidetable" , state .namedNonBasicTypesSidetable )
167+ global .SetLinkage (llvm .InternalLinkage )
168+ global .SetUnnamedAddr (true )
169+ global .SetGlobalConstant (true )
170+ }
171+ if len (getUses (mod .NamedGlobal ("reflect.namedNonBasicNumMethodSidetable" ))) != 0 {
172+ global := replaceGlobalIntWithArray (mod , "reflect.namedNonBasicNumMethodSidetable" , state .namedNonBasicNumMethodSidetable )
173+ global .SetLinkage (llvm .InternalLinkage )
174+ global .SetUnnamedAddr (true )
175+ global .SetGlobalConstant (true )
176+ }
177+ }
178+ if len (getUses (mod .NamedGlobal ("reflect.namedBasicNumMethodSidetable" ))) != 0 {
179+ global := replaceGlobalIntWithArray (mod , "reflect.namedBasicNumMethodSidetable" , state .namedBasicNumMethodSidetable )
161180 global .SetLinkage (llvm .InternalLinkage )
162181 global .SetUnnamedAddr (true )
163182 global .SetGlobalConstant (true )
@@ -189,9 +208,12 @@ func (state *typeCodeAssignmentState) getTypeCodeNum(typecode llvm.Value) *big.I
189208 // Note: see src/reflect/type.go for bit allocations.
190209 class , value := getClassAndValueFromTypeCode (typecode )
191210 name := ""
211+ var namedNumMethods uint64 // number of methods for a named type
192212 if class == "named" {
193213 name = value
194- typecode = llvm .ConstExtractValue (typecode .Initializer (), []uint32 {0 })
214+ initializer := typecode .Initializer ()
215+ typecode = llvm .ConstExtractValue (initializer , []uint32 {0 })
216+ namedNumMethods = llvm .ConstExtractValue (initializer , []uint32 {2 }).ZExtValue ()
195217 class , value = getClassAndValueFromTypeCode (typecode )
196218 }
197219 if class == "basic" {
@@ -205,7 +227,7 @@ func (state *typeCodeAssignmentState) getTypeCodeNum(typecode llvm.Value) *big.I
205227 }
206228 if name != "" {
207229 // This type is named, set the upper bits to the name ID.
208- num |= int64 (state .getBasicNamedTypeNum (name )) << 5
230+ num |= int64 (state .getBasicNamedTypeNum (name , namedNumMethods )) << 5
209231 }
210232 return big .NewInt (num << 1 )
211233 } else {
@@ -248,6 +270,14 @@ func (state *typeCodeAssignmentState) getTypeCodeNum(typecode llvm.Value) *big.I
248270 index := len (state .namedNonBasicTypesSidetable )
249271 state .namedNonBasicTypesSidetable = append (state .namedNonBasicTypesSidetable , 0 )
250272 state .namedNonBasicTypes [name ] = index
273+ // Also store the number of methods.
274+ if index != len (state .namedNonBasicNumMethodSidetable ) {
275+ panic ("unexpected side table length" )
276+ }
277+ if uint64 (byte (namedNumMethods )) != namedNumMethods {
278+ panic ("too many methods for type " + name )
279+ }
280+ state .namedNonBasicNumMethodSidetable = append (state .namedNonBasicNumMethodSidetable , byte (namedNumMethods ))
251281 // Get the typecode of the underlying type (which could be the
252282 // element type in the case of pointers, for example).
253283 num = state .getNonBasicTypeCode (class , typecode )
@@ -316,12 +346,19 @@ func getClassAndValueFromTypeCode(typecode llvm.Value) (class, value string) {
316346// getBasicNamedTypeNum returns an appropriate (unique) number for the given
317347// named type. If the name already has a number that number is returned, else a
318348// new number is returned. The number is always non-zero.
319- func (state * typeCodeAssignmentState ) getBasicNamedTypeNum (name string ) int {
349+ func (state * typeCodeAssignmentState ) getBasicNamedTypeNum (name string , numMethods uint64 ) int {
320350 if num , ok := state .namedBasicTypes [name ]; ok {
321351 return num
322352 }
323353 num := len (state .namedBasicTypes ) + 1
324354 state .namedBasicTypes [name ] = num
355+ if uint64 (byte (numMethods )) != numMethods {
356+ panic ("too many methods for type " + name )
357+ }
358+ if len (state .namedBasicNumMethodSidetable ) != num - 1 {
359+ panic ("unexpected side table length" )
360+ }
361+ state .namedBasicNumMethodSidetable = append (state .namedBasicNumMethodSidetable , byte (numMethods ))
325362 return num
326363}
327364
@@ -381,15 +418,21 @@ func (state *typeCodeAssignmentState) getStructTypeNum(typecode llvm.Value) int
381418 }
382419
383420 // Get the fields this struct type contains.
384- // The struct number will be the start index of
385- structTypeGlobal := llvm .ConstExtractValue (typecode .Initializer (), []uint32 {0 }).Operand (0 ).Initializer ()
421+ // The struct number will be the start index into
422+ // reflect.structTypesSidetable.
423+ typecodeID := typecode .Initializer ()
424+ structTypeGlobal := llvm .ConstExtractValue (typecodeID , []uint32 {0 }).Operand (0 ).Initializer ()
386425 numFields := structTypeGlobal .Type ().ArrayLength ()
387-
388- // The first data that is stored in the struct sidetable is the number of
389- // fields this struct contains. This is usually just a single byte because
390- // most structs don't contain that many fields, but make it a varint just
391- // to be sure.
392- buf := makeVarint (uint64 (numFields ))
426+ numMethods := llvm .ConstExtractValue (typecodeID , []uint32 {2 }).ZExtValue ()
427+
428+ // The first element that is stored in the struct sidetable is the number
429+ // of methods this struct has. It is used by Type.NumMethod().
430+ buf := makeVarint (numMethods )
431+ // The second element that is stored in the struct sidetable is the number
432+ // of fields this struct contains. This is usually just a single byte
433+ // because most structs don't contain that many fields, but make it a varint
434+ // just to be sure.
435+ buf = append (buf , makeVarint (uint64 (numFields ))... )
393436
394437 // Iterate over every field in the struct.
395438 // Every field is stored sequentially in the struct sidetable. Fields can
0 commit comments