runtime: use new reflect data structures (CL 31107)
in place of sigi, sigt.
R=ken
OCL=31118
CL=31277
diff --git a/src/pkg/runtime/Makefile b/src/pkg/runtime/Makefile
index 4e932b0..f3eb404 100644
--- a/src/pkg/runtime/Makefile
+++ b/src/pkg/runtime/Makefile
@@ -70,6 +70,7 @@
sys.$O\
thread.$O\
traceback.$O\
+ type.$O\
$(OFILES_$(GOARCH))\
HFILES=\
diff --git a/src/pkg/runtime/iface.c b/src/pkg/runtime/iface.c
index 6c933b1..cc9eb7e 100644
--- a/src/pkg/runtime/iface.c
+++ b/src/pkg/runtime/iface.c
@@ -3,173 +3,64 @@
// license that can be found in the LICENSE file.
#include "runtime.h"
-
-int32 iface_debug = 0;
-
-typedef struct Sigt Sigt;
-typedef struct Sigi Sigi;
-typedef struct Itype Itype;
-
-/*
- * the layout of Iface, Sigt and Sigi are known to the compiler
- */
-struct Sigt
-{
- byte* name; // name of basic type
- Sigt* link; // for linking into hash tables
- uint32 thash; // hash of type
- uint32 mhash; // hash of methods
- uint16 width; // width of base type in bytes
- uint16 alg; // algorithm
- // note: on amd64 there is a 32-bit pad here.
- struct {
- byte* fname;
- uint32 fhash; // hash of type
- uint32 offset; // offset of substruct
- void (*fun)(void);
- } meth[1]; // one or more - last name is nil
-};
-
-struct Sigi
-{
- byte* name;
- uint32 hash;
- uint32 size; // number of methods
- struct {
- byte* fname;
- uint32 fhash;
- uint32 perm; // location of fun in Sigt
- } meth[1]; // [size+1] - last name is nil
-};
-
-struct Itype
-{
- Sigi* sigi;
- Sigt* sigt;
- Itype* link;
- int32 bad;
- int32 unused;
- void (*fun[])(void);
-};
-
-static Iface niliface;
-static Eface nileface;
-
-static Itype* hash[1009];
-static Lock ifacelock;
-
-Sigi sigi·empty[2] = { (byte*)"interface { }" };
-
-static void
-printsigi(Sigi *si)
-{
- int32 i;
- byte *name;
-
- sys·printpointer(si);
- prints("{");
- prints((int8*)si->name);
- prints(":");
- for(i=0;; i++) {
- name = si->meth[i].fname;
- if(name == nil)
- break;
- prints("[");
- sys·printint(i);
- prints("]\"");
- prints((int8*)name);
- prints("\"");
- sys·printint(si->meth[i].fhash%999);
- prints("/");
- sys·printint(si->meth[i].perm);
- }
- prints("}");
-}
-
-static void
-printsigt(Sigt *st)
-{
- int32 i;
- byte *name;
-
- sys·printpointer(st);
- prints("{");
- prints((int8*)st->name);
- prints(":");
- sys·printint(st->thash%999); // type hash
- prints(",");
- sys·printint(st->mhash%999); // method hash
- prints(",");
- sys·printint(st->width); // width
- prints(",");
- sys·printint(st->alg); // algorithm
- for(i=0;; i++) {
- name = st->meth[i].fname;
- if(name == nil)
- break;
- prints("[");
- sys·printint(i);
- prints("]\"");
- prints((int8*)name);
- prints("\"");
- sys·printint(st->meth[i].fhash%999);
- prints("/");
- sys·printint(st->meth[i].offset);
- prints("/");
- sys·printpointer(st->meth[i].fun);
- }
- prints("}");
-}
+#include "type.h"
static void
printiface(Iface i)
{
- prints("(");
- sys·printpointer(i.type);
- prints(",");
- sys·printpointer(i.data);
- prints(")");
+ printf("(%p,%p)", i.tab, i.data);
}
static void
printeface(Eface e)
{
- prints("(");
- sys·printpointer(e.type);
- prints(",");
- sys·printpointer(e.data);
- prints(")");
+ printf("(%p,%p)", e.type, e.data);
}
-static Itype*
-itype(Sigi *si, Sigt *st, int32 canfail)
+/*
+ * layout of Itab known to compilers
+ */
+struct Itab
+{
+ InterfaceType* inter;
+ Type* type;
+ Itab* link;
+ int32 bad;
+ int32 unused;
+ void (*fun[])(void);
+};
+
+static Itab* hash[1009];
+static Lock ifacelock;
+
+static Itab*
+itab(InterfaceType *inter, Type *type, int32 canfail)
{
int32 locked;
- int32 nt, ni;
+ int32 ni;
+ Method *t, *et;
+ IMethod *i, *ei;
uint32 ihash, h;
- byte *sname, *iname;
- Itype *m;
+ String *iname;
+ Itab *m;
+ UncommonType *x;
- if(si->size == 0)
- throw("internal error - misuse of itype");
+ if(inter->mhdr.nel == 0)
+ throw("internal error - misuse of itab");
// easy case
- if(st->meth[0].fname == nil) {
+ x = type->x;
+ if(x == nil) {
if(canfail)
return nil;
- iname = si->meth[0].fname;
- goto throw1;
+ iname = inter->m[0].name;
+ goto throw;
}
// compiler has provided some good hash codes for us.
- h = 0;
- if(si)
- h += si->hash;
- if(st) {
- h += st->thash;
- h += st->mhash;
- }
-
+ h = inter->hash;
+ h += 17 * type->hash;
+ // TODO(rsc): h += 23 * x->mhash ?
h %= nelem(hash);
// look twice - once without lock, once with.
@@ -178,7 +69,7 @@
if(locked)
lock(&ifacelock);
for(m=hash[h]; m!=nil; m=m->link) {
- if(m->sigi == si && m->sigt == st) {
+ if(m->inter == inter && m->type == type) {
if(m->bad) {
m = nil;
if(!canfail) {
@@ -188,8 +79,8 @@
// the cached result doesn't record which
// interface function was missing, so jump
// down to the interface check, which will
- // give a better error.
- goto throw;
+ // do more work but give a better error.
+ goto search;
}
}
if(locked)
@@ -199,69 +90,60 @@
}
}
- ni = si->size;
- m = malloc(sizeof(*m) + ni*sizeof(m->fun[0]));
- m->sigi = si;
- m->sigt = st;
+ ni = inter->mhdr.nel;
+ m = malloc(sizeof(*m) + ni*sizeof m->fun[0]);
+ m->inter = inter;
+ m->type = type;
-throw:
- nt = 0;
- for(ni=0;; ni++) {
- iname = si->meth[ni].fname;
- if(iname == nil)
- break;
-
- // pick up next name from
- // interface signature
- ihash = si->meth[ni].fhash;
-
- for(;; nt++) {
- // pick up and compare next name
- // from structure signature
- sname = st->meth[nt].fname;
- if(sname == nil) {
+search:
+ // both inter and type have method sorted by hash,
+ // so can iterate over both in lock step;
+ // the loop is O(ni+nt) not O(ni*nt).
+ i = inter->m;
+ ei = i + inter->mhdr.nel;
+ t = x->m;
+ et = t + x->mhdr.nel;
+ for(; i < ei; i++) {
+ ihash = i->hash;
+ iname = i->name;
+ for(;; t++) {
+ if(t >= et) {
if(!canfail) {
- throw1:
- printf("cannot convert type %s to interface %s: missing method %s\n",
- st->name, si->name, iname);
- if(iface_debug) {
- prints("interface");
- printsigi(si);
- prints("\ntype");
- printsigt(st);
- prints("\n");
- }
+ throw:
+ // didn't find method
+ printf("%S is not %S: missing method %S\n",
+ *type->string, *inter->string, *iname);
throw("interface conversion");
return nil; // not reached
}
m->bad = 1;
- m->link = hash[h];
- hash[h] = m;
- if(locked)
- unlock(&ifacelock);
- return nil;
+ goto out;
}
- if(ihash == st->meth[nt].fhash && strcmp(sname, iname) == 0)
+ if(t->hash == ihash && t->name == iname)
break;
}
- m->fun[si->meth[ni].perm] = st->meth[nt].fun;
+ if(m)
+ m->fun[i->perm] = t->ifn;
}
+
+out:
m->link = hash[h];
hash[h] = m;
if(locked)
unlock(&ifacelock);
-
+ if(m->bad)
+ return nil;
return m;
}
static void
-copyin(Sigt *st, void *src, void **dst)
+copyin(Type *t, void *src, void **dst)
{
int32 wid, alg;
void *p;
- wid = st->width;
- alg = st->alg;
+ wid = t->size;
+ alg = t->alg;
if(wid <= sizeof(*dst))
algarray[alg].copy(wid, dst, src);
@@ -273,12 +155,12 @@
}
static void
-copyout(Sigt *st, void **src, void *dst)
+copyout(Type *t, void **src, void *dst)
{
int32 wid, alg;
- wid = st->width;
- alg = st->alg;
+ wid = t->size;
+ alg = t->alg;
if(wid <= sizeof(*src))
algarray[alg].copy(wid, dst, src);
@@ -286,132 +168,123 @@
algarray[alg].copy(wid, dst, *src);
}
-// ifaceT2I(sigi *byte, sigt *byte, elem any) (ret any);
+// ifaceT2I(sigi *byte, sigt *byte, elem any) (ret Iface);
#pragma textflag 7
void
-sys·ifaceT2I(Sigi *si, Sigt *st, ...)
+sys·ifaceT2I(InterfaceType *inter, Type *t, ...)
{
byte *elem;
Iface *ret;
int32 wid;
- elem = (byte*)(&st+1);
- wid = st->width;
- ret = (Iface*)(elem + rnd(wid, sizeof(uintptr)));
-
- ret->type = itype(si, st, 0);
- copyin(st, elem, &ret->data);
+ elem = (byte*)(&t+1);
+ wid = t->size;
+ ret = (Iface*)(elem + rnd(wid, Structrnd));
+ ret->tab = itab(inter, t, 0);
+ copyin(t, elem, &ret->data);
}
-// ifaceT2E(sigt *byte, elem any) (ret any);
+// ifaceT2E(sigt *byte, elem any) (ret Eface);
#pragma textflag 7
void
-sys·ifaceT2E(Sigt *st, ...)
+sys·ifaceT2E(Type *t, ...)
{
byte *elem;
Eface *ret;
int32 wid;
- elem = (byte*)(&st+1);
- wid = st->width;
- ret = (Eface*)(elem + rnd(wid, sizeof(uintptr)));
+ elem = (byte*)(&t+1);
+ wid = t->size;
+ ret = (Eface*)(elem + rnd(wid, Structrnd));
- ret->type = st;
- copyin(st, elem, &ret->data);
+ ret->type = t;
+ copyin(t, elem, &ret->data);
}
// ifaceI2T(sigt *byte, iface any) (ret any);
#pragma textflag 7
void
-sys·ifaceI2T(Sigt *st, Iface i, ...)
+sys·ifaceI2T(Type *t, Iface i, ...)
{
- Itype *im;
+ Itab *tab;
byte *ret;
ret = (byte*)(&i+1);
-
- im = i.type;
- if(im == nil) {
- printf("interface is nil, not %s\n", st->name);
+ tab = i.tab;
+ if(tab == nil) {
+ printf("interface is nil, not %S\n", *t->string);
throw("interface conversion");
}
- if(im->sigt != st) {
- printf("%s is %s, not %s\n", im->sigi->name, im->sigt->name, st->name);
+ if(tab->type != t) {
+ printf("%S is %S, not %S\n", *tab->inter->string, *tab->type->string, *t->string);
throw("interface conversion");
}
- copyout(st, &i.data, ret);
+ copyout(t, &i.data, ret);
}
-// ifaceI2T2(sigt *byte, iface any) (ret any, ok bool);
+// ifaceI2T2(sigt *byte, i Iface) (ret any, ok bool);
#pragma textflag 7
void
-sys·ifaceI2T2(Sigt *st, Iface i, ...)
+sys·ifaceI2T2(Type *t, Iface i, ...)
{
byte *ret;
bool *ok;
- Itype *im;
int32 wid;
ret = (byte*)(&i+1);
- wid = st->width;
+ wid = t->size;
ok = (bool*)(ret+rnd(wid, 1));
- im = i.type;
- if(im == nil || im->sigt != st) {
+ if(i.tab == nil || i.tab->type != t) {
*ok = false;
sys·memclr(ret, wid);
return;
}
*ok = true;
- copyout(st, &i.data, ret);
+ copyout(t, &i.data, ret);
}
-// ifaceE2T(sigt *byte, iface any) (ret any);
+// ifaceE2T(sigt *byte, e Eface) (ret any);
#pragma textflag 7
void
-sys·ifaceE2T(Sigt *st, Eface e, ...)
+sys·ifaceE2T(Type *t, Eface e, ...)
{
- Sigt *t;
byte *ret;
ret = (byte*)(&e+1);
- t = e.type;
- if(t == nil) {
- printf("interface is nil, not %s\n", st->name);
+ if(e.type != t) {
+ if(e.type == nil)
+ printf("interface is nil, not %S\n", *t->string);
+ else
+ printf("interface is %S, not %S\n", *e.type->string, *t->string);
throw("interface conversion");
}
- if(t != st) {
- printf("interface is %s, not %s\n", t->name, st->name);
- throw("interface conversion");
- }
- copyout(st, &e.data, ret);
+ copyout(t, &e.data, ret);
}
// ifaceE2T2(sigt *byte, iface any) (ret any, ok bool);
#pragma textflag 7
void
-sys·ifaceE2T2(Sigt *st, Eface e, ...)
+sys·ifaceE2T2(Type *t, Eface e, ...)
{
byte *ret;
bool *ok;
- Sigt *t;
int32 wid;
ret = (byte*)(&e+1);
- wid = st->width;
+ wid = t->size;
ok = (bool*)(ret+rnd(wid, 1));
- t = e.type;
- if(t != st) {
+ if(t != e.type) {
*ok = false;
sys·memclr(ret, wid);
return;
}
*ok = true;
- copyout(st, &e.data, ret);
+ copyout(t, &e.data, ret);
}
// ifaceI2E(sigi *byte, iface any) (ret any);
@@ -419,33 +292,35 @@
void
sys·ifaceI2E(Iface i, Eface ret)
{
- Itype *im;
+ Itab *tab;
ret.data = i.data;
- im = i.type;
- if(im == nil)
+ tab = i.tab;
+ if(tab == nil)
ret.type = nil;
else
- ret.type = im->sigt;
+ ret.type = tab->type;
FLUSH(&ret);
}
// ifaceI2I(sigi *byte, iface any) (ret any);
-// called only for implicit (no type assertion) conversions
+// called only for implicit (no type assertion) conversions.
+// converting nil is okay.
void
-sys·ifaceI2I(Sigi *si, Iface i, Iface ret)
+sys·ifaceI2I(InterfaceType *inter, Iface i, Iface ret)
{
- Itype *im;
+ Itab *tab;
- im = i.type;
- if(im == nil) {
+ tab = i.tab;
+ if(tab == nil) {
// If incoming interface is uninitialized (zeroed)
// make the outgoing interface zeroed as well.
- ret = niliface;
+ ret.tab = nil;
+ ret.data = nil;
} else {
ret = i;
- if(im->sigi != si)
- ret.type = itype(si, im->sigt, 0);
+ if(tab->inter != inter)
+ ret.tab = itab(inter, tab->type, 0);
}
FLUSH(&ret);
@@ -453,20 +328,21 @@
// ifaceI2Ix(sigi *byte, iface any) (ret any);
// called only for explicit conversions (with type assertion).
+// converting nil is not okay.
void
-sys·ifaceI2Ix(Sigi *si, Iface i, Iface ret)
+sys·ifaceI2Ix(InterfaceType *inter, Iface i, Iface ret)
{
- Itype *im;
+ Itab *tab;
- im = i.type;
- if(im == nil) {
+ tab = i.tab;
+ if(tab == nil) {
// explicit conversions require non-nil interface value.
- printf("interface is nil, not %s\n", si->name);
+ printf("interface is nil, not %S\n", *inter->string);
throw("interface conversion");
} else {
ret = i;
- if(im->sigi != si)
- ret.type = itype(si, im->sigt, 0);
+ if(tab->inter != inter)
+ ret.tab = itab(inter, tab->type, 0);
}
FLUSH(&ret);
@@ -474,22 +350,23 @@
// ifaceI2I2(sigi *byte, iface any) (ret any, ok bool);
void
-sys·ifaceI2I2(Sigi *si, Iface i, Iface ret, bool ok)
+sys·ifaceI2I2(InterfaceType *inter, Iface i, Iface ret, bool ok)
{
- Itype *im;
+ Itab *tab;
- im = i.type;
- if(im == nil) {
+ tab = i.tab;
+ if(tab == nil) {
// If incoming interface is nil, the conversion fails.
- ret = niliface;
+ ret.tab = nil;
+ ret.data = nil;
ok = false;
} else {
ret = i;
ok = true;
- if(im->sigi != si) {
- ret.type = itype(si, im->sigt, 1);
- if(ret.type == nil) {
- ret = niliface;
+ if(tab->inter != inter) {
+ ret.tab = itab(inter, tab->type, 1);
+ if(ret.tab == nil) {
+ ret.data = nil;
ok = false;
}
}
@@ -502,39 +379,40 @@
// ifaceE2I(sigi *byte, iface any) (ret any);
// Called only for explicit conversions (with type assertion).
void
-sys·ifaceE2I(Sigi *si, Eface e, Iface ret)
+sys·ifaceE2I(InterfaceType *inter, Eface e, Iface ret)
{
- Sigt *t;
+ Type *t;
t = e.type;
if(t == nil) {
// explicit conversions require non-nil interface value.
- printf("interface is nil, not %s\n", si->name);
+ printf("interface is nil, not %S\n", *inter->string);
throw("interface conversion");
} else {
ret.data = e.data;
- ret.type = itype(si, t, 0);
+ ret.tab = itab(inter, t, 0);
}
FLUSH(&ret);
}
// ifaceE2I2(sigi *byte, iface any) (ret any, ok bool);
void
-sys·ifaceE2I2(Sigi *si, Eface e, Iface ret, bool ok)
+sys·ifaceE2I2(InterfaceType *inter, Eface e, Iface ret, bool ok)
{
- Sigt *t;
+ Type *t;
t = e.type;
ok = true;
if(t == nil) {
// If incoming interface is nil, the conversion fails.
- ret = niliface;
+ ret.data = nil;
+ ret.tab = nil;
ok = false;
} else {
ret.data = e.data;
- ret.type = itype(si, t, 1);
- if(ret.type == nil) {
- ret = niliface;
+ ret.tab = itab(inter, t, 1);
+ if(ret.tab == nil) {
+ ret.data = nil;
ok = false;
}
}
@@ -543,19 +421,19 @@
}
static uintptr
-ifacehash1(void *data, Sigt *sigt)
+ifacehash1(void *data, Type *t)
{
int32 alg, wid;
- if(sigt == nil)
+ if(t == nil)
return 0;
- alg = sigt->alg;
- wid = sigt->width;
+ alg = t->alg;
+ wid = t->size;
if(algarray[alg].hash == nohash) {
// calling nohash will throw too,
// but we can print a better error.
- printf("hash of unhashable type %s\n", sigt->name);
+ printf("hash of unhashable type %S\n", *t->string);
if(alg == AFAKE)
throw("fake interface hash");
throw("interface hash");
@@ -568,9 +446,9 @@
uintptr
ifacehash(Iface a)
{
- if(a.type == nil)
+ if(a.tab == nil)
return 0;
- return ifacehash1(a.data, a.type->sigt);
+ return ifacehash1(a.data, a.tab->type);
}
uintptr
@@ -580,17 +458,17 @@
}
static bool
-ifaceeq1(void *data1, void *data2, Sigt *sigt)
+ifaceeq1(void *data1, void *data2, Type *t)
{
int32 alg, wid;
- alg = sigt->alg;
- wid = sigt->width;
+ alg = t->alg;
+ wid = t->size;
if(algarray[alg].equal == noequal) {
// calling noequal will throw too,
// but we can print a better error.
- printf("comparing uncomparable type %s\n", sigt->name);
+ printf("comparing uncomparable type %S\n", *t->string);
if(alg == AFAKE)
throw("fake interface compare");
throw("interface compare");
@@ -604,11 +482,11 @@
bool
ifaceeq(Iface i1, Iface i2)
{
- if(i1.type != i2.type)
+ if(i1.tab != i2.tab)
return false;
- if(i1.type == nil)
+ if(i1.tab == nil)
return true;
- return ifaceeq1(i1.data, i2.data, i1.type->sigt);
+ return ifaceeq1(i1.data, i2.data, i1.tab->type);
}
bool
@@ -641,16 +519,12 @@
void
sys·ifacethash(Iface i1, uint32 ret)
{
- Itype *im;
- Sigt *st;
+ Itab *tab;
ret = 0;
- im = i1.type;
- if(im != nil) {
- st = im->sigt;
- if(st != nil)
- ret = st->thash;
- }
+ tab = i1.tab;
+ if(tab != nil)
+ ret = tab->type->hash;
FLUSH(&ret);
}
@@ -658,12 +532,12 @@
void
sys·efacethash(Eface e1, uint32 ret)
{
- Sigt *st;
+ Type *t;
ret = 0;
- st = e1.type;
- if(st != nil)
- ret = st->thash;
+ t = e1.type;
+ if(t != nil)
+ ret = t->hash;
FLUSH(&ret);
}
@@ -680,227 +554,68 @@
}
void
-unsafe·Reflect(Eface i, uint64 retit, String rettype, bool retindir)
+unsafe·Typeof(Eface e, Eface ret)
{
- int32 wid;
-
- if(i.type == nil) {
- retit = 0;
- rettype = emptystring;
- retindir = false;
- } else {
- retit = (uint64)i.data;
- rettype = gostring(i.type->name);
- wid = i.type->width;
- retindir = wid > sizeof(i.data);
- }
- FLUSH(&retit);
- FLUSH(&rettype);
- FLUSH(&retindir);
+ if(e.type == nil) {
+ ret.type = nil;
+ ret.data = nil;
+ } else
+ ret = *(Eface*)e.type;
+ FLUSH(&ret);
}
-extern Sigt *gotypesigs[];
-extern int32 ngotypesigs;
-
-
-// The reflection library can ask to unreflect on a type
-// that has never been used, so we don't have a signature for it.
-// For concreteness, suppose a program does
-//
-// type T struct{ x []int }
-// var t T;
-// v := reflect.NewValue(v);
-// vv := v.Field(0);
-// if s, ok := vv.Interface().(string) {
-// print("first field is string");
-// }
-//
-// vv.Interface() returns the result of sys.Unreflect with
-// a typestring of "[]int". If []int is not used with interfaces
-// in the rest of the program, there will be no signature in gotypesigs
-// for "[]int", so we have to invent one. The requirements
-// on the fake signature are:
-//
-// (1) any interface conversion using the signature will fail
-// (2) calling unsafe.Reflect() returns the args to unreflect
-// (3) the right algorithm type is used, for == and map insertion
-//
-// (1) is ensured by the fact that we allocate a new Sigt,
-// so it will necessarily be != any Sigt in gotypesigs.
-// (2) is ensured by storing the type string in the signature
-// and setting the width to force the correct value of the bool indir.
-// (3) is ensured by sniffing the type string.
-//
-// Note that (1) is correct behavior: if the program had tested
-// for .([]int) instead of .(string) above, then there would be a
-// signature with type string "[]int" in gotypesigs, and unreflect
-// wouldn't call fakesigt.
-
-static Sigt* fake[1009];
-static int32 nfake;
-
-enum
-{
- SizeofInt = 4,
- SizeofFloat = 4,
-};
-
-// Table of prefixes of names of comparable types.
-static struct {
- int8 *s;
- int8 n;
- int8 alg;
- int8 w;
-} cmp[] =
-{
- // basic types
- "int", 3+1, AMEM, SizeofInt, // +1 is NUL
- "uint", 4+1, AMEM, SizeofInt,
- "int8", 4+1, AMEM, 1,
- "uint8", 5+1, AMEM, 1,
- "int16", 5+1, AMEM, 2,
- "uint16", 6+1, AMEM, 2,
- "int32", 5+1, AMEM, 4,
- "uint32", 6+1, AMEM, 4,
- "int64", 5+1, AMEM, 8,
- "uint64", 6+1, AMEM, 8,
- "uintptr", 7+1, AMEM, sizeof(uintptr),
- "float", 5+1, AMEM, SizeofFloat,
- "float32", 7+1, AMEM, 4,
- "float64", 7+1, AMEM, 8,
- "bool", 4+1, AMEM, sizeof(bool),
-
- // string compare is special
- "string", 6+1, ASTRING, sizeof(String),
-
- // generic types, identified by prefix
- "*", 1, AMEM, sizeof(uintptr),
- "chan ", 5, AMEM, sizeof(uintptr),
- "func(", 5, AMEM, sizeof(uintptr),
- "map[", 4, AMEM, sizeof(uintptr),
-};
-
-static Sigt*
-fakesigt(String type, bool indir)
-{
- Sigt *sigt;
- uint32 h;
- int32 i, locked;
-
- h = 0;
- for(i=0; i<type.len; i++)
- h = h*37 + type.str[i];
- h += indir;
- h %= nelem(fake);
-
- for(locked=0; locked<2; locked++) {
- if(locked)
- lock(&ifacelock);
- for(sigt = fake[h]; sigt != nil; sigt = sigt->link) {
- // don't need to compare indir.
- // same type string but different indir will have
- // different hashes.
- if(mcmp(sigt->name, type.str, type.len) == 0)
- if(sigt->name[type.len] == '\0') {
- if(locked)
- unlock(&ifacelock);
- return sigt;
- }
- }
- }
-
- sigt = malloc(sizeof(*sigt));
- sigt->name = malloc(type.len + 1);
- mcpy(sigt->name, type.str, type.len);
-
- sigt->alg = AFAKE;
- sigt->width = 1; // small width
- if(indir)
- sigt->width = 2*sizeof(niliface.data); // big width
-
- // AFAKE is like ANOEQ; check whether the type
- // should have a more capable algorithm.
- for(i=0; i<nelem(cmp); i++) {
- if(mcmp((byte*)sigt->name, (byte*)cmp[i].s, cmp[i].n) == 0) {
- sigt->alg = cmp[i].alg;
- sigt->width = cmp[i].w;
- break;
- }
- }
-
- sigt->link = fake[h];
- fake[h] = sigt;
-
- unlock(&ifacelock);
- return sigt;
-}
-
-static int32
-cmpstringchars(String a, uint8 *b)
-{
- int32 i;
- byte c1, c2;
-
- for(i=0;; i++) {
- c1 = 0;
- if(i < a.len)
- c1 = a.str[i];
- c2 = b[i];
- if(c1 < c2)
- return -1;
- if(c1 > c2)
- return +1;
- if(c1 == 0)
- return 0;
- }
-}
-
-static Sigt*
-findtype(String type, bool indir)
-{
- int32 i, lo, hi, m;
-
- lo = 0;
- hi = ngotypesigs;
- while(lo < hi) {
- m = lo + (hi - lo)/2;
- i = cmpstringchars(type, gotypesigs[m]->name);
- if(i == 0)
- return gotypesigs[m];
- if(i < 0)
- hi = m;
- else
- lo = m+1;
- }
- return fakesigt(type, indir);
-}
-
-
void
-unsafe·Unreflect(uint64 it, String type, bool indir, Eface ret)
+unsafe·Reflect(Eface e, Eface rettype, void *retaddr)
{
- Sigt *sigt;
+ uintptr *p;
+ uintptr x;
- ret = nileface;
+ if(e.type == nil) {
+ rettype.type = nil;
+ rettype.data = nil;
+ retaddr = 0;
+ } else {
+ rettype = *(Eface*)e.type;
+ if(e.type->size <= sizeof(uintptr)) {
+ // Copy data into x ...
+ x = 0;
+ algarray[e.type->alg].copy(e.type->size, &x, &e.data);
- if(cmpstring(type, emptystring) == 0)
- goto out;
+ // but then build pointer to x so that Reflect
+ // always returns pointer to data.
+ p = mallocgc(sizeof(uintptr));
+ *p = x;
+ } else {
+ // Already a pointer, but still make a copy,
+ // to preserve value semantics for interface data.
+ p = mallocgc(e.type->size);
+ algarray[e.type->alg].copy(e.type->size, p, e.data);
+ }
+ retaddr = p;
+ }
+ FLUSH(&rettype);
+ FLUSH(&retaddr);
+}
- if(type.len > 10 && mcmp(type.str, (byte*)"interface ", 10) == 0) {
- printf("unsafe.Unreflect: cannot put %S in interface\n", type);
- throw("unsafe.Unreflect");
+void
+unsafe·Unreflect(Iface typ, void *addr, Eface e)
+{
+ // Reflect library has reinterpreted typ
+ // as its own kind of type structure.
+ // We know that the pointer to the original
+ // type structure sits before the data pointer.
+ e.type = (Type*)((Eface*)typ.data-1);
+
+ // Interface holds either pointer to data
+ // or copy of original data.
+ if(e.type->size <= sizeof(uintptr))
+ algarray[e.type->alg].copy(e.type->size, &e.data, addr);
+ else {
+ // Easier: already a pointer to data.
+ // TODO(rsc): Should this make a copy?
+ e.data = addr;
}
- // if we think the type should be indirect
- // and caller does not, play it safe, return nil.
- sigt = findtype(type, indir);
- if(indir != (sigt->width > sizeof(ret.data)))
- goto out;
-
- ret.type = sigt;
- ret.data = (void*)it;
-
-out:
- FLUSH(&ret);
+ FLUSH(&e);
}
diff --git a/src/pkg/runtime/print.c b/src/pkg/runtime/print.c
index c7e0903..c9929cd 100644
--- a/src/pkg/runtime/print.c
+++ b/src/pkg/runtime/print.c
@@ -76,10 +76,10 @@
sys·printint(*(int64*)arg);
break;
case 'x':
- sys·printhex(*(int32*)arg);
+ sys·printhex(*(uint32*)arg);
break;
case 'X':
- sys·printhex(*(int64*)arg);
+ sys·printhex(*(uint64*)arg);
break;
case 'p':
sys·printpointer(*(void**)arg);
diff --git a/src/pkg/runtime/runtime.h b/src/pkg/runtime/runtime.h
index 8f1cfa7..26dfe70 100644
--- a/src/pkg/runtime/runtime.h
+++ b/src/pkg/runtime/runtime.h
@@ -56,9 +56,9 @@
typedef struct SigTab SigTab;
typedef struct MCache MCache;
typedef struct Iface Iface;
-typedef struct Itype Itype;
+typedef struct Itab Itab;
typedef struct Eface Eface;
-typedef struct Sigt Sigt;
+typedef struct Type Type;
typedef struct Defer Defer;
/*
@@ -117,12 +117,12 @@
};
struct Iface
{
- Itype* type;
+ Itab* tab;
void* data;
};
struct Eface
{
- Sigt* type;
+ Type* type;
void* data;
};