@@ -37,7 +37,7 @@ import (
3737)
3838
3939// A list of basic types and their numbers. This list should be kept in sync
40- // with the list of Kind constants of type.go in the runtime package.
40+ // with the list of Kind constants of type.go in the reflect package.
4141var basicTypes = map [string ]int64 {
4242 "bool" : 1 ,
4343 "int" : 2 ,
@@ -59,6 +59,19 @@ var basicTypes = map[string]int64{
5959 "unsafeptr" : 18 ,
6060}
6161
62+ // A list of non-basic types. Adding 19 to this number will give the Kind as
63+ // used in src/reflect/types.go, and it must be kept in sync with that list.
64+ var nonBasicTypes = map [string ]int64 {
65+ "chan" : 0 ,
66+ "interface" : 1 ,
67+ "pointer" : 2 ,
68+ "slice" : 3 ,
69+ "array" : 4 ,
70+ "func" : 5 ,
71+ "map" : 6 ,
72+ "struct" : 7 ,
73+ }
74+
6275// typeCodeAssignmentState keeps some global state around for type code
6376// assignments, used to assign one unique type code to each Go type.
6477type typeCodeAssignmentState struct {
@@ -96,7 +109,7 @@ type typeCodeAssignmentState struct {
96109 // Note that this byte buffer is not created when it is not needed
97110 // (reflect.namedNonBasicTypesSidetable has no uses), see
98111 // needsNamedTypesSidetable.
99- namedNonBasicTypesSidetable []byte
112+ namedNonBasicTypesSidetable []uint64
100113
101114 // This indicates whether namedNonBasicTypesSidetable needs to be created at
102115 // all. If it is false, namedNonBasicTypesSidetable will contain simple
@@ -144,17 +157,17 @@ func (c *Compiler) assignTypeCodes(typeSlice typeInfoSlice) {
144157
145158 // Only create this sidetable when it is necessary.
146159 if state .needsNamedNonBasicTypesSidetable {
147- global := c .replaceGlobalByteWithArray ("reflect.namedNonBasicTypesSidetable" , state .namedNonBasicTypesSidetable )
160+ global := c .replaceGlobalIntWithArray ("reflect.namedNonBasicTypesSidetable" , state .namedNonBasicTypesSidetable )
148161 global .SetLinkage (llvm .InternalLinkage )
149162 global .SetUnnamedAddr (true )
150163 }
151164 if state .needsStructTypesSidetable {
152- global := c .replaceGlobalByteWithArray ("reflect.structTypesSidetable" , state .structTypesSidetable )
165+ global := c .replaceGlobalIntWithArray ("reflect.structTypesSidetable" , state .structTypesSidetable )
153166 global .SetLinkage (llvm .InternalLinkage )
154167 global .SetUnnamedAddr (true )
155168 }
156169 if state .needsStructNamesSidetable {
157- global := c .replaceGlobalByteWithArray ("reflect.structNamesSidetable" , state .structNamesSidetable )
170+ global := c .replaceGlobalIntWithArray ("reflect.structNamesSidetable" , state .structNamesSidetable )
158171 global .SetLinkage (llvm .InternalLinkage )
159172 global .SetUnnamedAddr (true )
160173 }
@@ -194,49 +207,76 @@ func (state *typeCodeAssignmentState) getTypeCodeNum(typecode llvm.Value) *big.I
194207 // (channel, interface, pointer, slice) just contain the bits of the
195208 // wrapped type. Other types (like struct) need more fields and thus
196209 // cannot be encoded as a simple prefix.
197- var num * big.Int
198210 var classNumber int64
199- switch class {
200- case "chan" :
201- sub := llvm .ConstExtractValue (typecode .Initializer (), []uint32 {0 })
202- num = state .getTypeCodeNum (sub )
203- classNumber = 0
204- case "interface" :
205- num = big .NewInt (int64 (state .fallbackIndex ))
206- state .fallbackIndex ++
207- classNumber = 1
208- case "pointer" :
209- sub := llvm .ConstExtractValue (typecode .Initializer (), []uint32 {0 })
210- num = state .getTypeCodeNum (sub )
211- classNumber = 2
212- case "slice" :
213- sub := llvm .ConstExtractValue (typecode .Initializer (), []uint32 {0 })
214- num = state .getTypeCodeNum (sub )
215- classNumber = 3
216- case "array" :
217- num = big .NewInt (int64 (state .fallbackIndex ))
218- state .fallbackIndex ++
219- classNumber = 4
220- case "func" :
221- num = big .NewInt (int64 (state .fallbackIndex ))
222- state .fallbackIndex ++
223- classNumber = 5
224- case "map" :
225- num = big .NewInt (int64 (state .fallbackIndex ))
226- state .fallbackIndex ++
227- classNumber = 6
228- case "struct" :
229- num = big .NewInt (int64 (state .getStructTypeNum (typecode )))
230- classNumber = 7
231- default :
211+ if n , ok := nonBasicTypes [class ]; ok {
212+ classNumber = n
213+ } else {
232214 panic ("unknown type kind: " + class )
233215 }
216+ var num * big.Int
217+ lowBits := (classNumber << 1 ) + 1 // the 5 low bits of the typecode
234218 if name == "" {
235- num . Lsh ( num , 5 ). Or ( num , big . NewInt (( classNumber << 1 ) + 1 ) )
219+ num = state . getNonBasicTypeCode ( class , typecode )
236220 } else {
237- num = big .NewInt (int64 (state .getNonBasicNamedTypeNum (name , num ))<< 1 | 1 )
238- num .Lsh (num , 4 ).Or (num , big .NewInt ((classNumber << 1 )+ 1 ))
221+ // We must return a named type here. But first check whether it
222+ // has already been defined.
223+ if index , ok := state .namedNonBasicTypes [name ]; ok {
224+ num := big .NewInt (int64 (index ))
225+ num .Lsh (num , 5 ).Or (num , big .NewInt ((classNumber << 1 )+ 1 + (1 << 4 )))
226+ return num
227+ }
228+ lowBits |= 1 << 4 // set the 'n' bit (see above)
229+ if ! state .needsNamedNonBasicTypesSidetable {
230+ // Use simple small integers in this case, to make these numbers
231+ // smaller.
232+ index := len (state .namedNonBasicTypes ) + 1
233+ state .namedNonBasicTypes [name ] = index
234+ num = big .NewInt (int64 (index ))
235+ } else {
236+ // We need to store full type information.
237+ // First allocate a number in the named non-basic type
238+ // sidetable.
239+ index := len (state .namedNonBasicTypesSidetable )
240+ state .namedNonBasicTypesSidetable = append (state .namedNonBasicTypesSidetable , 0 )
241+ state .namedNonBasicTypes [name ] = index
242+ // Get the typecode of the underlying type (which could be the
243+ // element type in the case of pointers, for example).
244+ num = state .getNonBasicTypeCode (class , typecode )
245+ if num .BitLen () > state .uintptrLen || ! num .IsUint64 () {
246+ panic ("cannot store value in sidetable" )
247+ }
248+ // Now update the side table with the number we just
249+ // determined. We need this multi-step approach to avoid stack
250+ // overflow due to adding types recursively in the case of
251+ // linked lists (a pointer which points to a struct that
252+ // contains that same pointer).
253+ state .namedNonBasicTypesSidetable [index ] = num .Uint64 ()
254+ num = big .NewInt (int64 (index ))
255+ }
239256 }
257+ // Concatenate the 'num' and 'lowBits' bitstrings.
258+ num .Lsh (num , 5 ).Or (num , big .NewInt (lowBits ))
259+ return num
260+ }
261+ }
262+
263+ // getNonBasicTypeCode is used by getTypeCodeNum. It returns the upper bits of
264+ // the type code used there in the type code.
265+ func (state * typeCodeAssignmentState ) getNonBasicTypeCode (class string , typecode llvm.Value ) * big.Int {
266+ switch class {
267+ case "chan" , "pointer" , "slice" :
268+ // Prefix-style type kinds. The upper bits contain the element type.
269+ sub := llvm .ConstExtractValue (typecode .Initializer (), []uint32 {0 })
270+ return state .getTypeCodeNum (sub )
271+ case "struct" :
272+ // More complicated type kind. The upper bits contain the index to the
273+ // struct type in the struct types sidetable.
274+ return big .NewInt (int64 (state .getStructTypeNum (typecode )))
275+ default :
276+ // Type has not yet been implemented, so fall back by using a unique
277+ // number.
278+ num := big .NewInt (int64 (state .fallbackIndex ))
279+ state .fallbackIndex ++
240280 return num
241281 }
242282}
@@ -272,29 +312,6 @@ func (state *typeCodeAssignmentState) getBasicNamedTypeNum(name string) int {
272312 return num
273313}
274314
275- // getNonBasicNamedTypeNum returns a number unique for this named type. It tries
276- // to return the smallest number possible to make encoding of this type code
277- // easier.
278- func (state * typeCodeAssignmentState ) getNonBasicNamedTypeNum (name string , value * big.Int ) int {
279- if num , ok := state .namedNonBasicTypes [name ]; ok {
280- return num
281- }
282- if ! state .needsNamedNonBasicTypesSidetable {
283- // Use simple small integers in this case, to make these numbers
284- // smaller.
285- num := len (state .namedNonBasicTypes ) + 1
286- state .namedNonBasicTypes [name ] = num
287- return num
288- }
289- num := len (state .namedNonBasicTypesSidetable )
290- if value .BitLen () > state .uintptrLen || ! value .IsUint64 () {
291- panic ("cannot store value in sidetable" )
292- }
293- state .namedNonBasicTypesSidetable = append (state .namedNonBasicTypesSidetable , makeVarint (value .Uint64 ())... )
294- state .namedNonBasicTypes [name ] = num
295- return num
296- }
297-
298315// getStructTypeNum returns the struct type number, which is an index into
299316// reflect.structTypesSidetable or an unique number for every struct if this
300317// sidetable is not needed in the to-be-compiled program.
0 commit comments