blob: 3e690567376449a86a375257737904cd64470738 [file] [log] [blame]
Russ Cox8c195bd2015-02-13 14:40:36 -05001// Copyright 2009 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package gc
6
7import (
Russ Cox512f75e2015-05-08 01:43:18 -04008 "cmd/internal/gcprog"
Russ Cox8c195bd2015-02-13 14:40:36 -05009 "cmd/internal/obj"
10 "fmt"
Russ Cox512f75e2015-05-08 01:43:18 -040011 "os"
Russ Cox8c195bd2015-02-13 14:40:36 -050012)
13
14/*
15 * runtime interface and reflection data structures
16 */
17var signatlist *NodeList
18
19func sigcmp(a *Sig, b *Sig) int {
Russ Cox382b44e2015-02-23 16:07:24 -050020 i := stringsCompare(a.name, b.name)
Russ Cox8c195bd2015-02-13 14:40:36 -050021 if i != 0 {
22 return i
23 }
24 if a.pkg == b.pkg {
25 return 0
26 }
27 if a.pkg == nil {
28 return -1
29 }
30 if b.pkg == nil {
31 return +1
32 }
Russ Coxbed1f902015-03-02 16:03:26 -050033 return stringsCompare(a.pkg.Path, b.pkg.Path)
Russ Cox8c195bd2015-02-13 14:40:36 -050034}
35
36func lsort(l *Sig, f func(*Sig, *Sig) int) *Sig {
Russ Cox8c195bd2015-02-13 14:40:36 -050037 if l == nil || l.link == nil {
38 return l
39 }
40
Russ Cox382b44e2015-02-23 16:07:24 -050041 l1 := l
42 l2 := l
Russ Cox8c195bd2015-02-13 14:40:36 -050043 for {
44 l2 = l2.link
45 if l2 == nil {
46 break
47 }
48 l2 = l2.link
49 if l2 == nil {
50 break
51 }
52 l1 = l1.link
53 }
54
55 l2 = l1.link
56 l1.link = nil
57 l1 = lsort(l, f)
58 l2 = lsort(l2, f)
59
60 /* set up lead element */
61 if f(l1, l2) < 0 {
62 l = l1
63 l1 = l1.link
64 } else {
65 l = l2
66 l2 = l2.link
67 }
68
Russ Cox382b44e2015-02-23 16:07:24 -050069 le := l
Russ Cox8c195bd2015-02-13 14:40:36 -050070
71 for {
72 if l1 == nil {
73 for l2 != nil {
74 le.link = l2
75 le = l2
76 l2 = l2.link
77 }
78
79 le.link = nil
80 break
81 }
82
83 if l2 == nil {
84 for l1 != nil {
85 le.link = l1
86 le = l1
87 l1 = l1.link
88 }
89
90 break
91 }
92
93 if f(l1, l2) < 0 {
94 le.link = l1
95 le = l1
96 l1 = l1.link
97 } else {
98 le.link = l2
99 le = l2
100 l2 = l2.link
101 }
102 }
103
104 le.link = nil
105 return l
106}
107
Ainar Garipov7f9f70e2015-06-11 16:49:38 +0300108// Builds a type representing a Bucket structure for
Russ Cox8c195bd2015-02-13 14:40:36 -0500109// the given map type. This type is not visible to users -
110// we include only enough information to generate a correct GC
111// program for it.
Keith Randallcd5b1442015-03-11 12:58:47 -0700112// Make sure this stays in sync with ../../runtime/hashmap.go!
Russ Cox8c195bd2015-02-13 14:40:36 -0500113const (
114 BUCKETSIZE = 8
115 MAXKEYSIZE = 128
116 MAXVALSIZE = 128
117)
118
119func makefield(name string, t *Type) *Type {
Russ Cox382b44e2015-02-23 16:07:24 -0500120 f := typ(TFIELD)
Russ Cox8c195bd2015-02-13 14:40:36 -0500121 f.Type = t
122 f.Sym = new(Sym)
123 f.Sym.Name = name
124 return f
125}
126
127func mapbucket(t *Type) *Type {
Russ Cox8c195bd2015-02-13 14:40:36 -0500128 if t.Bucket != nil {
129 return t.Bucket
130 }
131
Russ Cox382b44e2015-02-23 16:07:24 -0500132 bucket := typ(TSTRUCT)
133 keytype := t.Down
134 valtype := t.Type
Russ Cox8c195bd2015-02-13 14:40:36 -0500135 dowidth(keytype)
136 dowidth(valtype)
137 if keytype.Width > MAXKEYSIZE {
138 keytype = Ptrto(keytype)
139 }
140 if valtype.Width > MAXVALSIZE {
141 valtype = Ptrto(valtype)
142 }
143
144 // The first field is: uint8 topbits[BUCKETSIZE].
Russ Cox382b44e2015-02-23 16:07:24 -0500145 arr := typ(TARRAY)
Russ Cox8c195bd2015-02-13 14:40:36 -0500146
147 arr.Type = Types[TUINT8]
148 arr.Bound = BUCKETSIZE
Russ Coxc5dff722015-07-30 22:05:51 -0400149 field := make([]*Type, 0, 5)
150 field = append(field, makefield("topbits", arr))
Russ Cox8c195bd2015-02-13 14:40:36 -0500151 arr = typ(TARRAY)
152 arr.Type = keytype
153 arr.Bound = BUCKETSIZE
Russ Coxc5dff722015-07-30 22:05:51 -0400154 field = append(field, makefield("keys", arr))
Russ Cox8c195bd2015-02-13 14:40:36 -0500155 arr = typ(TARRAY)
156 arr.Type = valtype
157 arr.Bound = BUCKETSIZE
Russ Coxc5dff722015-07-30 22:05:51 -0400158 field = append(field, makefield("values", arr))
159
160 // Make sure the overflow pointer is the last memory in the struct,
161 // because the runtime assumes it can use size-ptrSize as the
162 // offset of the overflow pointer. We double-check that property
163 // below once the offsets and size are computed.
164 //
165 // BUCKETSIZE is 8, so the struct is aligned to 64 bits to this point.
166 // On 32-bit systems, the max alignment is 32-bit, and the
167 // overflow pointer will add another 32-bit field, and the struct
168 // will end with no padding.
169 // On 64-bit systems, the max alignment is 64-bit, and the
170 // overflow pointer will add another 64-bit field, and the struct
171 // will end with no padding.
172 // On nacl/amd64p32, however, the max alignment is 64-bit,
173 // but the overflow pointer will add only a 32-bit field,
174 // so if the struct needs 64-bit padding (because a key or value does)
175 // then it would end with an extra 32-bit padding field.
176 // Preempt that by emitting the padding here.
177 if int(t.Type.Align) > Widthptr || int(t.Down.Align) > Widthptr {
178 field = append(field, makefield("pad", Types[TUINTPTR]))
179 }
180
181 // If keys and values have no pointers, the map implementation
182 // can keep a list of overflow pointers on the side so that
183 // buckets can be marked as having no pointers.
184 // Arrange for the bucket to have no pointers by changing
185 // the type of the overflow field to uintptr in this case.
186 // See comment on hmap.overflow in ../../../../runtime/hashmap.go.
187 otyp := Ptrto(bucket)
188 if !haspointers(t.Type) && !haspointers(t.Down) && t.Type.Width <= MAXKEYSIZE && t.Down.Width <= MAXVALSIZE {
189 otyp = Types[TUINTPTR]
190 }
191 ovf := makefield("overflow", otyp)
192 field = append(field, ovf)
Russ Cox8c195bd2015-02-13 14:40:36 -0500193
194 // link up fields
Marvin Stenger9ac0fff2015-09-08 03:51:30 +0200195 bucket.Noalg = true
Russ Cox8c195bd2015-02-13 14:40:36 -0500196 bucket.Local = t.Local
197 bucket.Type = field[0]
Russ Cox382b44e2015-02-23 16:07:24 -0500198 for n := int32(0); n < int32(len(field)-1); n++ {
Russ Cox8c195bd2015-02-13 14:40:36 -0500199 field[n].Down = field[n+1]
200 }
201 field[len(field)-1].Down = nil
202 dowidth(bucket)
203
Russ Coxc5dff722015-07-30 22:05:51 -0400204 // Double-check that overflow field is final memory in struct,
205 // with no padding at end. See comment above.
206 if ovf.Width != bucket.Width-int64(Widthptr) {
207 Yyerror("bad math in mapbucket for %v", t)
Russ Cox8c195bd2015-02-13 14:40:36 -0500208 }
209
210 t.Bucket = bucket
211
212 bucket.Map = t
213 return bucket
214}
215
216// Builds a type representing a Hmap structure for the given map type.
217// Make sure this stays in sync with ../../runtime/hashmap.go!
218func hmap(t *Type) *Type {
Russ Cox8c195bd2015-02-13 14:40:36 -0500219 if t.Hmap != nil {
220 return t.Hmap
221 }
222
Russ Cox382b44e2015-02-23 16:07:24 -0500223 bucket := mapbucket(t)
224 var field [8]*Type
Russ Cox8c195bd2015-02-13 14:40:36 -0500225 field[0] = makefield("count", Types[TINT])
226 field[1] = makefield("flags", Types[TUINT8])
227 field[2] = makefield("B", Types[TUINT8])
228 field[3] = makefield("hash0", Types[TUINT32])
229 field[4] = makefield("buckets", Ptrto(bucket))
230 field[5] = makefield("oldbuckets", Ptrto(bucket))
231 field[6] = makefield("nevacuate", Types[TUINTPTR])
232 field[7] = makefield("overflow", Types[TUNSAFEPTR])
233
Russ Cox382b44e2015-02-23 16:07:24 -0500234 h := typ(TSTRUCT)
Marvin Stenger9ac0fff2015-09-08 03:51:30 +0200235 h.Noalg = true
Russ Cox8c195bd2015-02-13 14:40:36 -0500236 h.Local = t.Local
237 h.Type = field[0]
Russ Cox382b44e2015-02-23 16:07:24 -0500238 for n := int32(0); n < int32(len(field)-1); n++ {
Russ Cox8c195bd2015-02-13 14:40:36 -0500239 field[n].Down = field[n+1]
240 }
241 field[len(field)-1].Down = nil
242 dowidth(h)
243 t.Hmap = h
244 h.Map = t
245 return h
246}
247
248func hiter(t *Type) *Type {
Russ Cox8c195bd2015-02-13 14:40:36 -0500249 if t.Hiter != nil {
250 return t.Hiter
251 }
252
253 // build a struct:
254 // hash_iter {
255 // key *Key
256 // val *Value
257 // t *MapType
258 // h *Hmap
259 // buckets *Bucket
260 // bptr *Bucket
261 // overflow0 unsafe.Pointer
262 // overflow1 unsafe.Pointer
263 // startBucket uintptr
264 // stuff uintptr
265 // bucket uintptr
266 // checkBucket uintptr
267 // }
Keith Randallcd5b1442015-03-11 12:58:47 -0700268 // must match ../../runtime/hashmap.go:hash_iter.
Russ Cox382b44e2015-02-23 16:07:24 -0500269 var field [12]*Type
Russ Cox8c195bd2015-02-13 14:40:36 -0500270 field[0] = makefield("key", Ptrto(t.Down))
271
272 field[1] = makefield("val", Ptrto(t.Type))
273 field[2] = makefield("t", Ptrto(Types[TUINT8]))
274 field[3] = makefield("h", Ptrto(hmap(t)))
275 field[4] = makefield("buckets", Ptrto(mapbucket(t)))
276 field[5] = makefield("bptr", Ptrto(mapbucket(t)))
277 field[6] = makefield("overflow0", Types[TUNSAFEPTR])
278 field[7] = makefield("overflow1", Types[TUNSAFEPTR])
279 field[8] = makefield("startBucket", Types[TUINTPTR])
280 field[9] = makefield("stuff", Types[TUINTPTR]) // offset+wrapped+B+I
281 field[10] = makefield("bucket", Types[TUINTPTR])
282 field[11] = makefield("checkBucket", Types[TUINTPTR])
283
284 // build iterator struct holding the above fields
Russ Cox382b44e2015-02-23 16:07:24 -0500285 i := typ(TSTRUCT)
Russ Cox8c195bd2015-02-13 14:40:36 -0500286
Marvin Stenger9ac0fff2015-09-08 03:51:30 +0200287 i.Noalg = true
Russ Cox8c195bd2015-02-13 14:40:36 -0500288 i.Type = field[0]
Russ Cox382b44e2015-02-23 16:07:24 -0500289 for n := int32(0); n < int32(len(field)-1); n++ {
Russ Cox8c195bd2015-02-13 14:40:36 -0500290 field[n].Down = field[n+1]
291 }
292 field[len(field)-1].Down = nil
293 dowidth(i)
294 if i.Width != int64(12*Widthptr) {
295 Yyerror("hash_iter size not correct %d %d", i.Width, 12*Widthptr)
296 }
297 t.Hiter = i
298 i.Map = t
299 return i
300}
301
302/*
303 * f is method type, with receiver.
304 * return function type, receiver as first argument (or not).
305 */
306func methodfunc(f *Type, receiver *Type) *Type {
Russ Cox175929b2015-03-02 14:22:05 -0500307 var in *NodeList
Russ Cox8c195bd2015-02-13 14:40:36 -0500308 if receiver != nil {
Russ Cox382b44e2015-02-23 16:07:24 -0500309 d := Nod(ODCLFIELD, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500310 d.Type = receiver
311 in = list(in, d)
312 }
313
Russ Cox382b44e2015-02-23 16:07:24 -0500314 var d *Node
315 for t := getinargx(f).Type; t != nil; t = t.Down {
Russ Cox8c195bd2015-02-13 14:40:36 -0500316 d = Nod(ODCLFIELD, nil, nil)
317 d.Type = t.Type
318 d.Isddd = t.Isddd
319 in = list(in, d)
320 }
321
Russ Cox175929b2015-03-02 14:22:05 -0500322 var out *NodeList
Russ Cox382b44e2015-02-23 16:07:24 -0500323 for t := getoutargx(f).Type; t != nil; t = t.Down {
Russ Cox8c195bd2015-02-13 14:40:36 -0500324 d = Nod(ODCLFIELD, nil, nil)
325 d.Type = t.Type
326 out = list(out, d)
327 }
328
Russ Cox382b44e2015-02-23 16:07:24 -0500329 t := functype(nil, in, out)
Russ Cox8c195bd2015-02-13 14:40:36 -0500330 if f.Nname != nil {
331 // Link to name of original method function.
332 t.Nname = f.Nname
333 }
334
335 return t
336}
337
338/*
339 * return methods of non-interface type t, sorted by name.
340 * generates stub functions as needed.
341 */
342func methods(t *Type) *Sig {
Russ Cox8c195bd2015-02-13 14:40:36 -0500343 // method type
Russ Cox382b44e2015-02-23 16:07:24 -0500344 mt := methtype(t, 0)
Russ Cox8c195bd2015-02-13 14:40:36 -0500345
346 if mt == nil {
347 return nil
348 }
349 expandmeth(mt)
350
351 // type stored in interface word
Russ Cox382b44e2015-02-23 16:07:24 -0500352 it := t
Russ Cox8c195bd2015-02-13 14:40:36 -0500353
Russ Coxdc7b54b2015-02-17 22:13:49 -0500354 if !isdirectiface(it) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500355 it = Ptrto(t)
356 }
357
358 // make list of methods for t,
359 // generating code if necessary.
Russ Cox175929b2015-03-02 14:22:05 -0500360 var a *Sig
Russ Cox8c195bd2015-02-13 14:40:36 -0500361
Russ Cox382b44e2015-02-23 16:07:24 -0500362 var this *Type
363 var b *Sig
364 var method *Sym
365 for f := mt.Xmethod; f != nil; f = f.Down {
Russ Cox8c195bd2015-02-13 14:40:36 -0500366 if f.Etype != TFIELD {
Håvard Haugen3c9fa382015-08-30 23:10:03 +0200367 Fatalf("methods: not field %v", f)
Russ Cox8c195bd2015-02-13 14:40:36 -0500368 }
369 if f.Type.Etype != TFUNC || f.Type.Thistuple == 0 {
Håvard Haugen3c9fa382015-08-30 23:10:03 +0200370 Fatalf("non-method on %v method %v %v\n", mt, f.Sym, f)
Russ Cox8c195bd2015-02-13 14:40:36 -0500371 }
Russ Coxdc7b54b2015-02-17 22:13:49 -0500372 if getthisx(f.Type).Type == nil {
Håvard Haugen3c9fa382015-08-30 23:10:03 +0200373 Fatalf("receiver with no type on %v method %v %v\n", mt, f.Sym, f)
Russ Cox8c195bd2015-02-13 14:40:36 -0500374 }
Russ Coxdc7b54b2015-02-17 22:13:49 -0500375 if f.Nointerface {
Russ Cox8c195bd2015-02-13 14:40:36 -0500376 continue
377 }
378
379 method = f.Sym
380 if method == nil {
381 continue
382 }
383
384 // get receiver type for this particular method.
385 // if pointer receiver but non-pointer t and
386 // this is not an embedded pointer inside a struct,
387 // method does not apply.
388 this = getthisx(f.Type).Type.Type
389
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +0000390 if Isptr[this.Etype] && this.Type == t {
Russ Cox8c195bd2015-02-13 14:40:36 -0500391 continue
392 }
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +0000393 if Isptr[this.Etype] && !Isptr[t.Etype] && f.Embedded != 2 && !isifacemethod(f.Type) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500394 continue
395 }
396
397 b = new(Sig)
398 b.link = a
399 a = b
400
401 a.name = method.Name
402 if !exportname(method.Name) {
403 if method.Pkg == nil {
Håvard Haugen3c9fa382015-08-30 23:10:03 +0200404 Fatalf("methods: missing package")
Russ Cox8c195bd2015-02-13 14:40:36 -0500405 }
406 a.pkg = method.Pkg
407 }
408
409 a.isym = methodsym(method, it, 1)
410 a.tsym = methodsym(method, t, 0)
411 a.type_ = methodfunc(f.Type, t)
412 a.mtype = methodfunc(f.Type, nil)
413
Russ Coxdc7b54b2015-02-17 22:13:49 -0500414 if a.isym.Flags&SymSiggen == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -0500415 a.isym.Flags |= SymSiggen
416 if !Eqtype(this, it) || this.Width < Types[Tptr].Width {
417 compiling_wrappers = 1
418 genwrapper(it, f, a.isym, 1)
419 compiling_wrappers = 0
420 }
421 }
422
Russ Coxdc7b54b2015-02-17 22:13:49 -0500423 if a.tsym.Flags&SymSiggen == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -0500424 a.tsym.Flags |= SymSiggen
425 if !Eqtype(this, t) {
426 compiling_wrappers = 1
427 genwrapper(t, f, a.tsym, 0)
428 compiling_wrappers = 0
429 }
430 }
431 }
432
433 return lsort(a, sigcmp)
434}
435
436/*
437 * return methods of interface type t, sorted by name.
438 */
439func imethods(t *Type) *Sig {
440 var a *Sig
Russ Cox8c195bd2015-02-13 14:40:36 -0500441 var method *Sym
442 var isym *Sym
443
Russ Cox175929b2015-03-02 14:22:05 -0500444 var all *Sig
445 var last *Sig
Russ Cox382b44e2015-02-23 16:07:24 -0500446 for f := t.Type; f != nil; f = f.Down {
Russ Cox8c195bd2015-02-13 14:40:36 -0500447 if f.Etype != TFIELD {
Håvard Haugen3c9fa382015-08-30 23:10:03 +0200448 Fatalf("imethods: not field")
Russ Cox8c195bd2015-02-13 14:40:36 -0500449 }
450 if f.Type.Etype != TFUNC || f.Sym == nil {
451 continue
452 }
453 method = f.Sym
454 a = new(Sig)
455 a.name = method.Name
456 if !exportname(method.Name) {
457 if method.Pkg == nil {
Håvard Haugen3c9fa382015-08-30 23:10:03 +0200458 Fatalf("imethods: missing package")
Russ Cox8c195bd2015-02-13 14:40:36 -0500459 }
460 a.pkg = method.Pkg
461 }
462
463 a.mtype = f.Type
464 a.offset = 0
465 a.type_ = methodfunc(f.Type, nil)
466
467 if last != nil && sigcmp(last, a) >= 0 {
Håvard Haugen3c9fa382015-08-30 23:10:03 +0200468 Fatalf("sigcmp vs sortinter %s %s", last.name, a.name)
Russ Cox8c195bd2015-02-13 14:40:36 -0500469 }
470 if last == nil {
471 all = a
472 } else {
473 last.link = a
474 }
475 last = a
476
477 // Compiler can only refer to wrappers for non-blank methods.
478 if isblanksym(method) {
479 continue
480 }
481
482 // NOTE(rsc): Perhaps an oversight that
483 // IfaceType.Method is not in the reflect data.
484 // Generate the method body, so that compiled
485 // code can refer to it.
486 isym = methodsym(method, t, 0)
487
Russ Coxdc7b54b2015-02-17 22:13:49 -0500488 if isym.Flags&SymSiggen == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -0500489 isym.Flags |= SymSiggen
490 genwrapper(t, f, isym, 0)
491 }
492 }
493
494 return all
495}
496
497var dimportpath_gopkg *Pkg
498
499func dimportpath(p *Pkg) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500500 if p.Pathsym != nil {
501 return
502 }
503
Michael Hudson-Doyle0de359d2015-03-19 23:05:34 +1300504 // If we are compiling the runtime package, there are two runtime packages around
505 // -- localpkg and Runtimepkg. We don't want to produce import path symbols for
506 // both of them, so just produce one for localpkg.
507 if myimportpath == "runtime" && p == Runtimepkg {
508 return
509 }
510
Russ Cox8c195bd2015-02-13 14:40:36 -0500511 if dimportpath_gopkg == nil {
Russ Coxbed1f902015-03-02 16:03:26 -0500512 dimportpath_gopkg = mkpkg("go")
Russ Cox8c195bd2015-02-13 14:40:36 -0500513 dimportpath_gopkg.Name = "go"
514 }
515
Michael Hudson-Doyleb92a0a82015-04-05 14:48:42 +1200516 nam := "importpath." + p.Prefix + "."
Russ Cox8c195bd2015-02-13 14:40:36 -0500517
Russ Cox382b44e2015-02-23 16:07:24 -0500518 n := Nod(ONAME, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500519 n.Sym = Pkglookup(nam, dimportpath_gopkg)
520
521 n.Class = PEXTERN
522 n.Xoffset = 0
523 p.Pathsym = n.Sym
524
Michael Hudson-Doyleb92a0a82015-04-05 14:48:42 +1200525 if p == localpkg {
526 // Note: myimportpath != "", or else dgopkgpath won't call dimportpath.
527 gdatastring(n, myimportpath)
528 } else {
529 gdatastring(n, p.Path)
530 }
Russ Cox8c195bd2015-02-13 14:40:36 -0500531 ggloblsym(n.Sym, int32(Types[TSTRING].Width), obj.DUPOK|obj.RODATA)
532}
533
534func dgopkgpath(s *Sym, ot int, pkg *Pkg) int {
535 if pkg == nil {
536 return dgostringptr(s, ot, "")
537 }
538
Michael Hudson-Doyle0de359d2015-03-19 23:05:34 +1300539 if pkg == localpkg && myimportpath == "" {
540 // If we don't know the full path of the package being compiled (i.e. -p
541 // was not passed on the compiler command line), emit reference to
542 // go.importpath.""., which 6l will rewrite using the correct import path.
543 // Every package that imports this one directly defines the symbol.
Russ Cox8c195bd2015-02-13 14:40:36 -0500544 var ns *Sym
545
546 if ns == nil {
Russ Coxbed1f902015-03-02 16:03:26 -0500547 ns = Pkglookup("importpath.\"\".", mkpkg("go"))
Russ Cox8c195bd2015-02-13 14:40:36 -0500548 }
549 return dsymptr(s, ot, ns, 0)
550 }
551
552 dimportpath(pkg)
553 return dsymptr(s, ot, pkg.Pathsym, 0)
554}
555
556/*
557 * uncommonType
558 * ../../runtime/type.go:/uncommonType
559 */
560func dextratype(sym *Sym, off int, t *Type, ptroff int) int {
Russ Cox382b44e2015-02-23 16:07:24 -0500561 m := methods(t)
Russ Cox8c195bd2015-02-13 14:40:36 -0500562 if t.Sym == nil && m == nil {
563 return off
564 }
565
566 // fill in *extraType pointer in header
567 off = int(Rnd(int64(off), int64(Widthptr)))
568
569 dsymptr(sym, ptroff, sym, off)
570
Russ Cox382b44e2015-02-23 16:07:24 -0500571 n := 0
572 for a := m; a != nil; a = a.link {
Russ Cox8c195bd2015-02-13 14:40:36 -0500573 dtypesym(a.type_)
574 n++
575 }
576
Russ Cox382b44e2015-02-23 16:07:24 -0500577 ot := off
578 s := sym
Russ Cox8c195bd2015-02-13 14:40:36 -0500579 if t.Sym != nil {
580 ot = dgostringptr(s, ot, t.Sym.Name)
581 if t != Types[t.Etype] && t != errortype {
582 ot = dgopkgpath(s, ot, t.Sym.Pkg)
583 } else {
584 ot = dgostringptr(s, ot, "")
585 }
586 } else {
587 ot = dgostringptr(s, ot, "")
588 ot = dgostringptr(s, ot, "")
589 }
590
591 // slice header
592 ot = dsymptr(s, ot, s, ot+Widthptr+2*Widthint)
593
594 ot = duintxx(s, ot, uint64(n), Widthint)
595 ot = duintxx(s, ot, uint64(n), Widthint)
596
597 // methods
Russ Cox382b44e2015-02-23 16:07:24 -0500598 for a := m; a != nil; a = a.link {
Russ Cox8c195bd2015-02-13 14:40:36 -0500599 // method
600 // ../../runtime/type.go:/method
601 ot = dgostringptr(s, ot, a.name)
602
603 ot = dgopkgpath(s, ot, a.pkg)
604 ot = dsymptr(s, ot, dtypesym(a.mtype), 0)
605 ot = dsymptr(s, ot, dtypesym(a.type_), 0)
606 if a.isym != nil {
607 ot = dsymptr(s, ot, a.isym, 0)
608 } else {
609 ot = duintptr(s, ot, 0)
610 }
611 if a.tsym != nil {
612 ot = dsymptr(s, ot, a.tsym, 0)
613 } else {
614 ot = duintptr(s, ot, 0)
615 }
616 }
617
618 return ot
619}
620
621var kinds = []int{
622 TINT: obj.KindInt,
623 TUINT: obj.KindUint,
624 TINT8: obj.KindInt8,
625 TUINT8: obj.KindUint8,
626 TINT16: obj.KindInt16,
627 TUINT16: obj.KindUint16,
628 TINT32: obj.KindInt32,
629 TUINT32: obj.KindUint32,
630 TINT64: obj.KindInt64,
631 TUINT64: obj.KindUint64,
632 TUINTPTR: obj.KindUintptr,
633 TFLOAT32: obj.KindFloat32,
634 TFLOAT64: obj.KindFloat64,
635 TBOOL: obj.KindBool,
636 TSTRING: obj.KindString,
637 TPTR32: obj.KindPtr,
638 TPTR64: obj.KindPtr,
639 TSTRUCT: obj.KindStruct,
640 TINTER: obj.KindInterface,
641 TCHAN: obj.KindChan,
642 TMAP: obj.KindMap,
643 TARRAY: obj.KindArray,
644 TFUNC: obj.KindFunc,
645 TCOMPLEX64: obj.KindComplex64,
646 TCOMPLEX128: obj.KindComplex128,
647 TUNSAFEPTR: obj.KindUnsafePointer,
648}
649
650func haspointers(t *Type) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -0500651 if t.Haspointers != 0 {
652 return t.Haspointers-1 != 0
653 }
654
Russ Cox382b44e2015-02-23 16:07:24 -0500655 var ret bool
Russ Cox8c195bd2015-02-13 14:40:36 -0500656 switch t.Etype {
657 case TINT,
658 TUINT,
659 TINT8,
660 TUINT8,
661 TINT16,
662 TUINT16,
663 TINT32,
664 TUINT32,
665 TINT64,
666 TUINT64,
667 TUINTPTR,
668 TFLOAT32,
669 TFLOAT64,
670 TCOMPLEX64,
671 TCOMPLEX128,
672 TBOOL:
Russ Coxdc7b54b2015-02-17 22:13:49 -0500673 ret = false
Russ Cox8c195bd2015-02-13 14:40:36 -0500674
675 case TARRAY:
676 if t.Bound < 0 { // slice
Russ Coxdc7b54b2015-02-17 22:13:49 -0500677 ret = true
Russ Cox8c195bd2015-02-13 14:40:36 -0500678 break
679 }
680
681 if t.Bound == 0 { // empty array
Russ Coxdc7b54b2015-02-17 22:13:49 -0500682 ret = false
Russ Cox8c195bd2015-02-13 14:40:36 -0500683 break
684 }
685
Russ Coxdc7b54b2015-02-17 22:13:49 -0500686 ret = haspointers(t.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -0500687
688 case TSTRUCT:
Russ Coxdc7b54b2015-02-17 22:13:49 -0500689 ret = false
Russ Cox382b44e2015-02-23 16:07:24 -0500690 for t1 := t.Type; t1 != nil; t1 = t1.Down {
Russ Cox8c195bd2015-02-13 14:40:36 -0500691 if haspointers(t1.Type) {
Russ Coxdc7b54b2015-02-17 22:13:49 -0500692 ret = true
Russ Cox8c195bd2015-02-13 14:40:36 -0500693 break
694 }
695 }
696
697 case TSTRING,
698 TPTR32,
699 TPTR64,
700 TUNSAFEPTR,
701 TINTER,
702 TCHAN,
703 TMAP,
704 TFUNC:
705 fallthrough
706 default:
Russ Coxdc7b54b2015-02-17 22:13:49 -0500707 ret = true
Austin Clements98a9d362015-05-04 14:37:45 -0400708
709 case TFIELD:
Håvard Haugen3c9fa382015-08-30 23:10:03 +0200710 Fatalf("haspointers: unexpected type, %v", t)
Russ Cox8c195bd2015-02-13 14:40:36 -0500711 }
712
Michael Hudson-Doyleac1cdd12015-04-22 12:41:14 +1200713 t.Haspointers = 1 + uint8(obj.Bool2int(ret))
Russ Coxdc7b54b2015-02-17 22:13:49 -0500714 return ret
Russ Cox8c195bd2015-02-13 14:40:36 -0500715}
716
Russ Coxceefebd2015-05-04 21:43:30 -0400717// typeptrdata returns the length in bytes of the prefix of t
Austin Clements98a9d362015-05-04 14:37:45 -0400718// containing pointer data. Anything after this offset is scalar data.
Russ Cox54af9a32015-05-04 22:53:54 -0400719func typeptrdata(t *Type) int64 {
Austin Clements98a9d362015-05-04 14:37:45 -0400720 if !haspointers(t) {
721 return 0
722 }
723
724 switch t.Etype {
725 case TPTR32,
726 TPTR64,
727 TUNSAFEPTR,
728 TFUNC,
729 TCHAN,
730 TMAP:
Russ Cox54af9a32015-05-04 22:53:54 -0400731 return int64(Widthptr)
Austin Clements98a9d362015-05-04 14:37:45 -0400732
733 case TSTRING:
734 // struct { byte *str; intgo len; }
Russ Cox54af9a32015-05-04 22:53:54 -0400735 return int64(Widthptr)
Austin Clements98a9d362015-05-04 14:37:45 -0400736
737 case TINTER:
738 // struct { Itab *tab; void *data; } or
739 // struct { Type *type; void *data; }
Russ Cox54af9a32015-05-04 22:53:54 -0400740 return 2 * int64(Widthptr)
Austin Clements98a9d362015-05-04 14:37:45 -0400741
742 case TARRAY:
743 if Isslice(t) {
744 // struct { byte *array; uintgo len; uintgo cap; }
Russ Cox54af9a32015-05-04 22:53:54 -0400745 return int64(Widthptr)
Austin Clements98a9d362015-05-04 14:37:45 -0400746 }
747 // haspointers already eliminated t.Bound == 0.
Russ Cox54af9a32015-05-04 22:53:54 -0400748 return (t.Bound-1)*t.Type.Width + typeptrdata(t.Type)
Austin Clements98a9d362015-05-04 14:37:45 -0400749
750 case TSTRUCT:
751 // Find the last field that has pointers.
752 var lastPtrField *Type
753 for t1 := t.Type; t1 != nil; t1 = t1.Down {
754 if haspointers(t1.Type) {
755 lastPtrField = t1
756 }
757 }
Russ Cox54af9a32015-05-04 22:53:54 -0400758 return lastPtrField.Width + typeptrdata(lastPtrField.Type)
Austin Clements98a9d362015-05-04 14:37:45 -0400759
760 default:
Håvard Haugen3c9fa382015-08-30 23:10:03 +0200761 Fatalf("typeptrdata: unexpected type, %v", t)
Austin Clements98a9d362015-05-04 14:37:45 -0400762 return 0
763 }
764}
765
Russ Cox8c195bd2015-02-13 14:40:36 -0500766/*
767 * commonType
768 * ../../runtime/type.go:/commonType
769 */
770
771var dcommontype_algarray *Sym
772
773func dcommontype(s *Sym, ot int, t *Type) int {
Russ Cox8c195bd2015-02-13 14:40:36 -0500774 if ot != 0 {
Håvard Haugen3c9fa382015-08-30 23:10:03 +0200775 Fatalf("dcommontype %d", ot)
Russ Cox8c195bd2015-02-13 14:40:36 -0500776 }
777
Russ Cox382b44e2015-02-23 16:07:24 -0500778 sizeofAlg := 2 * Widthptr
Russ Cox8c195bd2015-02-13 14:40:36 -0500779 if dcommontype_algarray == nil {
780 dcommontype_algarray = Pkglookup("algarray", Runtimepkg)
781 }
782 dowidth(t)
Russ Cox382b44e2015-02-23 16:07:24 -0500783 alg := algtype(t)
Russ Cox175929b2015-03-02 14:22:05 -0500784 var algsym *Sym
Russ Cox8c195bd2015-02-13 14:40:36 -0500785 if alg < 0 || alg == AMEM {
786 algsym = dalgsym(t)
787 }
788
Russ Cox382b44e2015-02-23 16:07:24 -0500789 var sptr *Sym
Russ Cox7feb4242015-07-15 00:01:54 -0400790 tptr := Ptrto(t)
791 if !Isptr[t.Etype] && (t.Sym != nil || methods(tptr) != nil) {
792 sptr = dtypesym(tptr)
Russ Cox8c195bd2015-02-13 14:40:36 -0500793 } else {
Russ Cox7feb4242015-07-15 00:01:54 -0400794 sptr = weaktypesym(tptr)
Russ Cox8c195bd2015-02-13 14:40:36 -0500795 }
796
Russ Cox512f75e2015-05-08 01:43:18 -0400797 gcsym, useGCProg, ptrdata := dgcsym(t)
798
Russ Cox8c195bd2015-02-13 14:40:36 -0500799 // ../../pkg/reflect/type.go:/^type.commonType
800 // actual type structure
801 // type commonType struct {
802 // size uintptr
Austin Clements98a9d362015-05-04 14:37:45 -0400803 // ptrsize uintptr
Russ Cox8c195bd2015-02-13 14:40:36 -0500804 // hash uint32
805 // _ uint8
806 // align uint8
807 // fieldAlign uint8
808 // kind uint8
809 // alg unsafe.Pointer
Russ Cox512f75e2015-05-08 01:43:18 -0400810 // gcdata unsafe.Pointer
Russ Cox8c195bd2015-02-13 14:40:36 -0500811 // string *string
812 // *extraType
813 // ptrToThis *Type
Russ Cox8c195bd2015-02-13 14:40:36 -0500814 // }
815 ot = duintptr(s, ot, uint64(t.Width))
Russ Cox512f75e2015-05-08 01:43:18 -0400816 ot = duintptr(s, ot, uint64(ptrdata))
Russ Cox8c195bd2015-02-13 14:40:36 -0500817
818 ot = duint32(s, ot, typehash(t))
819 ot = duint8(s, ot, 0) // unused
820
821 // runtime (and common sense) expects alignment to be a power of two.
Russ Cox382b44e2015-02-23 16:07:24 -0500822 i := int(t.Align)
Russ Cox8c195bd2015-02-13 14:40:36 -0500823
824 if i == 0 {
825 i = 1
826 }
827 if i&(i-1) != 0 {
Håvard Haugen3c9fa382015-08-30 23:10:03 +0200828 Fatalf("invalid alignment %d for %v", t.Align, t)
Russ Cox8c195bd2015-02-13 14:40:36 -0500829 }
830 ot = duint8(s, ot, t.Align) // align
831 ot = duint8(s, ot, t.Align) // fieldAlign
832
Russ Cox8c195bd2015-02-13 14:40:36 -0500833 i = kinds[t.Etype]
834 if t.Etype == TARRAY && t.Bound < 0 {
835 i = obj.KindSlice
836 }
837 if !haspointers(t) {
838 i |= obj.KindNoPointers
839 }
Russ Coxdc7b54b2015-02-17 22:13:49 -0500840 if isdirectiface(t) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500841 i |= obj.KindDirectIface
842 }
Russ Cox512f75e2015-05-08 01:43:18 -0400843 if useGCProg {
Russ Cox8c195bd2015-02-13 14:40:36 -0500844 i |= obj.KindGCProg
845 }
846 ot = duint8(s, ot, uint8(i)) // kind
847 if algsym == nil {
848 ot = dsymptr(s, ot, dcommontype_algarray, alg*sizeofAlg)
849 } else {
850 ot = dsymptr(s, ot, algsym, 0)
851 }
Russ Cox512f75e2015-05-08 01:43:18 -0400852 ot = dsymptr(s, ot, gcsym, 0)
Russ Cox8c195bd2015-02-13 14:40:36 -0500853
Russ Coxc8198342015-03-12 18:45:30 -0400854 p := Tconv(t, obj.FmtLeft|obj.FmtUnsigned)
Russ Cox8c195bd2015-02-13 14:40:36 -0500855
856 //print("dcommontype: %s\n", p);
857 ot = dgostringptr(s, ot, p) // string
858
859 // skip pointer to extraType,
860 // which follows the rest of this type structure.
861 // caller will fill in if needed.
862 // otherwise linker will assume 0.
863 ot += Widthptr
864
865 ot = dsymptr(s, ot, sptr, 0) // ptrto type
Russ Cox8c195bd2015-02-13 14:40:36 -0500866 return ot
867}
868
869func typesym(t *Type) *Sym {
Russ Coxc8198342015-03-12 18:45:30 -0400870 return Pkglookup(Tconv(t, obj.FmtLeft), typepkg)
Russ Cox8c195bd2015-02-13 14:40:36 -0500871}
872
873func tracksym(t *Type) *Sym {
Russ Coxc8198342015-03-12 18:45:30 -0400874 return Pkglookup(Tconv(t.Outer, obj.FmtLeft)+"."+t.Sym.Name, trackpkg)
Russ Cox8c195bd2015-02-13 14:40:36 -0500875}
876
877func typelinksym(t *Type) *Sym {
Russ Cox8c195bd2015-02-13 14:40:36 -0500878 // %-uT is what the generated Type's string field says.
879 // It uses (ambiguous) package names instead of import paths.
880 // %-T is the complete, unambiguous type name.
881 // We want the types to end up sorted by string field,
882 // so use that first in the name, and then add :%-T to
Dave Daye1c1fa22014-12-23 15:19:30 +1100883 // disambiguate. We use a tab character as the separator to
884 // ensure the types appear sorted by their string field. The
885 // names are a little long but they are discarded by the linker
886 // and do not end up in the symbol table of the final binary.
887 p := Tconv(t, obj.FmtLeft|obj.FmtUnsigned) + "\t" + Tconv(t, obj.FmtLeft)
Russ Cox8c195bd2015-02-13 14:40:36 -0500888
Russ Cox382b44e2015-02-23 16:07:24 -0500889 s := Pkglookup(p, typelinkpkg)
Russ Cox8c195bd2015-02-13 14:40:36 -0500890
891 //print("typelinksym: %s -> %+S\n", p, s);
892
893 return s
894}
895
896func typesymprefix(prefix string, t *Type) *Sym {
Russ Coxc8198342015-03-12 18:45:30 -0400897 p := prefix + "." + Tconv(t, obj.FmtLeft)
Russ Cox382b44e2015-02-23 16:07:24 -0500898 s := Pkglookup(p, typepkg)
Russ Cox8c195bd2015-02-13 14:40:36 -0500899
900 //print("algsym: %s -> %+S\n", p, s);
901
902 return s
903}
904
905func typenamesym(t *Type) *Sym {
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +0000906 if t == nil || (Isptr[t.Etype] && t.Type == nil) || isideal(t) {
Håvard Haugen3c9fa382015-08-30 23:10:03 +0200907 Fatalf("typename %v", t)
Russ Cox8c195bd2015-02-13 14:40:36 -0500908 }
Russ Cox382b44e2015-02-23 16:07:24 -0500909 s := typesym(t)
Russ Cox8c195bd2015-02-13 14:40:36 -0500910 if s.Def == nil {
Russ Cox382b44e2015-02-23 16:07:24 -0500911 n := Nod(ONAME, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500912 n.Sym = s
913 n.Type = Types[TUINT8]
Josh Bleecher Snyder75883ba2015-04-02 19:58:37 -0700914 n.Addable = true
Russ Cox8c195bd2015-02-13 14:40:36 -0500915 n.Ullman = 1
916 n.Class = PEXTERN
917 n.Xoffset = 0
918 n.Typecheck = 1
919 s.Def = n
920
921 signatlist = list(signatlist, typenod(t))
922 }
923
924 return s.Def.Sym
925}
926
927func typename(t *Type) *Node {
Russ Cox382b44e2015-02-23 16:07:24 -0500928 s := typenamesym(t)
929 n := Nod(OADDR, s.Def, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500930 n.Type = Ptrto(s.Def.Type)
Josh Bleecher Snyder75883ba2015-04-02 19:58:37 -0700931 n.Addable = true
Russ Cox8c195bd2015-02-13 14:40:36 -0500932 n.Ullman = 2
933 n.Typecheck = 1
934 return n
935}
936
937func weaktypesym(t *Type) *Sym {
Russ Coxc8198342015-03-12 18:45:30 -0400938 p := Tconv(t, obj.FmtLeft)
Russ Cox382b44e2015-02-23 16:07:24 -0500939 s := Pkglookup(p, weaktypepkg)
Russ Cox8c195bd2015-02-13 14:40:36 -0500940
941 //print("weaktypesym: %s -> %+S\n", p, s);
942
943 return s
944}
945
Keith Randall00c638d2015-06-08 08:42:28 -0700946// isreflexive reports whether t has a reflexive equality operator.
947// That is, if x==x for all x of type t.
Russ Coxdc7b54b2015-02-17 22:13:49 -0500948func isreflexive(t *Type) bool {
Russ Cox8c195bd2015-02-13 14:40:36 -0500949 switch t.Etype {
950 case TBOOL,
951 TINT,
952 TUINT,
953 TINT8,
954 TUINT8,
955 TINT16,
956 TUINT16,
957 TINT32,
958 TUINT32,
959 TINT64,
960 TUINT64,
961 TUINTPTR,
962 TPTR32,
963 TPTR64,
964 TUNSAFEPTR,
965 TSTRING,
966 TCHAN:
Russ Coxdc7b54b2015-02-17 22:13:49 -0500967 return true
Russ Cox8c195bd2015-02-13 14:40:36 -0500968
969 case TFLOAT32,
970 TFLOAT64,
971 TCOMPLEX64,
972 TCOMPLEX128,
973 TINTER:
Russ Coxdc7b54b2015-02-17 22:13:49 -0500974 return false
Russ Cox8c195bd2015-02-13 14:40:36 -0500975
976 case TARRAY:
Russ Coxdc7b54b2015-02-17 22:13:49 -0500977 if Isslice(t) {
Håvard Haugen3c9fa382015-08-30 23:10:03 +0200978 Fatalf("slice can't be a map key: %v", t)
Russ Cox8c195bd2015-02-13 14:40:36 -0500979 }
980 return isreflexive(t.Type)
981
982 case TSTRUCT:
Russ Cox382b44e2015-02-23 16:07:24 -0500983 for t1 := t.Type; t1 != nil; t1 = t1.Down {
Russ Coxdc7b54b2015-02-17 22:13:49 -0500984 if !isreflexive(t1.Type) {
985 return false
Russ Cox8c195bd2015-02-13 14:40:36 -0500986 }
987 }
Russ Coxdc7b54b2015-02-17 22:13:49 -0500988 return true
Russ Cox8c195bd2015-02-13 14:40:36 -0500989
990 default:
Håvard Haugen3c9fa382015-08-30 23:10:03 +0200991 Fatalf("bad type for map key: %v", t)
Russ Coxdc7b54b2015-02-17 22:13:49 -0500992 return false
Russ Cox8c195bd2015-02-13 14:40:36 -0500993 }
994}
995
Keith Randall00c638d2015-06-08 08:42:28 -0700996// needkeyupdate reports whether map updates with t as a key
997// need the key to be updated.
998func needkeyupdate(t *Type) bool {
999 switch t.Etype {
1000 case TBOOL,
1001 TINT,
1002 TUINT,
1003 TINT8,
1004 TUINT8,
1005 TINT16,
1006 TUINT16,
1007 TINT32,
1008 TUINT32,
1009 TINT64,
1010 TUINT64,
1011 TUINTPTR,
1012 TPTR32,
1013 TPTR64,
1014 TUNSAFEPTR,
1015 TCHAN:
1016 return false
1017
1018 case TFLOAT32, // floats can be +0/-0
1019 TFLOAT64,
1020 TCOMPLEX64,
1021 TCOMPLEX128,
1022 TINTER,
1023 TSTRING: // strings might have smaller backing stores
1024 return true
1025
1026 case TARRAY:
1027 if Isslice(t) {
1028 Fatalf("slice can't be a map key: %v", t)
1029 }
1030 return needkeyupdate(t.Type)
1031
1032 case TSTRUCT:
1033 for t1 := t.Type; t1 != nil; t1 = t1.Down {
1034 if needkeyupdate(t1.Type) {
1035 return true
1036 }
1037 }
1038 return false
1039
1040 default:
1041 Fatalf("bad type for map key: %v", t)
1042 return true
1043 }
1044}
1045
Russ Cox8c195bd2015-02-13 14:40:36 -05001046func dtypesym(t *Type) *Sym {
Russ Cox8c195bd2015-02-13 14:40:36 -05001047 // Replace byte, rune aliases with real type.
1048 // They've been separate internally to make error messages
1049 // better, but we have to merge them in the reflect tables.
1050 if t == bytetype || t == runetype {
1051 t = Types[t.Etype]
1052 }
1053
Russ Coxdc7b54b2015-02-17 22:13:49 -05001054 if isideal(t) {
Håvard Haugen3c9fa382015-08-30 23:10:03 +02001055 Fatalf("dtypesym %v", t)
Russ Cox8c195bd2015-02-13 14:40:36 -05001056 }
1057
Russ Cox382b44e2015-02-23 16:07:24 -05001058 s := typesym(t)
Russ Cox8c195bd2015-02-13 14:40:36 -05001059 if s.Flags&SymSiggen != 0 {
1060 return s
1061 }
1062 s.Flags |= SymSiggen
1063
1064 // special case (look for runtime below):
1065 // when compiling package runtime,
1066 // emit the type structures for int, float, etc.
Russ Cox382b44e2015-02-23 16:07:24 -05001067 tbase := t
Russ Cox8c195bd2015-02-13 14:40:36 -05001068
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00001069 if Isptr[t.Etype] && t.Sym == nil && t.Type.Sym != nil {
Russ Cox8c195bd2015-02-13 14:40:36 -05001070 tbase = t.Type
1071 }
Russ Cox382b44e2015-02-23 16:07:24 -05001072 dupok := 0
Russ Cox8c195bd2015-02-13 14:40:36 -05001073 if tbase.Sym == nil {
1074 dupok = obj.DUPOK
1075 }
1076
1077 if compiling_runtime != 0 && (tbase == Types[tbase.Etype] || tbase == bytetype || tbase == runetype || tbase == errortype) { // int, float, etc
1078 goto ok
1079 }
1080
1081 // named types from other files are defined only by those files
Dave Cheneye4981812015-03-10 09:58:01 +11001082 if tbase.Sym != nil && !tbase.Local {
Russ Cox8c195bd2015-02-13 14:40:36 -05001083 return s
1084 }
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +00001085 if isforw[tbase.Etype] {
Russ Cox8c195bd2015-02-13 14:40:36 -05001086 return s
1087 }
1088
1089ok:
Russ Cox382b44e2015-02-23 16:07:24 -05001090 ot := 0
1091 xt := 0
Russ Cox8c195bd2015-02-13 14:40:36 -05001092 switch t.Etype {
1093 default:
1094 ot = dcommontype(s, ot, t)
Michael Hudson-Doyleaf784822015-08-21 15:23:57 +12001095 xt = ot - 2*Widthptr
Russ Cox8c195bd2015-02-13 14:40:36 -05001096
1097 case TARRAY:
1098 if t.Bound >= 0 {
1099 // ../../runtime/type.go:/ArrayType
Russ Cox382b44e2015-02-23 16:07:24 -05001100 s1 := dtypesym(t.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05001101
Russ Cox382b44e2015-02-23 16:07:24 -05001102 t2 := typ(TARRAY)
Russ Cox8c195bd2015-02-13 14:40:36 -05001103 t2.Type = t.Type
1104 t2.Bound = -1 // slice
Russ Cox382b44e2015-02-23 16:07:24 -05001105 s2 := dtypesym(t2)
Russ Cox8c195bd2015-02-13 14:40:36 -05001106 ot = dcommontype(s, ot, t)
Michael Hudson-Doyleaf784822015-08-21 15:23:57 +12001107 xt = ot - 2*Widthptr
Russ Cox8c195bd2015-02-13 14:40:36 -05001108 ot = dsymptr(s, ot, s1, 0)
1109 ot = dsymptr(s, ot, s2, 0)
1110 ot = duintptr(s, ot, uint64(t.Bound))
1111 } else {
1112 // ../../runtime/type.go:/SliceType
Russ Cox382b44e2015-02-23 16:07:24 -05001113 s1 := dtypesym(t.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05001114
1115 ot = dcommontype(s, ot, t)
Michael Hudson-Doyleaf784822015-08-21 15:23:57 +12001116 xt = ot - 2*Widthptr
Russ Cox8c195bd2015-02-13 14:40:36 -05001117 ot = dsymptr(s, ot, s1, 0)
1118 }
1119
1120 // ../../runtime/type.go:/ChanType
1121 case TCHAN:
Russ Cox382b44e2015-02-23 16:07:24 -05001122 s1 := dtypesym(t.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05001123
1124 ot = dcommontype(s, ot, t)
Michael Hudson-Doyleaf784822015-08-21 15:23:57 +12001125 xt = ot - 2*Widthptr
Russ Cox8c195bd2015-02-13 14:40:36 -05001126 ot = dsymptr(s, ot, s1, 0)
1127 ot = duintptr(s, ot, uint64(t.Chan))
1128
1129 case TFUNC:
Russ Coxc8198342015-03-12 18:45:30 -04001130 for t1 := getthisx(t).Type; t1 != nil; t1 = t1.Down {
Russ Cox8c195bd2015-02-13 14:40:36 -05001131 dtypesym(t1.Type)
1132 }
Dave Cheneyd3287562015-03-09 16:24:07 +11001133 isddd := false
Russ Coxc8198342015-03-12 18:45:30 -04001134 for t1 := getinargx(t).Type; t1 != nil; t1 = t1.Down {
Dave Cheneyd3287562015-03-09 16:24:07 +11001135 isddd = t1.Isddd
Russ Cox8c195bd2015-02-13 14:40:36 -05001136 dtypesym(t1.Type)
1137 }
1138
Russ Coxc8198342015-03-12 18:45:30 -04001139 for t1 := getoutargx(t).Type; t1 != nil; t1 = t1.Down {
Russ Cox8c195bd2015-02-13 14:40:36 -05001140 dtypesym(t1.Type)
1141 }
1142
1143 ot = dcommontype(s, ot, t)
Michael Hudson-Doyleaf784822015-08-21 15:23:57 +12001144 xt = ot - 2*Widthptr
Michael Hudson-Doyleac1cdd12015-04-22 12:41:14 +12001145 ot = duint8(s, ot, uint8(obj.Bool2int(isddd)))
Russ Cox8c195bd2015-02-13 14:40:36 -05001146
1147 // two slice headers: in and out.
1148 ot = int(Rnd(int64(ot), int64(Widthptr)))
1149
1150 ot = dsymptr(s, ot, s, ot+2*(Widthptr+2*Widthint))
Russ Coxc8198342015-03-12 18:45:30 -04001151 n := t.Thistuple + t.Intuple
Russ Cox8c195bd2015-02-13 14:40:36 -05001152 ot = duintxx(s, ot, uint64(n), Widthint)
1153 ot = duintxx(s, ot, uint64(n), Widthint)
1154 ot = dsymptr(s, ot, s, ot+1*(Widthptr+2*Widthint)+n*Widthptr)
1155 ot = duintxx(s, ot, uint64(t.Outtuple), Widthint)
1156 ot = duintxx(s, ot, uint64(t.Outtuple), Widthint)
1157
1158 // slice data
Russ Coxc8198342015-03-12 18:45:30 -04001159 for t1 := getthisx(t).Type; t1 != nil; t1 = t1.Down {
Russ Cox8c195bd2015-02-13 14:40:36 -05001160 ot = dsymptr(s, ot, dtypesym(t1.Type), 0)
Russ Coxd7f6d462015-03-09 00:31:13 -04001161 n++
Russ Cox8c195bd2015-02-13 14:40:36 -05001162 }
Russ Coxc8198342015-03-12 18:45:30 -04001163 for t1 := getinargx(t).Type; t1 != nil; t1 = t1.Down {
Russ Cox8c195bd2015-02-13 14:40:36 -05001164 ot = dsymptr(s, ot, dtypesym(t1.Type), 0)
Russ Coxd7f6d462015-03-09 00:31:13 -04001165 n++
Russ Cox8c195bd2015-02-13 14:40:36 -05001166 }
Russ Coxc8198342015-03-12 18:45:30 -04001167 for t1 := getoutargx(t).Type; t1 != nil; t1 = t1.Down {
Russ Cox8c195bd2015-02-13 14:40:36 -05001168 ot = dsymptr(s, ot, dtypesym(t1.Type), 0)
Russ Coxd7f6d462015-03-09 00:31:13 -04001169 n++
Russ Cox8c195bd2015-02-13 14:40:36 -05001170 }
1171
1172 case TINTER:
Russ Cox382b44e2015-02-23 16:07:24 -05001173 m := imethods(t)
Russ Coxc8198342015-03-12 18:45:30 -04001174 n := 0
Russ Cox382b44e2015-02-23 16:07:24 -05001175 for a := m; a != nil; a = a.link {
Russ Cox8c195bd2015-02-13 14:40:36 -05001176 dtypesym(a.type_)
1177 n++
1178 }
1179
1180 // ../../runtime/type.go:/InterfaceType
1181 ot = dcommontype(s, ot, t)
1182
Michael Hudson-Doyleaf784822015-08-21 15:23:57 +12001183 xt = ot - 2*Widthptr
Russ Cox8c195bd2015-02-13 14:40:36 -05001184 ot = dsymptr(s, ot, s, ot+Widthptr+2*Widthint)
1185 ot = duintxx(s, ot, uint64(n), Widthint)
1186 ot = duintxx(s, ot, uint64(n), Widthint)
Russ Cox382b44e2015-02-23 16:07:24 -05001187 for a := m; a != nil; a = a.link {
Russ Cox8c195bd2015-02-13 14:40:36 -05001188 // ../../runtime/type.go:/imethod
1189 ot = dgostringptr(s, ot, a.name)
1190
1191 ot = dgopkgpath(s, ot, a.pkg)
1192 ot = dsymptr(s, ot, dtypesym(a.type_), 0)
1193 }
1194
1195 // ../../runtime/type.go:/MapType
1196 case TMAP:
Russ Cox382b44e2015-02-23 16:07:24 -05001197 s1 := dtypesym(t.Down)
Russ Cox8c195bd2015-02-13 14:40:36 -05001198
Russ Cox382b44e2015-02-23 16:07:24 -05001199 s2 := dtypesym(t.Type)
1200 s3 := dtypesym(mapbucket(t))
1201 s4 := dtypesym(hmap(t))
Russ Cox8c195bd2015-02-13 14:40:36 -05001202 ot = dcommontype(s, ot, t)
Michael Hudson-Doyleaf784822015-08-21 15:23:57 +12001203 xt = ot - 2*Widthptr
Russ Cox8c195bd2015-02-13 14:40:36 -05001204 ot = dsymptr(s, ot, s1, 0)
1205 ot = dsymptr(s, ot, s2, 0)
1206 ot = dsymptr(s, ot, s3, 0)
1207 ot = dsymptr(s, ot, s4, 0)
1208 if t.Down.Width > MAXKEYSIZE {
1209 ot = duint8(s, ot, uint8(Widthptr))
1210 ot = duint8(s, ot, 1) // indirect
1211 } else {
1212 ot = duint8(s, ot, uint8(t.Down.Width))
1213 ot = duint8(s, ot, 0) // not indirect
1214 }
1215
1216 if t.Type.Width > MAXVALSIZE {
1217 ot = duint8(s, ot, uint8(Widthptr))
1218 ot = duint8(s, ot, 1) // indirect
1219 } else {
1220 ot = duint8(s, ot, uint8(t.Type.Width))
1221 ot = duint8(s, ot, 0) // not indirect
1222 }
1223
1224 ot = duint16(s, ot, uint16(mapbucket(t).Width))
Michael Hudson-Doyleac1cdd12015-04-22 12:41:14 +12001225 ot = duint8(s, ot, uint8(obj.Bool2int(isreflexive(t.Down))))
Keith Randall00c638d2015-06-08 08:42:28 -07001226 ot = duint8(s, ot, uint8(obj.Bool2int(needkeyupdate(t.Down))))
Russ Cox8c195bd2015-02-13 14:40:36 -05001227
Josh Bleecher Snyderb09925b2015-04-01 09:38:44 -07001228 case TPTR32, TPTR64:
Russ Cox8c195bd2015-02-13 14:40:36 -05001229 if t.Type.Etype == TANY {
1230 // ../../runtime/type.go:/UnsafePointerType
1231 ot = dcommontype(s, ot, t)
1232
1233 break
1234 }
1235
1236 // ../../runtime/type.go:/PtrType
Russ Cox382b44e2015-02-23 16:07:24 -05001237 s1 := dtypesym(t.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -05001238
1239 ot = dcommontype(s, ot, t)
Michael Hudson-Doyleaf784822015-08-21 15:23:57 +12001240 xt = ot - 2*Widthptr
Russ Cox8c195bd2015-02-13 14:40:36 -05001241 ot = dsymptr(s, ot, s1, 0)
1242
1243 // ../../runtime/type.go:/StructType
1244 // for security, only the exported fields.
1245 case TSTRUCT:
Russ Coxc8198342015-03-12 18:45:30 -04001246 n := 0
Russ Cox8c195bd2015-02-13 14:40:36 -05001247
Russ Coxc8198342015-03-12 18:45:30 -04001248 for t1 := t.Type; t1 != nil; t1 = t1.Down {
Russ Cox8c195bd2015-02-13 14:40:36 -05001249 dtypesym(t1.Type)
1250 n++
1251 }
1252
1253 ot = dcommontype(s, ot, t)
Michael Hudson-Doyleaf784822015-08-21 15:23:57 +12001254 xt = ot - 2*Widthptr
Russ Cox8c195bd2015-02-13 14:40:36 -05001255 ot = dsymptr(s, ot, s, ot+Widthptr+2*Widthint)
1256 ot = duintxx(s, ot, uint64(n), Widthint)
1257 ot = duintxx(s, ot, uint64(n), Widthint)
Russ Coxc8198342015-03-12 18:45:30 -04001258 for t1 := t.Type; t1 != nil; t1 = t1.Down {
Russ Cox8c195bd2015-02-13 14:40:36 -05001259 // ../../runtime/type.go:/structField
Russ Coxdc7b54b2015-02-17 22:13:49 -05001260 if t1.Sym != nil && t1.Embedded == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -05001261 ot = dgostringptr(s, ot, t1.Sym.Name)
1262 if exportname(t1.Sym.Name) {
1263 ot = dgostringptr(s, ot, "")
1264 } else {
1265 ot = dgopkgpath(s, ot, t1.Sym.Pkg)
1266 }
1267 } else {
1268 ot = dgostringptr(s, ot, "")
1269 if t1.Type.Sym != nil && t1.Type.Sym.Pkg == builtinpkg {
1270 ot = dgopkgpath(s, ot, localpkg)
1271 } else {
1272 ot = dgostringptr(s, ot, "")
1273 }
1274 }
1275
1276 ot = dsymptr(s, ot, dtypesym(t1.Type), 0)
1277 ot = dgostrlitptr(s, ot, t1.Note)
1278 ot = duintptr(s, ot, uint64(t1.Width)) // field offset
1279 }
1280 }
1281
1282 ot = dextratype(s, ot, t, xt)
Michael Hudson-Doyle029c7bb2015-04-18 08:14:08 +12001283 ggloblsym(s, int32(ot), int16(dupok|obj.RODATA))
Russ Cox8c195bd2015-02-13 14:40:36 -05001284
1285 // generate typelink.foo pointing at s = type.foo.
1286 // The linker will leave a table of all the typelinks for
1287 // types in the binary, so reflect can find them.
1288 // We only need the link for unnamed composites that
1289 // we want be able to find.
1290 if t.Sym == nil {
1291 switch t.Etype {
Michael Hudson-Doyle2f0828ef2015-03-29 23:11:47 +00001292 case TPTR32, TPTR64:
1293 // The ptrto field of the type data cannot be relied on when
1294 // dynamic linking: a type T may be defined in a module that makes
1295 // no use of pointers to that type, but another module can contain
1296 // a package that imports the first one and does use *T pointers.
1297 // The second module will end up defining type data for *T and a
1298 // type.*T symbol pointing at it. It's important that calling
Ainar Garipov7f9f70e2015-06-11 16:49:38 +03001299 // .PtrTo() on the reflect.Type for T returns this type data and
Michael Hudson-Doyle2f0828ef2015-03-29 23:11:47 +00001300 // not some synthesized object, so we need reflect to be able to
1301 // find it!
1302 if !Ctxt.Flag_dynlink {
1303 break
1304 }
1305 fallthrough
Dave Daye1c1fa22014-12-23 15:19:30 +11001306 case TARRAY, TCHAN, TFUNC, TMAP:
Russ Cox382b44e2015-02-23 16:07:24 -05001307 slink := typelinksym(t)
Russ Cox8c195bd2015-02-13 14:40:36 -05001308 dsymptr(slink, 0, s, 0)
Michael Hudson-Doyle029c7bb2015-04-18 08:14:08 +12001309 ggloblsym(slink, int32(Widthptr), int16(dupok|obj.RODATA))
Russ Cox8c195bd2015-02-13 14:40:36 -05001310 }
1311 }
1312
1313 return s
1314}
1315
1316func dumptypestructs() {
Russ Cox8c195bd2015-02-13 14:40:36 -05001317 var n *Node
Russ Cox8c195bd2015-02-13 14:40:36 -05001318
1319 // copy types from externdcl list to signatlist
Russ Cox382b44e2015-02-23 16:07:24 -05001320 for l := externdcl; l != nil; l = l.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -05001321 n = l.N
1322 if n.Op != OTYPE {
1323 continue
1324 }
1325 signatlist = list(signatlist, n)
1326 }
1327
1328 // process signatlist
Russ Cox382b44e2015-02-23 16:07:24 -05001329 var t *Type
1330 for l := signatlist; l != nil; l = l.Next {
Russ Cox8c195bd2015-02-13 14:40:36 -05001331 n = l.N
1332 if n.Op != OTYPE {
1333 continue
1334 }
1335 t = n.Type
1336 dtypesym(t)
1337 if t.Sym != nil {
1338 dtypesym(Ptrto(t))
1339 }
1340 }
1341
1342 // generate import strings for imported packages
Russ Coxd0b59de2015-03-02 16:21:15 -05001343 for _, p := range pkgs {
Marvin Stengere03c7892015-09-08 05:46:31 +02001344 if p.Direct {
Russ Coxd0b59de2015-03-02 16:21:15 -05001345 dimportpath(p)
Russ Cox8c195bd2015-02-13 14:40:36 -05001346 }
1347 }
1348
1349 // do basic types if compiling package runtime.
1350 // they have to be in at least one package,
1351 // and runtime is always loaded implicitly,
1352 // so this is as good as any.
1353 // another possible choice would be package main,
1354 // but using runtime means fewer copies in .6 files.
1355 if compiling_runtime != 0 {
Russ Cox382b44e2015-02-23 16:07:24 -05001356 for i := 1; i <= TBOOL; i++ {
Russ Cox8c195bd2015-02-13 14:40:36 -05001357 dtypesym(Ptrto(Types[i]))
1358 }
1359 dtypesym(Ptrto(Types[TSTRING]))
1360 dtypesym(Ptrto(Types[TUNSAFEPTR]))
1361
1362 // emit type structs for error and func(error) string.
1363 // The latter is the type of an auto-generated wrapper.
1364 dtypesym(Ptrto(errortype))
1365
1366 dtypesym(functype(nil, list1(Nod(ODCLFIELD, nil, typenod(errortype))), list1(Nod(ODCLFIELD, nil, typenod(Types[TSTRING])))))
1367
1368 // add paths for runtime and main, which 6l imports implicitly.
1369 dimportpath(Runtimepkg)
1370
1371 if flag_race != 0 {
1372 dimportpath(racepkg)
1373 }
Russ Coxbed1f902015-03-02 16:03:26 -05001374 dimportpath(mkpkg("main"))
Russ Cox8c195bd2015-02-13 14:40:36 -05001375 }
1376}
1377
1378func dalgsym(t *Type) *Sym {
Russ Cox8c195bd2015-02-13 14:40:36 -05001379 var s *Sym
Russ Cox8c195bd2015-02-13 14:40:36 -05001380 var hashfunc *Sym
Russ Cox8c195bd2015-02-13 14:40:36 -05001381 var eqfunc *Sym
Russ Cox8c195bd2015-02-13 14:40:36 -05001382
1383 // dalgsym is only called for a type that needs an algorithm table,
1384 // which implies that the type is comparable (or else it would use ANOEQ).
1385
1386 if algtype(t) == AMEM {
1387 // we use one algorithm table for all AMEM types of a given size
Russ Cox382b44e2015-02-23 16:07:24 -05001388 p := fmt.Sprintf(".alg%d", t.Width)
Russ Cox8c195bd2015-02-13 14:40:36 -05001389
1390 s = Pkglookup(p, typepkg)
1391
1392 if s.Flags&SymAlgGen != 0 {
1393 return s
1394 }
1395 s.Flags |= SymAlgGen
1396
1397 // make hash closure
1398 p = fmt.Sprintf(".hashfunc%d", t.Width)
1399
1400 hashfunc = Pkglookup(p, typepkg)
1401
Russ Cox382b44e2015-02-23 16:07:24 -05001402 ot := 0
Russ Cox8c195bd2015-02-13 14:40:36 -05001403 ot = dsymptr(hashfunc, ot, Pkglookup("memhash_varlen", Runtimepkg), 0)
1404 ot = duintxx(hashfunc, ot, uint64(t.Width), Widthptr) // size encoded in closure
1405 ggloblsym(hashfunc, int32(ot), obj.DUPOK|obj.RODATA)
1406
1407 // make equality closure
1408 p = fmt.Sprintf(".eqfunc%d", t.Width)
1409
1410 eqfunc = Pkglookup(p, typepkg)
1411
1412 ot = 0
1413 ot = dsymptr(eqfunc, ot, Pkglookup("memequal_varlen", Runtimepkg), 0)
1414 ot = duintxx(eqfunc, ot, uint64(t.Width), Widthptr)
1415 ggloblsym(eqfunc, int32(ot), obj.DUPOK|obj.RODATA)
1416 } else {
1417 // generate an alg table specific to this type
1418 s = typesymprefix(".alg", t)
1419
Russ Cox382b44e2015-02-23 16:07:24 -05001420 hash := typesymprefix(".hash", t)
1421 eq := typesymprefix(".eq", t)
Russ Cox8c195bd2015-02-13 14:40:36 -05001422 hashfunc = typesymprefix(".hashfunc", t)
1423 eqfunc = typesymprefix(".eqfunc", t)
1424
1425 genhash(hash, t)
1426 geneq(eq, t)
1427
1428 // make Go funcs (closures) for calling hash and equal from Go
1429 dsymptr(hashfunc, 0, hash, 0)
1430
1431 ggloblsym(hashfunc, int32(Widthptr), obj.DUPOK|obj.RODATA)
1432 dsymptr(eqfunc, 0, eq, 0)
1433 ggloblsym(eqfunc, int32(Widthptr), obj.DUPOK|obj.RODATA)
1434 }
1435
1436 // ../../runtime/alg.go:/typeAlg
Russ Cox382b44e2015-02-23 16:07:24 -05001437 ot := 0
Russ Cox8c195bd2015-02-13 14:40:36 -05001438
1439 ot = dsymptr(s, ot, hashfunc, 0)
1440 ot = dsymptr(s, ot, eqfunc, 0)
1441 ggloblsym(s, int32(ot), obj.DUPOK|obj.RODATA)
1442 return s
1443}
1444
Russ Cox512f75e2015-05-08 01:43:18 -04001445// maxPtrmaskBytes is the maximum length of a GC ptrmask bitmap,
1446// which holds 1-bit entries describing where pointers are in a given type.
1447// 16 bytes is enough to describe 128 pointer-sized words, 512 or 1024 bytes
1448// depending on the system. Above this length, the GC information is
1449// recorded as a GC program, which can express repetition compactly.
1450// In either form, the information is used by the runtime to initialize the
1451// heap bitmap, and for large types (like 128 or more words), they are
1452// roughly the same speed. GC programs are never much larger and often
1453// more compact. (If large arrays are involved, they can be arbitrarily more
1454// compact.)
1455//
1456// The cutoff must be large enough that any allocation large enough to
1457// use a GC program is large enough that it does not share heap bitmap
1458// bytes with any other objects, allowing the GC program execution to
1459// assume an aligned start and not use atomic operations. In the current
1460// runtime, this means all malloc size classes larger than the cutoff must
1461// be multiples of four words. On 32-bit systems that's 16 bytes, and
1462// all size classes >= 16 bytes are 16-byte aligned, so no real constraint.
1463// On 64-bit systems, that's 32 bytes, and 32-byte alignment is guaranteed
1464// for size classes >= 256 bytes. On a 64-bit sytem, 256 bytes allocated
1465// is 32 pointers, the bits for which fit in 4 bytes. So maxPtrmaskBytes
1466// must be >= 4.
1467//
Russ Cox80ec7112015-06-07 22:47:59 -04001468// We used to use 16 because the GC programs do have some constant overhead
Russ Cox512f75e2015-05-08 01:43:18 -04001469// to get started, and processing 128 pointers seems to be enough to
1470// amortize that overhead well.
Russ Cox80ec7112015-06-07 22:47:59 -04001471//
1472// To make sure that the runtime's chansend can call typeBitsBulkBarrier,
1473// we raised the limit to 2048, so that even 32-bit systems are guaranteed to
1474// use bitmaps for objects up to 64 kB in size.
1475//
1476// Also known to reflect/type.go.
1477//
1478const maxPtrmaskBytes = 2048
Russ Cox512f75e2015-05-08 01:43:18 -04001479
1480// dgcsym emits and returns a data symbol containing GC information for type t,
1481// along with a boolean reporting whether the UseGCProg bit should be set in
1482// the type kind, and the ptrdata field to record in the reflect type information.
1483func dgcsym(t *Type) (sym *Sym, useGCProg bool, ptrdata int64) {
1484 ptrdata = typeptrdata(t)
1485 if ptrdata/int64(Widthptr) <= maxPtrmaskBytes*8 {
1486 sym = dgcptrmask(t)
1487 return
Russ Cox8c195bd2015-02-13 14:40:36 -05001488 }
1489
Russ Cox512f75e2015-05-08 01:43:18 -04001490 useGCProg = true
1491 sym, ptrdata = dgcprog(t)
1492 return
Russ Cox8c195bd2015-02-13 14:40:36 -05001493}
1494
Russ Cox512f75e2015-05-08 01:43:18 -04001495// dgcptrmask emits and returns the symbol containing a pointer mask for type t.
1496func dgcptrmask(t *Type) *Sym {
1497 ptrmask := make([]byte, (typeptrdata(t)/int64(Widthptr)+7)/8)
1498 fillptrmask(t, ptrmask)
1499 p := fmt.Sprintf("gcbits.%x", ptrmask)
1500
1501 sym := Pkglookup(p, Runtimepkg)
1502 if sym.Flags&SymUniq == 0 {
1503 sym.Flags |= SymUniq
1504 for i, x := range ptrmask {
1505 duint8(sym, i, x)
1506 }
1507 ggloblsym(sym, int32(len(ptrmask)), obj.DUPOK|obj.RODATA|obj.LOCAL)
1508 }
1509 return sym
1510}
1511
1512// fillptrmask fills in ptrmask with 1s corresponding to the
1513// word offsets in t that hold pointers.
1514// ptrmask is assumed to fit at least typeptrdata(t)/Widthptr bits.
1515func fillptrmask(t *Type, ptrmask []byte) {
1516 for i := range ptrmask {
1517 ptrmask[i] = 0
Russ Cox8c195bd2015-02-13 14:40:36 -05001518 }
1519 if !haspointers(t) {
1520 return
1521 }
1522
Russ Cox512f75e2015-05-08 01:43:18 -04001523 vec := bvalloc(8 * int32(len(ptrmask)))
Russ Cox6d8a1472015-04-28 00:28:47 -04001524 xoffset := int64(0)
Russ Cox4d0f3a12015-04-27 22:45:57 -04001525 onebitwalktype1(t, &xoffset, vec)
Russ Cox8c195bd2015-02-13 14:40:36 -05001526
Russ Cox54af9a32015-05-04 22:53:54 -04001527 nptr := typeptrdata(t) / int64(Widthptr)
Russ Cox6d8a1472015-04-28 00:28:47 -04001528 for i := int64(0); i < nptr; i++ {
1529 if bvget(vec, int32(i)) == 1 {
Russ Cox512f75e2015-05-08 01:43:18 -04001530 ptrmask[i/8] |= 1 << (uint(i) % 8)
Russ Cox8c195bd2015-02-13 14:40:36 -05001531 }
1532 }
1533}
1534
Russ Cox512f75e2015-05-08 01:43:18 -04001535// dgcprog emits and returns the symbol containing a GC program for type t
1536// along with the size of the data described by the program (in the range [typeptrdata(t), t.Width]).
1537// In practice, the size is typeptrdata(t) except for non-trivial arrays.
1538// For non-trivial arrays, the program describes the full t.Width size.
1539func dgcprog(t *Type) (*Sym, int64) {
1540 dowidth(t)
1541 if t.Width == BADWIDTH {
Håvard Haugen3c9fa382015-08-30 23:10:03 +02001542 Fatalf("dgcprog: %v badwidth", t)
Russ Cox512f75e2015-05-08 01:43:18 -04001543 }
1544 sym := typesymprefix(".gcprog", t)
1545 var p GCProg
1546 p.init(sym)
1547 p.emit(t, 0)
1548 offset := p.w.BitIndex() * int64(Widthptr)
1549 p.end()
1550 if ptrdata := typeptrdata(t); offset < ptrdata || offset > t.Width {
Håvard Haugen3c9fa382015-08-30 23:10:03 +02001551 Fatalf("dgcprog: %v: offset=%d but ptrdata=%d size=%d", t, offset, ptrdata, t.Width)
Russ Cox512f75e2015-05-08 01:43:18 -04001552 }
1553 return sym, offset
Russ Cox8c195bd2015-02-13 14:40:36 -05001554}
1555
Russ Cox512f75e2015-05-08 01:43:18 -04001556type GCProg struct {
1557 sym *Sym
1558 symoff int
1559 w gcprog.Writer
Russ Cox8c195bd2015-02-13 14:40:36 -05001560}
1561
Russ Cox512f75e2015-05-08 01:43:18 -04001562var Debug_gcprog int // set by -d gcprog
1563
1564func (p *GCProg) init(sym *Sym) {
1565 p.sym = sym
1566 p.symoff = 4 // first 4 bytes hold program length
1567 p.w.Init(p.writeByte)
1568 if Debug_gcprog > 0 {
1569 fmt.Fprintf(os.Stderr, "compile: start GCProg for %v\n", sym)
1570 p.w.Debug(os.Stderr)
1571 }
Russ Cox8c195bd2015-02-13 14:40:36 -05001572}
1573
Russ Cox512f75e2015-05-08 01:43:18 -04001574func (p *GCProg) writeByte(x byte) {
1575 p.symoff = duint8(p.sym, p.symoff, x)
1576}
1577
1578func (p *GCProg) end() {
1579 p.w.End()
1580 duint32(p.sym, 0, uint32(p.symoff-4))
1581 ggloblsym(p.sym, int32(p.symoff), obj.DUPOK|obj.RODATA|obj.LOCAL)
1582 if Debug_gcprog > 0 {
1583 fmt.Fprintf(os.Stderr, "compile: end GCProg for %v\n", p.sym)
1584 }
1585}
1586
1587func (p *GCProg) emit(t *Type, offset int64) {
1588 dowidth(t)
1589 if !haspointers(t) {
Russ Cox8c195bd2015-02-13 14:40:36 -05001590 return
1591 }
Russ Cox512f75e2015-05-08 01:43:18 -04001592 if t.Width == int64(Widthptr) {
1593 p.w.Ptr(offset / int64(Widthptr))
1594 return
Russ Cox8c195bd2015-02-13 14:40:36 -05001595 }
Russ Cox8c195bd2015-02-13 14:40:36 -05001596 switch t.Etype {
Russ Cox512f75e2015-05-08 01:43:18 -04001597 default:
Håvard Haugen3c9fa382015-08-30 23:10:03 +02001598 Fatalf("GCProg.emit: unexpected type %v", t)
Russ Cox8c195bd2015-02-13 14:40:36 -05001599
1600 case TSTRING:
Russ Cox512f75e2015-05-08 01:43:18 -04001601 p.w.Ptr(offset / int64(Widthptr))
Russ Cox8c195bd2015-02-13 14:40:36 -05001602
Russ Cox8c195bd2015-02-13 14:40:36 -05001603 case TINTER:
Russ Cox512f75e2015-05-08 01:43:18 -04001604 p.w.Ptr(offset / int64(Widthptr))
1605 p.w.Ptr(offset/int64(Widthptr) + 1)
Russ Cox8c195bd2015-02-13 14:40:36 -05001606
1607 case TARRAY:
Russ Coxdc7b54b2015-02-17 22:13:49 -05001608 if Isslice(t) {
Russ Cox512f75e2015-05-08 01:43:18 -04001609 p.w.Ptr(offset / int64(Widthptr))
1610 return
Russ Cox8c195bd2015-02-13 14:40:36 -05001611 }
Russ Cox512f75e2015-05-08 01:43:18 -04001612 if t.Bound == 0 {
1613 // should have been handled by haspointers check above
Håvard Haugen3c9fa382015-08-30 23:10:03 +02001614 Fatalf("GCProg.emit: empty array")
Russ Cox512f75e2015-05-08 01:43:18 -04001615 }
1616
1617 // Flatten array-of-array-of-array to just a big array by multiplying counts.
1618 count := t.Bound
1619 elem := t.Type
1620 for Isfixedarray(elem) {
1621 count *= elem.Bound
1622 elem = elem.Type
1623 }
1624
1625 if !p.w.ShouldRepeat(elem.Width/int64(Widthptr), count) {
1626 // Cheaper to just emit the bits.
1627 for i := int64(0); i < count; i++ {
1628 p.emit(elem, offset+i*elem.Width)
1629 }
1630 return
1631 }
1632 p.emit(elem, offset)
1633 p.w.ZeroUntil((offset + elem.Width) / int64(Widthptr))
1634 p.w.Repeat(elem.Width/int64(Widthptr), count-1)
Russ Cox8c195bd2015-02-13 14:40:36 -05001635
1636 case TSTRUCT:
Russ Cox382b44e2015-02-23 16:07:24 -05001637 for t1 := t.Type; t1 != nil; t1 = t1.Down {
Russ Cox512f75e2015-05-08 01:43:18 -04001638 p.emit(t1.Type, offset+t1.Width)
Russ Cox8c195bd2015-02-13 14:40:36 -05001639 }
Russ Cox8c195bd2015-02-13 14:40:36 -05001640 }
1641}