Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1 | // 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 | |
| 5 | package gc |
| 6 | |
| 7 | import ( |
Russ Cox | 512f75e | 2015-05-08 01:43:18 -0400 | [diff] [blame] | 8 | "cmd/internal/gcprog" |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 9 | "cmd/internal/obj" |
| 10 | "fmt" |
Russ Cox | 512f75e | 2015-05-08 01:43:18 -0400 | [diff] [blame] | 11 | "os" |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 12 | ) |
| 13 | |
| 14 | /* |
| 15 | * runtime interface and reflection data structures |
| 16 | */ |
| 17 | var signatlist *NodeList |
| 18 | |
| 19 | func sigcmp(a *Sig, b *Sig) int { |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 20 | i := stringsCompare(a.name, b.name) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 21 | 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 Cox | bed1f90 | 2015-03-02 16:03:26 -0500 | [diff] [blame] | 33 | return stringsCompare(a.pkg.Path, b.pkg.Path) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 34 | } |
| 35 | |
| 36 | func lsort(l *Sig, f func(*Sig, *Sig) int) *Sig { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 37 | if l == nil || l.link == nil { |
| 38 | return l |
| 39 | } |
| 40 | |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 41 | l1 := l |
| 42 | l2 := l |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 43 | 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 Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 69 | le := l |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 70 | |
| 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 Garipov | 7f9f70e | 2015-06-11 16:49:38 +0300 | [diff] [blame] | 108 | // Builds a type representing a Bucket structure for |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 109 | // 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 Randall | cd5b144 | 2015-03-11 12:58:47 -0700 | [diff] [blame] | 112 | // Make sure this stays in sync with ../../runtime/hashmap.go! |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 113 | const ( |
| 114 | BUCKETSIZE = 8 |
| 115 | MAXKEYSIZE = 128 |
| 116 | MAXVALSIZE = 128 |
| 117 | ) |
| 118 | |
| 119 | func makefield(name string, t *Type) *Type { |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 120 | f := typ(TFIELD) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 121 | f.Type = t |
| 122 | f.Sym = new(Sym) |
| 123 | f.Sym.Name = name |
| 124 | return f |
| 125 | } |
| 126 | |
| 127 | func mapbucket(t *Type) *Type { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 128 | if t.Bucket != nil { |
| 129 | return t.Bucket |
| 130 | } |
| 131 | |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 132 | bucket := typ(TSTRUCT) |
| 133 | keytype := t.Down |
| 134 | valtype := t.Type |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 135 | 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 Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 145 | arr := typ(TARRAY) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 146 | |
| 147 | arr.Type = Types[TUINT8] |
| 148 | arr.Bound = BUCKETSIZE |
Russ Cox | c5dff72 | 2015-07-30 22:05:51 -0400 | [diff] [blame] | 149 | field := make([]*Type, 0, 5) |
| 150 | field = append(field, makefield("topbits", arr)) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 151 | arr = typ(TARRAY) |
| 152 | arr.Type = keytype |
| 153 | arr.Bound = BUCKETSIZE |
Russ Cox | c5dff72 | 2015-07-30 22:05:51 -0400 | [diff] [blame] | 154 | field = append(field, makefield("keys", arr)) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 155 | arr = typ(TARRAY) |
| 156 | arr.Type = valtype |
| 157 | arr.Bound = BUCKETSIZE |
Russ Cox | c5dff72 | 2015-07-30 22:05:51 -0400 | [diff] [blame] | 158 | 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 Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 193 | |
| 194 | // link up fields |
Marvin Stenger | 9ac0fff | 2015-09-08 03:51:30 +0200 | [diff] [blame] | 195 | bucket.Noalg = true |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 196 | bucket.Local = t.Local |
| 197 | bucket.Type = field[0] |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 198 | for n := int32(0); n < int32(len(field)-1); n++ { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 199 | field[n].Down = field[n+1] |
| 200 | } |
| 201 | field[len(field)-1].Down = nil |
| 202 | dowidth(bucket) |
| 203 | |
Russ Cox | c5dff72 | 2015-07-30 22:05:51 -0400 | [diff] [blame] | 204 | // 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 Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 208 | } |
| 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! |
| 218 | func hmap(t *Type) *Type { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 219 | if t.Hmap != nil { |
| 220 | return t.Hmap |
| 221 | } |
| 222 | |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 223 | bucket := mapbucket(t) |
| 224 | var field [8]*Type |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 225 | 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 Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 234 | h := typ(TSTRUCT) |
Marvin Stenger | 9ac0fff | 2015-09-08 03:51:30 +0200 | [diff] [blame] | 235 | h.Noalg = true |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 236 | h.Local = t.Local |
| 237 | h.Type = field[0] |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 238 | for n := int32(0); n < int32(len(field)-1); n++ { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 239 | 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 | |
| 248 | func hiter(t *Type) *Type { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 249 | 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 Randall | cd5b144 | 2015-03-11 12:58:47 -0700 | [diff] [blame] | 268 | // must match ../../runtime/hashmap.go:hash_iter. |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 269 | var field [12]*Type |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 270 | 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 Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 285 | i := typ(TSTRUCT) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 286 | |
Marvin Stenger | 9ac0fff | 2015-09-08 03:51:30 +0200 | [diff] [blame] | 287 | i.Noalg = true |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 288 | i.Type = field[0] |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 289 | for n := int32(0); n < int32(len(field)-1); n++ { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 290 | 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 | */ |
| 306 | func methodfunc(f *Type, receiver *Type) *Type { |
Russ Cox | 175929b | 2015-03-02 14:22:05 -0500 | [diff] [blame] | 307 | var in *NodeList |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 308 | if receiver != nil { |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 309 | d := Nod(ODCLFIELD, nil, nil) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 310 | d.Type = receiver |
| 311 | in = list(in, d) |
| 312 | } |
| 313 | |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 314 | var d *Node |
| 315 | for t := getinargx(f).Type; t != nil; t = t.Down { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 316 | d = Nod(ODCLFIELD, nil, nil) |
| 317 | d.Type = t.Type |
| 318 | d.Isddd = t.Isddd |
| 319 | in = list(in, d) |
| 320 | } |
| 321 | |
Russ Cox | 175929b | 2015-03-02 14:22:05 -0500 | [diff] [blame] | 322 | var out *NodeList |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 323 | for t := getoutargx(f).Type; t != nil; t = t.Down { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 324 | d = Nod(ODCLFIELD, nil, nil) |
| 325 | d.Type = t.Type |
| 326 | out = list(out, d) |
| 327 | } |
| 328 | |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 329 | t := functype(nil, in, out) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 330 | 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 | */ |
| 342 | func methods(t *Type) *Sig { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 343 | // method type |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 344 | mt := methtype(t, 0) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 345 | |
| 346 | if mt == nil { |
| 347 | return nil |
| 348 | } |
| 349 | expandmeth(mt) |
| 350 | |
| 351 | // type stored in interface word |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 352 | it := t |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 353 | |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 354 | if !isdirectiface(it) { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 355 | it = Ptrto(t) |
| 356 | } |
| 357 | |
| 358 | // make list of methods for t, |
| 359 | // generating code if necessary. |
Russ Cox | 175929b | 2015-03-02 14:22:05 -0500 | [diff] [blame] | 360 | var a *Sig |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 361 | |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 362 | var this *Type |
| 363 | var b *Sig |
| 364 | var method *Sym |
| 365 | for f := mt.Xmethod; f != nil; f = f.Down { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 366 | if f.Etype != TFIELD { |
Håvard Haugen | 3c9fa38 | 2015-08-30 23:10:03 +0200 | [diff] [blame] | 367 | Fatalf("methods: not field %v", f) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 368 | } |
| 369 | if f.Type.Etype != TFUNC || f.Type.Thistuple == 0 { |
Håvard Haugen | 3c9fa38 | 2015-08-30 23:10:03 +0200 | [diff] [blame] | 370 | Fatalf("non-method on %v method %v %v\n", mt, f.Sym, f) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 371 | } |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 372 | if getthisx(f.Type).Type == nil { |
Håvard Haugen | 3c9fa38 | 2015-08-30 23:10:03 +0200 | [diff] [blame] | 373 | Fatalf("receiver with no type on %v method %v %v\n", mt, f.Sym, f) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 374 | } |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 375 | if f.Nointerface { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 376 | 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 Snyder | 25da594 | 2015-03-01 07:54:01 +0000 | [diff] [blame] | 390 | if Isptr[this.Etype] && this.Type == t { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 391 | continue |
| 392 | } |
Josh Bleecher Snyder | 25da594 | 2015-03-01 07:54:01 +0000 | [diff] [blame] | 393 | if Isptr[this.Etype] && !Isptr[t.Etype] && f.Embedded != 2 && !isifacemethod(f.Type) { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 394 | 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 Haugen | 3c9fa38 | 2015-08-30 23:10:03 +0200 | [diff] [blame] | 404 | Fatalf("methods: missing package") |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 405 | } |
| 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 Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 414 | if a.isym.Flags&SymSiggen == 0 { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 415 | 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 Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 423 | if a.tsym.Flags&SymSiggen == 0 { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 424 | 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 | */ |
| 439 | func imethods(t *Type) *Sig { |
| 440 | var a *Sig |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 441 | var method *Sym |
| 442 | var isym *Sym |
| 443 | |
Russ Cox | 175929b | 2015-03-02 14:22:05 -0500 | [diff] [blame] | 444 | var all *Sig |
| 445 | var last *Sig |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 446 | for f := t.Type; f != nil; f = f.Down { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 447 | if f.Etype != TFIELD { |
Håvard Haugen | 3c9fa38 | 2015-08-30 23:10:03 +0200 | [diff] [blame] | 448 | Fatalf("imethods: not field") |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 449 | } |
| 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 Haugen | 3c9fa38 | 2015-08-30 23:10:03 +0200 | [diff] [blame] | 458 | Fatalf("imethods: missing package") |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 459 | } |
| 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 Haugen | 3c9fa38 | 2015-08-30 23:10:03 +0200 | [diff] [blame] | 468 | Fatalf("sigcmp vs sortinter %s %s", last.name, a.name) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 469 | } |
| 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 Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 488 | if isym.Flags&SymSiggen == 0 { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 489 | isym.Flags |= SymSiggen |
| 490 | genwrapper(t, f, isym, 0) |
| 491 | } |
| 492 | } |
| 493 | |
| 494 | return all |
| 495 | } |
| 496 | |
| 497 | var dimportpath_gopkg *Pkg |
| 498 | |
| 499 | func dimportpath(p *Pkg) { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 500 | if p.Pathsym != nil { |
| 501 | return |
| 502 | } |
| 503 | |
Michael Hudson-Doyle | 0de359d | 2015-03-19 23:05:34 +1300 | [diff] [blame] | 504 | // 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 Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 511 | if dimportpath_gopkg == nil { |
Russ Cox | bed1f90 | 2015-03-02 16:03:26 -0500 | [diff] [blame] | 512 | dimportpath_gopkg = mkpkg("go") |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 513 | dimportpath_gopkg.Name = "go" |
| 514 | } |
| 515 | |
Michael Hudson-Doyle | b92a0a8 | 2015-04-05 14:48:42 +1200 | [diff] [blame] | 516 | nam := "importpath." + p.Prefix + "." |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 517 | |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 518 | n := Nod(ONAME, nil, nil) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 519 | n.Sym = Pkglookup(nam, dimportpath_gopkg) |
| 520 | |
| 521 | n.Class = PEXTERN |
| 522 | n.Xoffset = 0 |
| 523 | p.Pathsym = n.Sym |
| 524 | |
Michael Hudson-Doyle | b92a0a8 | 2015-04-05 14:48:42 +1200 | [diff] [blame] | 525 | 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 Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 531 | ggloblsym(n.Sym, int32(Types[TSTRING].Width), obj.DUPOK|obj.RODATA) |
| 532 | } |
| 533 | |
| 534 | func dgopkgpath(s *Sym, ot int, pkg *Pkg) int { |
| 535 | if pkg == nil { |
| 536 | return dgostringptr(s, ot, "") |
| 537 | } |
| 538 | |
Michael Hudson-Doyle | 0de359d | 2015-03-19 23:05:34 +1300 | [diff] [blame] | 539 | 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 Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 544 | var ns *Sym |
| 545 | |
| 546 | if ns == nil { |
Russ Cox | bed1f90 | 2015-03-02 16:03:26 -0500 | [diff] [blame] | 547 | ns = Pkglookup("importpath.\"\".", mkpkg("go")) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 548 | } |
| 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 | */ |
| 560 | func dextratype(sym *Sym, off int, t *Type, ptroff int) int { |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 561 | m := methods(t) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 562 | 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 Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 571 | n := 0 |
| 572 | for a := m; a != nil; a = a.link { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 573 | dtypesym(a.type_) |
| 574 | n++ |
| 575 | } |
| 576 | |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 577 | ot := off |
| 578 | s := sym |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 579 | 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 Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 598 | for a := m; a != nil; a = a.link { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 599 | // 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 | |
| 621 | var 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 | |
| 650 | func haspointers(t *Type) bool { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 651 | if t.Haspointers != 0 { |
| 652 | return t.Haspointers-1 != 0 |
| 653 | } |
| 654 | |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 655 | var ret bool |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 656 | 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 Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 673 | ret = false |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 674 | |
| 675 | case TARRAY: |
| 676 | if t.Bound < 0 { // slice |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 677 | ret = true |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 678 | break |
| 679 | } |
| 680 | |
| 681 | if t.Bound == 0 { // empty array |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 682 | ret = false |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 683 | break |
| 684 | } |
| 685 | |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 686 | ret = haspointers(t.Type) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 687 | |
| 688 | case TSTRUCT: |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 689 | ret = false |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 690 | for t1 := t.Type; t1 != nil; t1 = t1.Down { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 691 | if haspointers(t1.Type) { |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 692 | ret = true |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 693 | 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 Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 707 | ret = true |
Austin Clements | 98a9d36 | 2015-05-04 14:37:45 -0400 | [diff] [blame] | 708 | |
| 709 | case TFIELD: |
Håvard Haugen | 3c9fa38 | 2015-08-30 23:10:03 +0200 | [diff] [blame] | 710 | Fatalf("haspointers: unexpected type, %v", t) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 711 | } |
| 712 | |
Michael Hudson-Doyle | ac1cdd1 | 2015-04-22 12:41:14 +1200 | [diff] [blame] | 713 | t.Haspointers = 1 + uint8(obj.Bool2int(ret)) |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 714 | return ret |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 715 | } |
| 716 | |
Russ Cox | ceefebd | 2015-05-04 21:43:30 -0400 | [diff] [blame] | 717 | // typeptrdata returns the length in bytes of the prefix of t |
Austin Clements | 98a9d36 | 2015-05-04 14:37:45 -0400 | [diff] [blame] | 718 | // containing pointer data. Anything after this offset is scalar data. |
Russ Cox | 54af9a3 | 2015-05-04 22:53:54 -0400 | [diff] [blame] | 719 | func typeptrdata(t *Type) int64 { |
Austin Clements | 98a9d36 | 2015-05-04 14:37:45 -0400 | [diff] [blame] | 720 | 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 Cox | 54af9a3 | 2015-05-04 22:53:54 -0400 | [diff] [blame] | 731 | return int64(Widthptr) |
Austin Clements | 98a9d36 | 2015-05-04 14:37:45 -0400 | [diff] [blame] | 732 | |
| 733 | case TSTRING: |
| 734 | // struct { byte *str; intgo len; } |
Russ Cox | 54af9a3 | 2015-05-04 22:53:54 -0400 | [diff] [blame] | 735 | return int64(Widthptr) |
Austin Clements | 98a9d36 | 2015-05-04 14:37:45 -0400 | [diff] [blame] | 736 | |
| 737 | case TINTER: |
| 738 | // struct { Itab *tab; void *data; } or |
| 739 | // struct { Type *type; void *data; } |
Russ Cox | 54af9a3 | 2015-05-04 22:53:54 -0400 | [diff] [blame] | 740 | return 2 * int64(Widthptr) |
Austin Clements | 98a9d36 | 2015-05-04 14:37:45 -0400 | [diff] [blame] | 741 | |
| 742 | case TARRAY: |
| 743 | if Isslice(t) { |
| 744 | // struct { byte *array; uintgo len; uintgo cap; } |
Russ Cox | 54af9a3 | 2015-05-04 22:53:54 -0400 | [diff] [blame] | 745 | return int64(Widthptr) |
Austin Clements | 98a9d36 | 2015-05-04 14:37:45 -0400 | [diff] [blame] | 746 | } |
| 747 | // haspointers already eliminated t.Bound == 0. |
Russ Cox | 54af9a3 | 2015-05-04 22:53:54 -0400 | [diff] [blame] | 748 | return (t.Bound-1)*t.Type.Width + typeptrdata(t.Type) |
Austin Clements | 98a9d36 | 2015-05-04 14:37:45 -0400 | [diff] [blame] | 749 | |
| 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 Cox | 54af9a3 | 2015-05-04 22:53:54 -0400 | [diff] [blame] | 758 | return lastPtrField.Width + typeptrdata(lastPtrField.Type) |
Austin Clements | 98a9d36 | 2015-05-04 14:37:45 -0400 | [diff] [blame] | 759 | |
| 760 | default: |
Håvard Haugen | 3c9fa38 | 2015-08-30 23:10:03 +0200 | [diff] [blame] | 761 | Fatalf("typeptrdata: unexpected type, %v", t) |
Austin Clements | 98a9d36 | 2015-05-04 14:37:45 -0400 | [diff] [blame] | 762 | return 0 |
| 763 | } |
| 764 | } |
| 765 | |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 766 | /* |
| 767 | * commonType |
| 768 | * ../../runtime/type.go:/commonType |
| 769 | */ |
| 770 | |
| 771 | var dcommontype_algarray *Sym |
| 772 | |
| 773 | func dcommontype(s *Sym, ot int, t *Type) int { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 774 | if ot != 0 { |
Håvard Haugen | 3c9fa38 | 2015-08-30 23:10:03 +0200 | [diff] [blame] | 775 | Fatalf("dcommontype %d", ot) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 776 | } |
| 777 | |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 778 | sizeofAlg := 2 * Widthptr |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 779 | if dcommontype_algarray == nil { |
| 780 | dcommontype_algarray = Pkglookup("algarray", Runtimepkg) |
| 781 | } |
| 782 | dowidth(t) |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 783 | alg := algtype(t) |
Russ Cox | 175929b | 2015-03-02 14:22:05 -0500 | [diff] [blame] | 784 | var algsym *Sym |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 785 | if alg < 0 || alg == AMEM { |
| 786 | algsym = dalgsym(t) |
| 787 | } |
| 788 | |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 789 | var sptr *Sym |
Russ Cox | 7feb424 | 2015-07-15 00:01:54 -0400 | [diff] [blame] | 790 | tptr := Ptrto(t) |
| 791 | if !Isptr[t.Etype] && (t.Sym != nil || methods(tptr) != nil) { |
| 792 | sptr = dtypesym(tptr) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 793 | } else { |
Russ Cox | 7feb424 | 2015-07-15 00:01:54 -0400 | [diff] [blame] | 794 | sptr = weaktypesym(tptr) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 795 | } |
| 796 | |
Russ Cox | 512f75e | 2015-05-08 01:43:18 -0400 | [diff] [blame] | 797 | gcsym, useGCProg, ptrdata := dgcsym(t) |
| 798 | |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 799 | // ../../pkg/reflect/type.go:/^type.commonType |
| 800 | // actual type structure |
| 801 | // type commonType struct { |
| 802 | // size uintptr |
Austin Clements | 98a9d36 | 2015-05-04 14:37:45 -0400 | [diff] [blame] | 803 | // ptrsize uintptr |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 804 | // hash uint32 |
| 805 | // _ uint8 |
| 806 | // align uint8 |
| 807 | // fieldAlign uint8 |
| 808 | // kind uint8 |
| 809 | // alg unsafe.Pointer |
Russ Cox | 512f75e | 2015-05-08 01:43:18 -0400 | [diff] [blame] | 810 | // gcdata unsafe.Pointer |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 811 | // string *string |
| 812 | // *extraType |
| 813 | // ptrToThis *Type |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 814 | // } |
| 815 | ot = duintptr(s, ot, uint64(t.Width)) |
Russ Cox | 512f75e | 2015-05-08 01:43:18 -0400 | [diff] [blame] | 816 | ot = duintptr(s, ot, uint64(ptrdata)) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 817 | |
| 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 Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 822 | i := int(t.Align) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 823 | |
| 824 | if i == 0 { |
| 825 | i = 1 |
| 826 | } |
| 827 | if i&(i-1) != 0 { |
Håvard Haugen | 3c9fa38 | 2015-08-30 23:10:03 +0200 | [diff] [blame] | 828 | Fatalf("invalid alignment %d for %v", t.Align, t) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 829 | } |
| 830 | ot = duint8(s, ot, t.Align) // align |
| 831 | ot = duint8(s, ot, t.Align) // fieldAlign |
| 832 | |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 833 | 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 Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 840 | if isdirectiface(t) { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 841 | i |= obj.KindDirectIface |
| 842 | } |
Russ Cox | 512f75e | 2015-05-08 01:43:18 -0400 | [diff] [blame] | 843 | if useGCProg { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 844 | 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 Cox | 512f75e | 2015-05-08 01:43:18 -0400 | [diff] [blame] | 852 | ot = dsymptr(s, ot, gcsym, 0) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 853 | |
Russ Cox | c819834 | 2015-03-12 18:45:30 -0400 | [diff] [blame] | 854 | p := Tconv(t, obj.FmtLeft|obj.FmtUnsigned) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 855 | |
| 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 Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 866 | return ot |
| 867 | } |
| 868 | |
| 869 | func typesym(t *Type) *Sym { |
Russ Cox | c819834 | 2015-03-12 18:45:30 -0400 | [diff] [blame] | 870 | return Pkglookup(Tconv(t, obj.FmtLeft), typepkg) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 871 | } |
| 872 | |
| 873 | func tracksym(t *Type) *Sym { |
Russ Cox | c819834 | 2015-03-12 18:45:30 -0400 | [diff] [blame] | 874 | return Pkglookup(Tconv(t.Outer, obj.FmtLeft)+"."+t.Sym.Name, trackpkg) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 875 | } |
| 876 | |
| 877 | func typelinksym(t *Type) *Sym { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 878 | // %-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 Day | e1c1fa2 | 2014-12-23 15:19:30 +1100 | [diff] [blame] | 883 | // 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 Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 888 | |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 889 | s := Pkglookup(p, typelinkpkg) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 890 | |
| 891 | //print("typelinksym: %s -> %+S\n", p, s); |
| 892 | |
| 893 | return s |
| 894 | } |
| 895 | |
| 896 | func typesymprefix(prefix string, t *Type) *Sym { |
Russ Cox | c819834 | 2015-03-12 18:45:30 -0400 | [diff] [blame] | 897 | p := prefix + "." + Tconv(t, obj.FmtLeft) |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 898 | s := Pkglookup(p, typepkg) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 899 | |
| 900 | //print("algsym: %s -> %+S\n", p, s); |
| 901 | |
| 902 | return s |
| 903 | } |
| 904 | |
| 905 | func typenamesym(t *Type) *Sym { |
Josh Bleecher Snyder | 25da594 | 2015-03-01 07:54:01 +0000 | [diff] [blame] | 906 | if t == nil || (Isptr[t.Etype] && t.Type == nil) || isideal(t) { |
Håvard Haugen | 3c9fa38 | 2015-08-30 23:10:03 +0200 | [diff] [blame] | 907 | Fatalf("typename %v", t) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 908 | } |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 909 | s := typesym(t) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 910 | if s.Def == nil { |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 911 | n := Nod(ONAME, nil, nil) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 912 | n.Sym = s |
| 913 | n.Type = Types[TUINT8] |
Josh Bleecher Snyder | 75883ba | 2015-04-02 19:58:37 -0700 | [diff] [blame] | 914 | n.Addable = true |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 915 | 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 | |
| 927 | func typename(t *Type) *Node { |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 928 | s := typenamesym(t) |
| 929 | n := Nod(OADDR, s.Def, nil) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 930 | n.Type = Ptrto(s.Def.Type) |
Josh Bleecher Snyder | 75883ba | 2015-04-02 19:58:37 -0700 | [diff] [blame] | 931 | n.Addable = true |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 932 | n.Ullman = 2 |
| 933 | n.Typecheck = 1 |
| 934 | return n |
| 935 | } |
| 936 | |
| 937 | func weaktypesym(t *Type) *Sym { |
Russ Cox | c819834 | 2015-03-12 18:45:30 -0400 | [diff] [blame] | 938 | p := Tconv(t, obj.FmtLeft) |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 939 | s := Pkglookup(p, weaktypepkg) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 940 | |
| 941 | //print("weaktypesym: %s -> %+S\n", p, s); |
| 942 | |
| 943 | return s |
| 944 | } |
| 945 | |
Keith Randall | 00c638d | 2015-06-08 08:42:28 -0700 | [diff] [blame^] | 946 | // isreflexive reports whether t has a reflexive equality operator. |
| 947 | // That is, if x==x for all x of type t. |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 948 | func isreflexive(t *Type) bool { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 949 | 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 Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 967 | return true |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 968 | |
| 969 | case TFLOAT32, |
| 970 | TFLOAT64, |
| 971 | TCOMPLEX64, |
| 972 | TCOMPLEX128, |
| 973 | TINTER: |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 974 | return false |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 975 | |
| 976 | case TARRAY: |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 977 | if Isslice(t) { |
Håvard Haugen | 3c9fa38 | 2015-08-30 23:10:03 +0200 | [diff] [blame] | 978 | Fatalf("slice can't be a map key: %v", t) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 979 | } |
| 980 | return isreflexive(t.Type) |
| 981 | |
| 982 | case TSTRUCT: |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 983 | for t1 := t.Type; t1 != nil; t1 = t1.Down { |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 984 | if !isreflexive(t1.Type) { |
| 985 | return false |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 986 | } |
| 987 | } |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 988 | return true |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 989 | |
| 990 | default: |
Håvard Haugen | 3c9fa38 | 2015-08-30 23:10:03 +0200 | [diff] [blame] | 991 | Fatalf("bad type for map key: %v", t) |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 992 | return false |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 993 | } |
| 994 | } |
| 995 | |
Keith Randall | 00c638d | 2015-06-08 08:42:28 -0700 | [diff] [blame^] | 996 | // needkeyupdate reports whether map updates with t as a key |
| 997 | // need the key to be updated. |
| 998 | func 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 Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1046 | func dtypesym(t *Type) *Sym { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1047 | // 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 Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 1054 | if isideal(t) { |
Håvard Haugen | 3c9fa38 | 2015-08-30 23:10:03 +0200 | [diff] [blame] | 1055 | Fatalf("dtypesym %v", t) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1056 | } |
| 1057 | |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 1058 | s := typesym(t) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1059 | 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 Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 1067 | tbase := t |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1068 | |
Josh Bleecher Snyder | 25da594 | 2015-03-01 07:54:01 +0000 | [diff] [blame] | 1069 | if Isptr[t.Etype] && t.Sym == nil && t.Type.Sym != nil { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1070 | tbase = t.Type |
| 1071 | } |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 1072 | dupok := 0 |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1073 | 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 Cheney | e498181 | 2015-03-10 09:58:01 +1100 | [diff] [blame] | 1082 | if tbase.Sym != nil && !tbase.Local { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1083 | return s |
| 1084 | } |
Josh Bleecher Snyder | 25da594 | 2015-03-01 07:54:01 +0000 | [diff] [blame] | 1085 | if isforw[tbase.Etype] { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1086 | return s |
| 1087 | } |
| 1088 | |
| 1089 | ok: |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 1090 | ot := 0 |
| 1091 | xt := 0 |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1092 | switch t.Etype { |
| 1093 | default: |
| 1094 | ot = dcommontype(s, ot, t) |
Michael Hudson-Doyle | af78482 | 2015-08-21 15:23:57 +1200 | [diff] [blame] | 1095 | xt = ot - 2*Widthptr |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1096 | |
| 1097 | case TARRAY: |
| 1098 | if t.Bound >= 0 { |
| 1099 | // ../../runtime/type.go:/ArrayType |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 1100 | s1 := dtypesym(t.Type) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1101 | |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 1102 | t2 := typ(TARRAY) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1103 | t2.Type = t.Type |
| 1104 | t2.Bound = -1 // slice |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 1105 | s2 := dtypesym(t2) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1106 | ot = dcommontype(s, ot, t) |
Michael Hudson-Doyle | af78482 | 2015-08-21 15:23:57 +1200 | [diff] [blame] | 1107 | xt = ot - 2*Widthptr |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1108 | 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 Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 1113 | s1 := dtypesym(t.Type) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1114 | |
| 1115 | ot = dcommontype(s, ot, t) |
Michael Hudson-Doyle | af78482 | 2015-08-21 15:23:57 +1200 | [diff] [blame] | 1116 | xt = ot - 2*Widthptr |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1117 | ot = dsymptr(s, ot, s1, 0) |
| 1118 | } |
| 1119 | |
| 1120 | // ../../runtime/type.go:/ChanType |
| 1121 | case TCHAN: |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 1122 | s1 := dtypesym(t.Type) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1123 | |
| 1124 | ot = dcommontype(s, ot, t) |
Michael Hudson-Doyle | af78482 | 2015-08-21 15:23:57 +1200 | [diff] [blame] | 1125 | xt = ot - 2*Widthptr |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1126 | ot = dsymptr(s, ot, s1, 0) |
| 1127 | ot = duintptr(s, ot, uint64(t.Chan)) |
| 1128 | |
| 1129 | case TFUNC: |
Russ Cox | c819834 | 2015-03-12 18:45:30 -0400 | [diff] [blame] | 1130 | for t1 := getthisx(t).Type; t1 != nil; t1 = t1.Down { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1131 | dtypesym(t1.Type) |
| 1132 | } |
Dave Cheney | d328756 | 2015-03-09 16:24:07 +1100 | [diff] [blame] | 1133 | isddd := false |
Russ Cox | c819834 | 2015-03-12 18:45:30 -0400 | [diff] [blame] | 1134 | for t1 := getinargx(t).Type; t1 != nil; t1 = t1.Down { |
Dave Cheney | d328756 | 2015-03-09 16:24:07 +1100 | [diff] [blame] | 1135 | isddd = t1.Isddd |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1136 | dtypesym(t1.Type) |
| 1137 | } |
| 1138 | |
Russ Cox | c819834 | 2015-03-12 18:45:30 -0400 | [diff] [blame] | 1139 | for t1 := getoutargx(t).Type; t1 != nil; t1 = t1.Down { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1140 | dtypesym(t1.Type) |
| 1141 | } |
| 1142 | |
| 1143 | ot = dcommontype(s, ot, t) |
Michael Hudson-Doyle | af78482 | 2015-08-21 15:23:57 +1200 | [diff] [blame] | 1144 | xt = ot - 2*Widthptr |
Michael Hudson-Doyle | ac1cdd1 | 2015-04-22 12:41:14 +1200 | [diff] [blame] | 1145 | ot = duint8(s, ot, uint8(obj.Bool2int(isddd))) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1146 | |
| 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 Cox | c819834 | 2015-03-12 18:45:30 -0400 | [diff] [blame] | 1151 | n := t.Thistuple + t.Intuple |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1152 | 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 Cox | c819834 | 2015-03-12 18:45:30 -0400 | [diff] [blame] | 1159 | for t1 := getthisx(t).Type; t1 != nil; t1 = t1.Down { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1160 | ot = dsymptr(s, ot, dtypesym(t1.Type), 0) |
Russ Cox | d7f6d46 | 2015-03-09 00:31:13 -0400 | [diff] [blame] | 1161 | n++ |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1162 | } |
Russ Cox | c819834 | 2015-03-12 18:45:30 -0400 | [diff] [blame] | 1163 | for t1 := getinargx(t).Type; t1 != nil; t1 = t1.Down { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1164 | ot = dsymptr(s, ot, dtypesym(t1.Type), 0) |
Russ Cox | d7f6d46 | 2015-03-09 00:31:13 -0400 | [diff] [blame] | 1165 | n++ |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1166 | } |
Russ Cox | c819834 | 2015-03-12 18:45:30 -0400 | [diff] [blame] | 1167 | for t1 := getoutargx(t).Type; t1 != nil; t1 = t1.Down { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1168 | ot = dsymptr(s, ot, dtypesym(t1.Type), 0) |
Russ Cox | d7f6d46 | 2015-03-09 00:31:13 -0400 | [diff] [blame] | 1169 | n++ |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1170 | } |
| 1171 | |
| 1172 | case TINTER: |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 1173 | m := imethods(t) |
Russ Cox | c819834 | 2015-03-12 18:45:30 -0400 | [diff] [blame] | 1174 | n := 0 |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 1175 | for a := m; a != nil; a = a.link { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1176 | dtypesym(a.type_) |
| 1177 | n++ |
| 1178 | } |
| 1179 | |
| 1180 | // ../../runtime/type.go:/InterfaceType |
| 1181 | ot = dcommontype(s, ot, t) |
| 1182 | |
Michael Hudson-Doyle | af78482 | 2015-08-21 15:23:57 +1200 | [diff] [blame] | 1183 | xt = ot - 2*Widthptr |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1184 | 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 Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 1187 | for a := m; a != nil; a = a.link { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1188 | // ../../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 Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 1197 | s1 := dtypesym(t.Down) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1198 | |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 1199 | s2 := dtypesym(t.Type) |
| 1200 | s3 := dtypesym(mapbucket(t)) |
| 1201 | s4 := dtypesym(hmap(t)) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1202 | ot = dcommontype(s, ot, t) |
Michael Hudson-Doyle | af78482 | 2015-08-21 15:23:57 +1200 | [diff] [blame] | 1203 | xt = ot - 2*Widthptr |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1204 | 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-Doyle | ac1cdd1 | 2015-04-22 12:41:14 +1200 | [diff] [blame] | 1225 | ot = duint8(s, ot, uint8(obj.Bool2int(isreflexive(t.Down)))) |
Keith Randall | 00c638d | 2015-06-08 08:42:28 -0700 | [diff] [blame^] | 1226 | ot = duint8(s, ot, uint8(obj.Bool2int(needkeyupdate(t.Down)))) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1227 | |
Josh Bleecher Snyder | b09925b | 2015-04-01 09:38:44 -0700 | [diff] [blame] | 1228 | case TPTR32, TPTR64: |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1229 | 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 Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 1237 | s1 := dtypesym(t.Type) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1238 | |
| 1239 | ot = dcommontype(s, ot, t) |
Michael Hudson-Doyle | af78482 | 2015-08-21 15:23:57 +1200 | [diff] [blame] | 1240 | xt = ot - 2*Widthptr |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1241 | ot = dsymptr(s, ot, s1, 0) |
| 1242 | |
| 1243 | // ../../runtime/type.go:/StructType |
| 1244 | // for security, only the exported fields. |
| 1245 | case TSTRUCT: |
Russ Cox | c819834 | 2015-03-12 18:45:30 -0400 | [diff] [blame] | 1246 | n := 0 |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1247 | |
Russ Cox | c819834 | 2015-03-12 18:45:30 -0400 | [diff] [blame] | 1248 | for t1 := t.Type; t1 != nil; t1 = t1.Down { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1249 | dtypesym(t1.Type) |
| 1250 | n++ |
| 1251 | } |
| 1252 | |
| 1253 | ot = dcommontype(s, ot, t) |
Michael Hudson-Doyle | af78482 | 2015-08-21 15:23:57 +1200 | [diff] [blame] | 1254 | xt = ot - 2*Widthptr |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1255 | 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 Cox | c819834 | 2015-03-12 18:45:30 -0400 | [diff] [blame] | 1258 | for t1 := t.Type; t1 != nil; t1 = t1.Down { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1259 | // ../../runtime/type.go:/structField |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 1260 | if t1.Sym != nil && t1.Embedded == 0 { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1261 | 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-Doyle | 029c7bb | 2015-04-18 08:14:08 +1200 | [diff] [blame] | 1283 | ggloblsym(s, int32(ot), int16(dupok|obj.RODATA)) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1284 | |
| 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-Doyle | 2f0828ef | 2015-03-29 23:11:47 +0000 | [diff] [blame] | 1292 | 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 Garipov | 7f9f70e | 2015-06-11 16:49:38 +0300 | [diff] [blame] | 1299 | // .PtrTo() on the reflect.Type for T returns this type data and |
Michael Hudson-Doyle | 2f0828ef | 2015-03-29 23:11:47 +0000 | [diff] [blame] | 1300 | // 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 Day | e1c1fa2 | 2014-12-23 15:19:30 +1100 | [diff] [blame] | 1306 | case TARRAY, TCHAN, TFUNC, TMAP: |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 1307 | slink := typelinksym(t) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1308 | dsymptr(slink, 0, s, 0) |
Michael Hudson-Doyle | 029c7bb | 2015-04-18 08:14:08 +1200 | [diff] [blame] | 1309 | ggloblsym(slink, int32(Widthptr), int16(dupok|obj.RODATA)) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1310 | } |
| 1311 | } |
| 1312 | |
| 1313 | return s |
| 1314 | } |
| 1315 | |
| 1316 | func dumptypestructs() { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1317 | var n *Node |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1318 | |
| 1319 | // copy types from externdcl list to signatlist |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 1320 | for l := externdcl; l != nil; l = l.Next { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1321 | n = l.N |
| 1322 | if n.Op != OTYPE { |
| 1323 | continue |
| 1324 | } |
| 1325 | signatlist = list(signatlist, n) |
| 1326 | } |
| 1327 | |
| 1328 | // process signatlist |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 1329 | var t *Type |
| 1330 | for l := signatlist; l != nil; l = l.Next { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1331 | 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 Cox | d0b59de | 2015-03-02 16:21:15 -0500 | [diff] [blame] | 1343 | for _, p := range pkgs { |
Marvin Stenger | e03c789 | 2015-09-08 05:46:31 +0200 | [diff] [blame] | 1344 | if p.Direct { |
Russ Cox | d0b59de | 2015-03-02 16:21:15 -0500 | [diff] [blame] | 1345 | dimportpath(p) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1346 | } |
| 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 Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 1356 | for i := 1; i <= TBOOL; i++ { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1357 | 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 Cox | bed1f90 | 2015-03-02 16:03:26 -0500 | [diff] [blame] | 1374 | dimportpath(mkpkg("main")) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1375 | } |
| 1376 | } |
| 1377 | |
| 1378 | func dalgsym(t *Type) *Sym { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1379 | var s *Sym |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1380 | var hashfunc *Sym |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1381 | var eqfunc *Sym |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1382 | |
| 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 Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 1388 | p := fmt.Sprintf(".alg%d", t.Width) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1389 | |
| 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 Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 1402 | ot := 0 |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1403 | 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 Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 1420 | hash := typesymprefix(".hash", t) |
| 1421 | eq := typesymprefix(".eq", t) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1422 | 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 Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 1437 | ot := 0 |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1438 | |
| 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 Cox | 512f75e | 2015-05-08 01:43:18 -0400 | [diff] [blame] | 1445 | // 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 Cox | 80ec711 | 2015-06-07 22:47:59 -0400 | [diff] [blame] | 1468 | // We used to use 16 because the GC programs do have some constant overhead |
Russ Cox | 512f75e | 2015-05-08 01:43:18 -0400 | [diff] [blame] | 1469 | // to get started, and processing 128 pointers seems to be enough to |
| 1470 | // amortize that overhead well. |
Russ Cox | 80ec711 | 2015-06-07 22:47:59 -0400 | [diff] [blame] | 1471 | // |
| 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 | // |
| 1478 | const maxPtrmaskBytes = 2048 |
Russ Cox | 512f75e | 2015-05-08 01:43:18 -0400 | [diff] [blame] | 1479 | |
| 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. |
| 1483 | func 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 Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1488 | } |
| 1489 | |
Russ Cox | 512f75e | 2015-05-08 01:43:18 -0400 | [diff] [blame] | 1490 | useGCProg = true |
| 1491 | sym, ptrdata = dgcprog(t) |
| 1492 | return |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1493 | } |
| 1494 | |
Russ Cox | 512f75e | 2015-05-08 01:43:18 -0400 | [diff] [blame] | 1495 | // dgcptrmask emits and returns the symbol containing a pointer mask for type t. |
| 1496 | func 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. |
| 1515 | func fillptrmask(t *Type, ptrmask []byte) { |
| 1516 | for i := range ptrmask { |
| 1517 | ptrmask[i] = 0 |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1518 | } |
| 1519 | if !haspointers(t) { |
| 1520 | return |
| 1521 | } |
| 1522 | |
Russ Cox | 512f75e | 2015-05-08 01:43:18 -0400 | [diff] [blame] | 1523 | vec := bvalloc(8 * int32(len(ptrmask))) |
Russ Cox | 6d8a147 | 2015-04-28 00:28:47 -0400 | [diff] [blame] | 1524 | xoffset := int64(0) |
Russ Cox | 4d0f3a1 | 2015-04-27 22:45:57 -0400 | [diff] [blame] | 1525 | onebitwalktype1(t, &xoffset, vec) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1526 | |
Russ Cox | 54af9a3 | 2015-05-04 22:53:54 -0400 | [diff] [blame] | 1527 | nptr := typeptrdata(t) / int64(Widthptr) |
Russ Cox | 6d8a147 | 2015-04-28 00:28:47 -0400 | [diff] [blame] | 1528 | for i := int64(0); i < nptr; i++ { |
| 1529 | if bvget(vec, int32(i)) == 1 { |
Russ Cox | 512f75e | 2015-05-08 01:43:18 -0400 | [diff] [blame] | 1530 | ptrmask[i/8] |= 1 << (uint(i) % 8) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1531 | } |
| 1532 | } |
| 1533 | } |
| 1534 | |
Russ Cox | 512f75e | 2015-05-08 01:43:18 -0400 | [diff] [blame] | 1535 | // 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. |
| 1539 | func dgcprog(t *Type) (*Sym, int64) { |
| 1540 | dowidth(t) |
| 1541 | if t.Width == BADWIDTH { |
Håvard Haugen | 3c9fa38 | 2015-08-30 23:10:03 +0200 | [diff] [blame] | 1542 | Fatalf("dgcprog: %v badwidth", t) |
Russ Cox | 512f75e | 2015-05-08 01:43:18 -0400 | [diff] [blame] | 1543 | } |
| 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 Haugen | 3c9fa38 | 2015-08-30 23:10:03 +0200 | [diff] [blame] | 1551 | Fatalf("dgcprog: %v: offset=%d but ptrdata=%d size=%d", t, offset, ptrdata, t.Width) |
Russ Cox | 512f75e | 2015-05-08 01:43:18 -0400 | [diff] [blame] | 1552 | } |
| 1553 | return sym, offset |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1554 | } |
| 1555 | |
Russ Cox | 512f75e | 2015-05-08 01:43:18 -0400 | [diff] [blame] | 1556 | type GCProg struct { |
| 1557 | sym *Sym |
| 1558 | symoff int |
| 1559 | w gcprog.Writer |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1560 | } |
| 1561 | |
Russ Cox | 512f75e | 2015-05-08 01:43:18 -0400 | [diff] [blame] | 1562 | var Debug_gcprog int // set by -d gcprog |
| 1563 | |
| 1564 | func (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 Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1572 | } |
| 1573 | |
Russ Cox | 512f75e | 2015-05-08 01:43:18 -0400 | [diff] [blame] | 1574 | func (p *GCProg) writeByte(x byte) { |
| 1575 | p.symoff = duint8(p.sym, p.symoff, x) |
| 1576 | } |
| 1577 | |
| 1578 | func (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 | |
| 1587 | func (p *GCProg) emit(t *Type, offset int64) { |
| 1588 | dowidth(t) |
| 1589 | if !haspointers(t) { |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1590 | return |
| 1591 | } |
Russ Cox | 512f75e | 2015-05-08 01:43:18 -0400 | [diff] [blame] | 1592 | if t.Width == int64(Widthptr) { |
| 1593 | p.w.Ptr(offset / int64(Widthptr)) |
| 1594 | return |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1595 | } |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1596 | switch t.Etype { |
Russ Cox | 512f75e | 2015-05-08 01:43:18 -0400 | [diff] [blame] | 1597 | default: |
Håvard Haugen | 3c9fa38 | 2015-08-30 23:10:03 +0200 | [diff] [blame] | 1598 | Fatalf("GCProg.emit: unexpected type %v", t) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1599 | |
| 1600 | case TSTRING: |
Russ Cox | 512f75e | 2015-05-08 01:43:18 -0400 | [diff] [blame] | 1601 | p.w.Ptr(offset / int64(Widthptr)) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1602 | |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1603 | case TINTER: |
Russ Cox | 512f75e | 2015-05-08 01:43:18 -0400 | [diff] [blame] | 1604 | p.w.Ptr(offset / int64(Widthptr)) |
| 1605 | p.w.Ptr(offset/int64(Widthptr) + 1) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1606 | |
| 1607 | case TARRAY: |
Russ Cox | dc7b54b | 2015-02-17 22:13:49 -0500 | [diff] [blame] | 1608 | if Isslice(t) { |
Russ Cox | 512f75e | 2015-05-08 01:43:18 -0400 | [diff] [blame] | 1609 | p.w.Ptr(offset / int64(Widthptr)) |
| 1610 | return |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1611 | } |
Russ Cox | 512f75e | 2015-05-08 01:43:18 -0400 | [diff] [blame] | 1612 | if t.Bound == 0 { |
| 1613 | // should have been handled by haspointers check above |
Håvard Haugen | 3c9fa38 | 2015-08-30 23:10:03 +0200 | [diff] [blame] | 1614 | Fatalf("GCProg.emit: empty array") |
Russ Cox | 512f75e | 2015-05-08 01:43:18 -0400 | [diff] [blame] | 1615 | } |
| 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 Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1635 | |
| 1636 | case TSTRUCT: |
Russ Cox | 382b44e | 2015-02-23 16:07:24 -0500 | [diff] [blame] | 1637 | for t1 := t.Type; t1 != nil; t1 = t1.Down { |
Russ Cox | 512f75e | 2015-05-08 01:43:18 -0400 | [diff] [blame] | 1638 | p.emit(t1.Type, offset+t1.Width) |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1639 | } |
Russ Cox | 8c195bd | 2015-02-13 14:40:36 -0500 | [diff] [blame] | 1640 | } |
| 1641 | } |