diff options
Diffstat (limited to 'src/cmd/gc/reflect.c')
-rw-r--r-- | src/cmd/gc/reflect.c | 149 |
1 files changed, 134 insertions, 15 deletions
diff --git a/src/cmd/gc/reflect.c b/src/cmd/gc/reflect.c index 0a8aa8d7a..dbb447e4e 100644 --- a/src/cmd/gc/reflect.c +++ b/src/cmd/gc/reflect.c @@ -125,6 +125,8 @@ mapbucket(Type *t) keytype = t->down; valtype = t->type; + dowidth(keytype); + dowidth(valtype); if(keytype->width > MAXKEYSIZE) keytype = ptrto(keytype); if(valtype->width > MAXVALSIZE) @@ -143,6 +145,11 @@ mapbucket(Type *t) overflowfield->sym = mal(sizeof(Sym)); // not important but needs to be set to give this type a name overflowfield->sym->name = "overflow"; offset += widthptr; + + // The keys are padded to the native integer alignment. + // This is usually the same as widthptr; the exception (as usual) is nacl/amd64. + if(widthreg > widthptr) + offset += widthreg - widthptr; keysfield = typ(TFIELD); keysfield->type = typ(TARRAY); @@ -173,6 +180,7 @@ mapbucket(Type *t) bucket->width = offset; bucket->local = t->local; t->bucket = bucket; + bucket->map = t; return bucket; } @@ -229,10 +237,89 @@ hmap(Type *t) h->width = offset; h->local = t->local; t->hmap = h; - h->hmap = t; + h->map = t; return h; } +Type* +hiter(Type *t) +{ + int32 n, off; + Type *field[7]; + Type *i; + + if(t->hiter != T) + return t->hiter; + + // build a struct: + // hash_iter { + // key *Key + // val *Value + // t *MapType + // h *Hmap + // buckets *Bucket + // bptr *Bucket + // other [4]uintptr + // } + // must match ../../pkg/runtime/hashmap.c:hash_iter. + field[0] = typ(TFIELD); + field[0]->type = ptrto(t->down); + field[0]->sym = mal(sizeof(Sym)); + field[0]->sym->name = "key"; + + field[1] = typ(TFIELD); + field[1]->type = ptrto(t->type); + field[1]->sym = mal(sizeof(Sym)); + field[1]->sym->name = "val"; + + field[2] = typ(TFIELD); + field[2]->type = ptrto(types[TUINT8]); // TODO: is there a Type type? + field[2]->sym = mal(sizeof(Sym)); + field[2]->sym->name = "t"; + + field[3] = typ(TFIELD); + field[3]->type = ptrto(hmap(t)); + field[3]->sym = mal(sizeof(Sym)); + field[3]->sym->name = "h"; + + field[4] = typ(TFIELD); + field[4]->type = ptrto(mapbucket(t)); + field[4]->sym = mal(sizeof(Sym)); + field[4]->sym->name = "buckets"; + + field[5] = typ(TFIELD); + field[5]->type = ptrto(mapbucket(t)); + field[5]->sym = mal(sizeof(Sym)); + field[5]->sym->name = "bptr"; + + // all other non-pointer fields + field[6] = typ(TFIELD); + field[6]->type = typ(TARRAY); + field[6]->type->type = types[TUINTPTR]; + field[6]->type->bound = 4; + field[6]->type->width = 4 * widthptr; + field[6]->sym = mal(sizeof(Sym)); + field[6]->sym->name = "other"; + + // build iterator struct holding the above fields + i = typ(TSTRUCT); + i->noalg = 1; + i->type = field[0]; + off = 0; + for(n = 0; n < 6; n++) { + field[n]->down = field[n+1]; + field[n]->width = off; + off += field[n]->type->width; + } + field[6]->down = T; + off += field[6]->type->width; + if(off != 10 * widthptr) + yyerror("hash_iter size not correct %d %d", off, 10 * widthptr); + t->hiter = i; + i->map = t; + return i; +} + /* * f is method type, with receiver. * return function type, receiver as first argument (or not). @@ -396,9 +483,8 @@ imethods(Type *t) last->link = a; last = a; - // Compiler can only refer to wrappers for - // named interface types and non-blank methods. - if(t->sym == S || isblanksym(method)) + // Compiler can only refer to wrappers for non-blank methods. + if(isblanksym(method)) continue; // NOTE(rsc): Perhaps an oversight that @@ -620,6 +706,10 @@ haspointers(Type *t) ret = 1; break; } + if(t->bound == 0) { // empty array + ret = 0; + break; + } ret = haspointers(t->type); break; case TSTRUCT: @@ -656,7 +746,7 @@ static int dcommontype(Sym *s, int ot, Type *t) { int i, alg, sizeofAlg; - Sym *sptr, *algsym; + Sym *sptr, *algsym, *zero; static Sym *algarray; char *p; @@ -677,6 +767,18 @@ dcommontype(Sym *s, int ot, Type *t) else sptr = weaktypesym(ptrto(t)); + // All (non-reflect-allocated) Types share the same zero object. + // Each place in the compiler where a pointer to the zero object + // might be returned by a runtime call (map access return value, + // 2-arg type cast) declares the size of the zerovalue it needs. + // The linker magically takes the max of all the sizes. + zero = pkglookup("zerovalue", runtimepkg); + + // We use size 0 here so we get the pointer to the zero value, + // but don't allocate space for the zero value unless we need it. + // TODO: how do we get this symbol into bss? We really want + // a read-only bss, but I don't think such a thing exists. + // ../../pkg/reflect/type.go:/^type.commonType // actual type structure // type commonType struct { @@ -691,6 +793,7 @@ dcommontype(Sym *s, int ot, Type *t) // string *string // *extraType // ptrToThis *Type + // zero unsafe.Pointer // } ot = duintptr(s, ot, t->width); ot = duint32(s, ot, typehash(t)); @@ -728,6 +831,7 @@ dcommontype(Sym *s, int ot, Type *t) ot += widthptr; ot = dsymptr(s, ot, sptr, 0); // ptrto type + ot = dsymptr(s, ot, zero, 0); // ptr to zero value return ot; } @@ -893,7 +997,7 @@ ok: switch(t->etype) { default: ot = dcommontype(s, ot, t); - xt = ot - 2*widthptr; + xt = ot - 3*widthptr; break; case TARRAY: @@ -905,7 +1009,7 @@ ok: t2->bound = -1; // slice s2 = dtypesym(t2); ot = dcommontype(s, ot, t); - xt = ot - 2*widthptr; + xt = ot - 3*widthptr; ot = dsymptr(s, ot, s1, 0); ot = dsymptr(s, ot, s2, 0); ot = duintptr(s, ot, t->bound); @@ -913,7 +1017,7 @@ ok: // ../../pkg/runtime/type.go:/SliceType s1 = dtypesym(t->type); ot = dcommontype(s, ot, t); - xt = ot - 2*widthptr; + xt = ot - 3*widthptr; ot = dsymptr(s, ot, s1, 0); } break; @@ -922,7 +1026,7 @@ ok: // ../../pkg/runtime/type.go:/ChanType s1 = dtypesym(t->type); ot = dcommontype(s, ot, t); - xt = ot - 2*widthptr; + xt = ot - 3*widthptr; ot = dsymptr(s, ot, s1, 0); ot = duintptr(s, ot, t->chan); break; @@ -939,7 +1043,7 @@ ok: dtypesym(t1->type); ot = dcommontype(s, ot, t); - xt = ot - 2*widthptr; + xt = ot - 3*widthptr; ot = duint8(s, ot, isddd); // two slice headers: in and out. @@ -971,7 +1075,7 @@ ok: // ../../pkg/runtime/type.go:/InterfaceType ot = dcommontype(s, ot, t); - xt = ot - 2*widthptr; + xt = ot - 3*widthptr; ot = dsymptr(s, ot, s, ot+widthptr+2*widthint); ot = duintxx(s, ot, n, widthint); ot = duintxx(s, ot, n, widthint); @@ -990,7 +1094,7 @@ ok: s3 = dtypesym(mapbucket(t)); s4 = dtypesym(hmap(t)); ot = dcommontype(s, ot, t); - xt = ot - 2*widthptr; + xt = ot - 3*widthptr; ot = dsymptr(s, ot, s1, 0); ot = dsymptr(s, ot, s2, 0); ot = dsymptr(s, ot, s3, 0); @@ -1007,7 +1111,7 @@ ok: // ../../pkg/runtime/type.go:/PtrType s1 = dtypesym(t->type); ot = dcommontype(s, ot, t); - xt = ot - 2*widthptr; + xt = ot - 3*widthptr; ot = dsymptr(s, ot, s1, 0); break; @@ -1020,7 +1124,7 @@ ok: n++; } ot = dcommontype(s, ot, t); - xt = ot - 2*widthptr; + xt = ot - 3*widthptr; ot = dsymptr(s, ot, s, ot+widthptr+2*widthint); ot = duintxx(s, ot, n, widthint); ot = duintxx(s, ot, n, widthint); @@ -1218,7 +1322,22 @@ dgcsym1(Sym *s, int ot, Type *t, vlong *off, int stack_size) // NOTE: Any changes here need to be made to reflect.PtrTo as well. if(*off % widthptr != 0) fatal("dgcsym1: invalid alignment, %T", t); - if(!haspointers(t->type) || t->type->etype == TUINT8) { + + // NOTE(rsc): Emitting GC_APTR here for *nonptrtype + // (pointer to non-pointer-containing type) means that + // we do not record 'nonptrtype' and instead tell the + // garbage collector to look up the type of the memory in + // type information stored in the heap. In effect we are telling + // the collector "we don't trust our information - use yours". + // It's not completely clear why we want to do this. + // It does have the effect that if you have a *SliceHeader and a *[]int + // pointing at the same actual slice header, *SliceHeader will not be + // used as an authoritative type for the memory, which is good: + // if the collector scanned the memory as type *SliceHeader, it would + // see no pointers inside but mark the block as scanned, preventing + // the seeing of pointers when we followed the *[]int pointer. + // Perhaps that kind of situation is the rationale. + if(!haspointers(t->type)) { ot = duintptr(s, ot, GC_APTR); ot = duintptr(s, ot, *off); } else { |