Commit c7513eac authored by Russ Cox's avatar Russ Cox

runtime: use new reflect data structures (CL 31107)

in place of sigi, sigt.

R=ken
OCL=31118
CL=31277
parent ce2e450c
...@@ -36,17 +36,17 @@ func stringiter(string, int) int; ...@@ -36,17 +36,17 @@ func stringiter(string, int) int;
func stringiter2(string, int) (retk int, retv int); func stringiter2(string, int) (retk int, retv int);
func ifaceI2E(iface any) (ret any); func ifaceI2E(iface any) (ret any);
func ifaceE2I(sigi *byte, iface any) (ret any); func ifaceE2I(typ *byte, iface any) (ret any);
func ifaceT2E(sigt *byte, elem any) (ret any); func ifaceT2E(typ *byte, elem any) (ret any);
func ifaceE2T(sigt *byte, elem any) (ret any); func ifaceE2T(typ *byte, elem any) (ret any);
func ifaceE2I2(sigi *byte, iface any) (ret any, ok bool); func ifaceE2I2(typ *byte, iface any) (ret any, ok bool);
func ifaceE2T2(sigt *byte, elem any) (ret any, ok bool); func ifaceE2T2(typ *byte, elem any) (ret any, ok bool);
func ifaceT2I(sigi *byte, sigt *byte, elem any) (ret any); func ifaceT2I(typ1 *byte, typ2 *byte, elem any) (ret any);
func ifaceI2T(sigt *byte, iface any) (ret any); func ifaceI2T(typ *byte, iface any) (ret any);
func ifaceI2T2(sigt *byte, iface any) (ret any, ok bool); func ifaceI2T2(typ *byte, iface any) (ret any, ok bool);
func ifaceI2I(sigi *byte, iface any) (ret any); func ifaceI2I(typ *byte, iface any) (ret any);
func ifaceI2Ix(sigi *byte, iface any) (ret any); func ifaceI2Ix(typ *byte, iface any) (ret any);
func ifaceI2I2(sigi *byte, iface any) (ret any, ok bool); func ifaceI2I2(typ *byte, iface any) (ret any, ok bool);
func ifaceeq(i1 any, i2 any) (ret bool); func ifaceeq(i1 any, i2 any) (ret bool);
func efaceeq(i1 any, i2 any) (ret bool); func efaceeq(i1 any, i2 any) (ret bool);
func ifacethash(i1 any) (ret uint32); func ifacethash(i1 any) (ret uint32);
......
...@@ -70,6 +70,7 @@ OFILES=\ ...@@ -70,6 +70,7 @@ OFILES=\
sys.$O\ sys.$O\
thread.$O\ thread.$O\
traceback.$O\ traceback.$O\
type.$O\
$(OFILES_$(GOARCH))\ $(OFILES_$(GOARCH))\
HFILES=\ HFILES=\
......
...@@ -3,173 +3,64 @@ ...@@ -3,173 +3,64 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
#include "runtime.h" #include "runtime.h"
#include "type.h"
int32 iface_debug = 0; static void
printiface(Iface i)
{
printf("(%p,%p)", i.tab, i.data);
}
typedef struct Sigt Sigt; static void
typedef struct Sigi Sigi; printeface(Eface e)
typedef struct Itype Itype; {
printf("(%p,%p)", e.type, e.data);
}
/* /*
* the layout of Iface, Sigt and Sigi are known to the compiler * layout of Itab known to compilers
*/ */
struct Sigt struct Itab
{
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; InterfaceType* inter;
Sigt* sigt; Type* type;
Itype* link; Itab* link;
int32 bad; int32 bad;
int32 unused; int32 unused;
void (*fun[])(void); void (*fun[])(void);
}; };
static Iface niliface; static Itab* hash[1009];
static Eface nileface;
static Itype* hash[1009];
static Lock ifacelock; static Lock ifacelock;
Sigi sigi·empty[2] = { (byte*)"interface { }" }; static Itab*
itab(InterfaceType *inter, Type *type, int32 canfail)
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("}");
}
static void
printiface(Iface i)
{
prints("(");
sys·printpointer(i.type);
prints(",");
sys·printpointer(i.data);
prints(")");
}
static void
printeface(Eface e)
{
prints("(");
sys·printpointer(e.type);
prints(",");
sys·printpointer(e.data);
prints(")");
}
static Itype*
itype(Sigi *si, Sigt *st, int32 canfail)
{ {
int32 locked; int32 locked;
int32 nt, ni; int32 ni;
Method *t, *et;
IMethod *i, *ei;
uint32 ihash, h; uint32 ihash, h;
byte *sname, *iname; String *iname;
Itype *m; Itab *m;
UncommonType *x;
if(si->size == 0) if(inter->mhdr.nel == 0)
throw("internal error - misuse of itype"); throw("internal error - misuse of itab");
// easy case // easy case
if(st->meth[0].fname == nil) { x = type->x;
if(x == nil) {
if(canfail) if(canfail)
return nil; return nil;
iname = si->meth[0].fname; iname = inter->m[0].name;
goto throw1; goto throw;
} }
// compiler has provided some good hash codes for us. // compiler has provided some good hash codes for us.
h = 0; h = inter->hash;
if(si) h += 17 * type->hash;
h += si->hash; // TODO(rsc): h += 23 * x->mhash ?
if(st) {
h += st->thash;
h += st->mhash;
}
h %= nelem(hash); h %= nelem(hash);
// look twice - once without lock, once with. // look twice - once without lock, once with.
...@@ -178,7 +69,7 @@ itype(Sigi *si, Sigt *st, int32 canfail) ...@@ -178,7 +69,7 @@ itype(Sigi *si, Sigt *st, int32 canfail)
if(locked) if(locked)
lock(&ifacelock); lock(&ifacelock);
for(m=hash[h]; m!=nil; m=m->link) { 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) { if(m->bad) {
m = nil; m = nil;
if(!canfail) { if(!canfail) {
...@@ -188,8 +79,8 @@ itype(Sigi *si, Sigt *st, int32 canfail) ...@@ -188,8 +79,8 @@ itype(Sigi *si, Sigt *st, int32 canfail)
// the cached result doesn't record which // the cached result doesn't record which
// interface function was missing, so jump // interface function was missing, so jump
// down to the interface check, which will // down to the interface check, which will
// give a better error. // do more work but give a better error.
goto throw; goto search;
} }
} }
if(locked) if(locked)
...@@ -199,69 +90,60 @@ itype(Sigi *si, Sigt *st, int32 canfail) ...@@ -199,69 +90,60 @@ itype(Sigi *si, Sigt *st, int32 canfail)
} }
} }
ni = si->size; ni = inter->mhdr.nel;
m = malloc(sizeof(*m) + ni*sizeof(m->fun[0])); m = malloc(sizeof(*m) + ni*sizeof m->fun[0]);
m->sigi = si; m->inter = inter;
m->sigt = st; m->type = type;
throw: search:
nt = 0; // both inter and type have method sorted by hash,
for(ni=0;; ni++) { // so can iterate over both in lock step;
iname = si->meth[ni].fname; // the loop is O(ni+nt) not O(ni*nt).
if(iname == nil) i = inter->m;
break; ei = i + inter->mhdr.nel;
t = x->m;
// pick up next name from et = t + x->mhdr.nel;
// interface signature for(; i < ei; i++) {
ihash = si->meth[ni].fhash; ihash = i->hash;
iname = i->name;
for(;; nt++) { for(;; t++) {
// pick up and compare next name if(t >= et) {
// from structure signature
sname = st->meth[nt].fname;
if(sname == nil) {
if(!canfail) { if(!canfail) {
throw1: throw:
printf("cannot convert type %s to interface %s: missing method %s\n", // didn't find method
st->name, si->name, iname); printf("%S is not %S: missing method %S\n",
if(iface_debug) { *type->string, *inter->string, *iname);
prints("interface");
printsigi(si);
prints("\ntype");
printsigt(st);
prints("\n");
}
throw("interface conversion"); throw("interface conversion");
return nil; // not reached return nil; // not reached
} }
m->bad = 1; m->bad = 1;
m->link = hash[h]; goto out;
hash[h] = m;
if(locked)
unlock(&ifacelock);
return nil;
} }
if(ihash == st->meth[nt].fhash && strcmp(sname, iname) == 0) if(t->hash == ihash && t->name == iname)
break; break;
} }
m->fun[si->meth[ni].perm] = st->meth[nt].fun; if(m)
m->fun[i->perm] = t->ifn;
} }
out:
m->link = hash[h]; m->link = hash[h];
hash[h] = m; hash[h] = m;
if(locked) if(locked)
unlock(&ifacelock); unlock(&ifacelock);
if(m->bad)
return nil;
return m; return m;
} }
static void static void
copyin(Sigt *st, void *src, void **dst) copyin(Type *t, void *src, void **dst)
{ {
int32 wid, alg; int32 wid, alg;
void *p; void *p;
wid = st->width; wid = t->size;
alg = st->alg; alg = t->alg;
if(wid <= sizeof(*dst)) if(wid <= sizeof(*dst))
algarray[alg].copy(wid, dst, src); algarray[alg].copy(wid, dst, src);
...@@ -273,12 +155,12 @@ copyin(Sigt *st, void *src, void **dst) ...@@ -273,12 +155,12 @@ copyin(Sigt *st, void *src, void **dst)
} }
static void static void
copyout(Sigt *st, void **src, void *dst) copyout(Type *t, void **src, void *dst)
{ {
int32 wid, alg; int32 wid, alg;
wid = st->width; wid = t->size;
alg = st->alg; alg = t->alg;
if(wid <= sizeof(*src)) if(wid <= sizeof(*src))
algarray[alg].copy(wid, dst, src); algarray[alg].copy(wid, dst, src);
...@@ -286,132 +168,123 @@ copyout(Sigt *st, void **src, void *dst) ...@@ -286,132 +168,123 @@ copyout(Sigt *st, void **src, void *dst)
algarray[alg].copy(wid, dst, *src); 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 #pragma textflag 7
void void
sys·ifaceT2I(Sigi *si, Sigt *st, ...) sys·ifaceT2I(InterfaceType *inter, Type *t, ...)
{ {
byte *elem; byte *elem;
Iface *ret; Iface *ret;
int32 wid; int32 wid;
elem = (byte*)(&st+1); elem = (byte*)(&t+1);
wid = st->width; wid = t->size;
ret = (Iface*)(elem + rnd(wid, sizeof(uintptr))); ret = (Iface*)(elem + rnd(wid, Structrnd));
ret->tab = itab(inter, t, 0);
ret->type = itype(si, st, 0); copyin(t, elem, &ret->data);
copyin(st, elem, &ret->data);
} }
// ifaceT2E(sigt *byte, elem any) (ret any); // ifaceT2E(sigt *byte, elem any) (ret Eface);
#pragma textflag 7 #pragma textflag 7
void void
sys·ifaceT2E(Sigt *st, ...) sys·ifaceT2E(Type *t, ...)
{ {
byte *elem; byte *elem;
Eface *ret; Eface *ret;
int32 wid; int32 wid;
elem = (byte*)(&st+1); elem = (byte*)(&t+1);
wid = st->width; wid = t->size;
ret = (Eface*)(elem + rnd(wid, sizeof(uintptr))); ret = (Eface*)(elem + rnd(wid, Structrnd));
ret->type = st; ret->type = t;
copyin(st, elem, &ret->data); copyin(t, elem, &ret->data);
} }
// ifaceI2T(sigt *byte, iface any) (ret any); // ifaceI2T(sigt *byte, iface any) (ret any);
#pragma textflag 7 #pragma textflag 7
void void
sys·ifaceI2T(Sigt *st, Iface i, ...) sys·ifaceI2T(Type *t, Iface i, ...)
{ {
Itype *im; Itab *tab;
byte *ret; byte *ret;
ret = (byte*)(&i+1); ret = (byte*)(&i+1);
tab = i.tab;
im = i.type; if(tab == nil) {
if(im == nil) { printf("interface is nil, not %S\n", *t->string);
printf("interface is nil, not %s\n", st->name);
throw("interface conversion"); throw("interface conversion");
} }
if(im->sigt != st) { if(tab->type != t) {
printf("%s is %s, not %s\n", im->sigi->name, im->sigt->name, st->name); printf("%S is %S, not %S\n", *tab->inter->string, *tab->type->string, *t->string);
throw("interface conversion"); 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 #pragma textflag 7
void void
sys·ifaceI2T2(Sigt *st, Iface i, ...) sys·ifaceI2T2(Type *t, Iface i, ...)
{ {
byte *ret; byte *ret;
bool *ok; bool *ok;
Itype *im;
int32 wid; int32 wid;
ret = (byte*)(&i+1); ret = (byte*)(&i+1);
wid = st->width; wid = t->size;
ok = (bool*)(ret+rnd(wid, 1)); ok = (bool*)(ret+rnd(wid, 1));
im = i.type; if(i.tab == nil || i.tab->type != t) {
if(im == nil || im->sigt != st) {
*ok = false; *ok = false;
sys·memclr(ret, wid); sys·memclr(ret, wid);
return; return;
} }
*ok = true; *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 #pragma textflag 7
void void
sys·ifaceE2T(Sigt *st, Eface e, ...) sys·ifaceE2T(Type *t, Eface e, ...)
{ {
Sigt *t;
byte *ret; byte *ret;
ret = (byte*)(&e+1); ret = (byte*)(&e+1);
t = e.type; if(e.type != t) {
if(t == nil) { if(e.type == nil)
printf("interface is nil, not %s\n", st->name); printf("interface is nil, not %S\n", *t->string);
throw("interface conversion"); else
} printf("interface is %S, not %S\n", *e.type->string, *t->string);
if(t != st) {
printf("interface is %s, not %s\n", t->name, st->name);
throw("interface conversion"); throw("interface conversion");
} }
copyout(st, &e.data, ret); copyout(t, &e.data, ret);
} }
// ifaceE2T2(sigt *byte, iface any) (ret any, ok bool); // ifaceE2T2(sigt *byte, iface any) (ret any, ok bool);
#pragma textflag 7 #pragma textflag 7
void void
sys·ifaceE2T2(Sigt *st, Eface e, ...) sys·ifaceE2T2(Type *t, Eface e, ...)
{ {
byte *ret; byte *ret;
bool *ok; bool *ok;
Sigt *t;
int32 wid; int32 wid;
ret = (byte*)(&e+1); ret = (byte*)(&e+1);
wid = st->width; wid = t->size;
ok = (bool*)(ret+rnd(wid, 1)); ok = (bool*)(ret+rnd(wid, 1));
t = e.type; if(t != e.type) {
if(t != st) {
*ok = false; *ok = false;
sys·memclr(ret, wid); sys·memclr(ret, wid);
return; return;
} }
*ok = true; *ok = true;
copyout(st, &e.data, ret); copyout(t, &e.data, ret);
} }
// ifaceI2E(sigi *byte, iface any) (ret any); // ifaceI2E(sigi *byte, iface any) (ret any);
...@@ -419,33 +292,35 @@ sys·ifaceE2T2(Sigt *st, Eface e, ...) ...@@ -419,33 +292,35 @@ sys·ifaceE2T2(Sigt *st, Eface e, ...)
void void
sys·ifaceI2E(Iface i, Eface ret) sys·ifaceI2E(Iface i, Eface ret)
{ {
Itype *im; Itab *tab;
ret.data = i.data; ret.data = i.data;
im = i.type; tab = i.tab;
if(im == nil) if(tab == nil)
ret.type = nil; ret.type = nil;
else else
ret.type = im->sigt; ret.type = tab->type;
FLUSH(&ret); FLUSH(&ret);
} }
// ifaceI2I(sigi *byte, iface any) (ret any); // 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 void
sys·ifaceI2I(Sigi *si, Iface i, Iface ret) sys·ifaceI2I(InterfaceType *inter, Iface i, Iface ret)
{ {
Itype *im; Itab *tab;
im = i.type; tab = i.tab;
if(im == nil) { if(tab == nil) {
// If incoming interface is uninitialized (zeroed) // If incoming interface is uninitialized (zeroed)
// make the outgoing interface zeroed as well. // make the outgoing interface zeroed as well.
ret = niliface; ret.tab = nil;
ret.data = nil;
} else { } else {
ret = i; ret = i;
if(im->sigi != si) if(tab->inter != inter)
ret.type = itype(si, im->sigt, 0); ret.tab = itab(inter, tab->type, 0);
} }
FLUSH(&ret); FLUSH(&ret);
...@@ -453,20 +328,21 @@ sys·ifaceI2I(Sigi *si, Iface i, Iface ret) ...@@ -453,20 +328,21 @@ sys·ifaceI2I(Sigi *si, Iface i, Iface ret)
// ifaceI2Ix(sigi *byte, iface any) (ret any); // ifaceI2Ix(sigi *byte, iface any) (ret any);
// called only for explicit conversions (with type assertion). // called only for explicit conversions (with type assertion).
// converting nil is not okay.
void void
sys·ifaceI2Ix(Sigi *si, Iface i, Iface ret) sys·ifaceI2Ix(InterfaceType *inter, Iface i, Iface ret)
{ {
Itype *im; Itab *tab;
im = i.type; tab = i.tab;
if(im == nil) { if(tab == nil) {
// explicit conversions require non-nil interface value. // 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"); throw("interface conversion");
} else { } else {
ret = i; ret = i;
if(im->sigi != si) if(tab->inter != inter)
ret.type = itype(si, im->sigt, 0); ret.tab = itab(inter, tab->type, 0);
} }
FLUSH(&ret); FLUSH(&ret);
...@@ -474,22 +350,23 @@ sys·ifaceI2Ix(Sigi *si, Iface i, Iface ret) ...@@ -474,22 +350,23 @@ sys·ifaceI2Ix(Sigi *si, Iface i, Iface ret)
// ifaceI2I2(sigi *byte, iface any) (ret any, ok bool); // ifaceI2I2(sigi *byte, iface any) (ret any, ok bool);
void 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; tab = i.tab;
if(im == nil) { if(tab == nil) {
// If incoming interface is nil, the conversion fails. // If incoming interface is nil, the conversion fails.
ret = niliface; ret.tab = nil;
ret.data = nil;
ok = false; ok = false;
} else { } else {
ret = i; ret = i;
ok = true; ok = true;
if(im->sigi != si) { if(tab->inter != inter) {
ret.type = itype(si, im->sigt, 1); ret.tab = itab(inter, tab->type, 1);
if(ret.type == nil) { if(ret.tab == nil) {
ret = niliface; ret.data = nil;
ok = false; ok = false;
} }
} }
...@@ -502,39 +379,40 @@ sys·ifaceI2I2(Sigi *si, Iface i, Iface ret, bool ok) ...@@ -502,39 +379,40 @@ sys·ifaceI2I2(Sigi *si, Iface i, Iface ret, bool ok)
// ifaceE2I(sigi *byte, iface any) (ret any); // ifaceE2I(sigi *byte, iface any) (ret any);
// Called only for explicit conversions (with type assertion). // Called only for explicit conversions (with type assertion).
void void
sys·ifaceE2I(Sigi *si, Eface e, Iface ret) sys·ifaceE2I(InterfaceType *inter, Eface e, Iface ret)
{ {
Sigt *t; Type *t;
t = e.type; t = e.type;
if(t == nil) { if(t == nil) {
// explicit conversions require non-nil interface value. // 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"); throw("interface conversion");
} else { } else {
ret.data = e.data; ret.data = e.data;
ret.type = itype(si, t, 0); ret.tab = itab(inter, t, 0);
} }
FLUSH(&ret); FLUSH(&ret);
} }
// ifaceE2I2(sigi *byte, iface any) (ret any, ok bool); // ifaceE2I2(sigi *byte, iface any) (ret any, ok bool);
void 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; t = e.type;
ok = true; ok = true;
if(t == nil) { if(t == nil) {
// If incoming interface is nil, the conversion fails. // If incoming interface is nil, the conversion fails.
ret = niliface; ret.data = nil;
ret.tab = nil;
ok = false; ok = false;
} else { } else {
ret.data = e.data; ret.data = e.data;
ret.type = itype(si, t, 1); ret.tab = itab(inter, t, 1);
if(ret.type == nil) { if(ret.tab == nil) {
ret = niliface; ret.data = nil;
ok = false; ok = false;
} }
} }
...@@ -543,19 +421,19 @@ sys·ifaceE2I2(Sigi *si, Eface e, Iface ret, bool ok) ...@@ -543,19 +421,19 @@ sys·ifaceE2I2(Sigi *si, Eface e, Iface ret, bool ok)
} }
static uintptr static uintptr
ifacehash1(void *data, Sigt *sigt) ifacehash1(void *data, Type *t)
{ {
int32 alg, wid; int32 alg, wid;
if(sigt == nil) if(t == nil)
return 0; return 0;
alg = sigt->alg; alg = t->alg;
wid = sigt->width; wid = t->size;
if(algarray[alg].hash == nohash) { if(algarray[alg].hash == nohash) {
// calling nohash will throw too, // calling nohash will throw too,
// but we can print a better error. // 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) if(alg == AFAKE)
throw("fake interface hash"); throw("fake interface hash");
throw("interface hash"); throw("interface hash");
...@@ -568,9 +446,9 @@ ifacehash1(void *data, Sigt *sigt) ...@@ -568,9 +446,9 @@ ifacehash1(void *data, Sigt *sigt)
uintptr uintptr
ifacehash(Iface a) ifacehash(Iface a)
{ {
if(a.type == nil) if(a.tab == nil)
return 0; return 0;
return ifacehash1(a.data, a.type->sigt); return ifacehash1(a.data, a.tab->type);
} }
uintptr uintptr
...@@ -580,17 +458,17 @@ efacehash(Eface a) ...@@ -580,17 +458,17 @@ efacehash(Eface a)
} }
static bool static bool
ifaceeq1(void *data1, void *data2, Sigt *sigt) ifaceeq1(void *data1, void *data2, Type *t)
{ {
int32 alg, wid; int32 alg, wid;
alg = sigt->alg; alg = t->alg;
wid = sigt->width; wid = t->size;
if(algarray[alg].equal == noequal) { if(algarray[alg].equal == noequal) {
// calling noequal will throw too, // calling noequal will throw too,
// but we can print a better error. // 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) if(alg == AFAKE)
throw("fake interface compare"); throw("fake interface compare");
throw("interface compare"); throw("interface compare");
...@@ -604,11 +482,11 @@ ifaceeq1(void *data1, void *data2, Sigt *sigt) ...@@ -604,11 +482,11 @@ ifaceeq1(void *data1, void *data2, Sigt *sigt)
bool bool
ifaceeq(Iface i1, Iface i2) ifaceeq(Iface i1, Iface i2)
{ {
if(i1.type != i2.type) if(i1.tab != i2.tab)
return false; return false;
if(i1.type == nil) if(i1.tab == nil)
return true; return true;
return ifaceeq1(i1.data, i2.data, i1.type->sigt); return ifaceeq1(i1.data, i2.data, i1.tab->type);
} }
bool bool
...@@ -641,16 +519,12 @@ sys·efaceeq(Eface e1, Eface e2, bool ret) ...@@ -641,16 +519,12 @@ sys·efaceeq(Eface e1, Eface e2, bool ret)
void void
sys·ifacethash(Iface i1, uint32 ret) sys·ifacethash(Iface i1, uint32 ret)
{ {
Itype *im; Itab *tab;
Sigt *st;
ret = 0; ret = 0;
im = i1.type; tab = i1.tab;
if(im != nil) { if(tab != nil)
st = im->sigt; ret = tab->type->hash;
if(st != nil)
ret = st->thash;
}
FLUSH(&ret); FLUSH(&ret);
} }
...@@ -658,12 +532,12 @@ sys·ifacethash(Iface i1, uint32 ret) ...@@ -658,12 +532,12 @@ sys·ifacethash(Iface i1, uint32 ret)
void void
sys·efacethash(Eface e1, uint32 ret) sys·efacethash(Eface e1, uint32 ret)
{ {
Sigt *st; Type *t;
ret = 0; ret = 0;
st = e1.type; t = e1.type;
if(st != nil) if(t != nil)
ret = st->thash; ret = t->hash;
FLUSH(&ret); FLUSH(&ret);
} }
...@@ -680,227 +554,68 @@ sys·printeface(Eface e) ...@@ -680,227 +554,68 @@ sys·printeface(Eface e)
} }
void 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);
}
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; if(e.type == nil) {
byte c1, c2; ret.type = nil;
ret.data = nil;
for(i=0;; i++) { } else
c1 = 0; ret = *(Eface*)e.type;
if(i < a.len) FLUSH(&ret);
c1 = a.str[i];
c2 = b[i];
if(c1 < c2)
return -1;
if(c1 > c2)
return +1;
if(c1 == 0)
return 0;
}
} }
static Sigt* void
findtype(String type, bool indir) unsafe·Reflect(Eface e, Eface rettype, void *retaddr)
{ {
int32 i, lo, hi, m; uintptr *p;
uintptr x;
lo = 0; if(e.type == nil) {
hi = ngotypesigs; rettype.type = nil;
while(lo < hi) { rettype.data = nil;
m = lo + (hi - lo)/2; retaddr = 0;
i = cmpstringchars(type, gotypesigs[m]->name); } else {
if(i == 0) rettype = *(Eface*)e.type;
return gotypesigs[m]; if(e.type->size <= sizeof(uintptr)) {
if(i < 0) // Copy data into x ...
hi = m; x = 0;
else algarray[e.type->alg].copy(e.type->size, &x, &e.data);
lo = m+1;
// 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;
} }
return fakesigt(type, indir); FLUSH(&rettype);
FLUSH(&retaddr);
} }
void void
unsafe·Unreflect(uint64 it, String type, bool indir, Eface ret) unsafe·Unreflect(Iface typ, void *addr, Eface e)
{ {
Sigt *sigt; // Reflect library has reinterpreted typ
// as its own kind of type structure.
ret = nileface; // We know that the pointer to the original
// type structure sits before the data pointer.
if(cmpstring(type, emptystring) == 0) e.type = (Type*)((Eface*)typ.data-1);
goto out;
// Interface holds either pointer to data
if(type.len > 10 && mcmp(type.str, (byte*)"interface ", 10) == 0) { // or copy of original data.
printf("unsafe.Unreflect: cannot put %S in interface\n", type); if(e.type->size <= sizeof(uintptr))
throw("unsafe.Unreflect"); 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 FLUSH(&e);
// 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);
} }
...@@ -76,10 +76,10 @@ printf(int8 *s, ...) ...@@ -76,10 +76,10 @@ printf(int8 *s, ...)
sys·printint(*(int64*)arg); sys·printint(*(int64*)arg);
break; break;
case 'x': case 'x':
sys·printhex(*(int32*)arg); sys·printhex(*(uint32*)arg);
break; break;
case 'X': case 'X':
sys·printhex(*(int64*)arg); sys·printhex(*(uint64*)arg);
break; break;
case 'p': case 'p':
sys·printpointer(*(void**)arg); sys·printpointer(*(void**)arg);
......
...@@ -56,9 +56,9 @@ typedef struct Usema Usema; ...@@ -56,9 +56,9 @@ typedef struct Usema Usema;
typedef struct SigTab SigTab; typedef struct SigTab SigTab;
typedef struct MCache MCache; typedef struct MCache MCache;
typedef struct Iface Iface; typedef struct Iface Iface;
typedef struct Itype Itype; typedef struct Itab Itab;
typedef struct Eface Eface; typedef struct Eface Eface;
typedef struct Sigt Sigt; typedef struct Type Type;
typedef struct Defer Defer; typedef struct Defer Defer;
/* /*
...@@ -117,12 +117,12 @@ struct String ...@@ -117,12 +117,12 @@ struct String
}; };
struct Iface struct Iface
{ {
Itype* type; Itab* tab;
void* data; void* data;
}; };
struct Eface struct Eface
{ {
Sigt* type; Type* type;
void* data; void* data;
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment