summaryrefslogtreecommitdiff
path: root/src/cmd/gc/reflect.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/gc/reflect.c')
-rw-r--r--src/cmd/gc/reflect.c149
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 {