diff --git a/src/cmd/gc/sys.go b/src/cmd/gc/sys.go index a8a11866d8..aad0a98049 100644 --- a/src/cmd/gc/sys.go +++ b/src/cmd/gc/sys.go @@ -36,17 +36,17 @@ func stringiter(string, int) int; func stringiter2(string, int) (retk int, retv int); func ifaceI2E(iface any) (ret any); -func ifaceE2I(sigi *byte, iface any) (ret any); -func ifaceT2E(sigt *byte, elem any) (ret any); -func ifaceE2T(sigt *byte, elem any) (ret any); -func ifaceE2I2(sigi *byte, iface any) (ret any, ok bool); -func ifaceE2T2(sigt *byte, elem any) (ret any, ok bool); -func ifaceT2I(sigi *byte, sigt *byte, elem any) (ret any); -func ifaceI2T(sigt *byte, iface any) (ret any); -func ifaceI2T2(sigt *byte, iface any) (ret any, ok bool); -func ifaceI2I(sigi *byte, iface any) (ret any); -func ifaceI2Ix(sigi *byte, iface any) (ret any); -func ifaceI2I2(sigi *byte, iface any) (ret any, ok bool); +func ifaceE2I(typ *byte, iface any) (ret any); +func ifaceT2E(typ *byte, elem any) (ret any); +func ifaceE2T(typ *byte, elem any) (ret any); +func ifaceE2I2(typ *byte, iface any) (ret any, ok bool); +func ifaceE2T2(typ *byte, elem any) (ret any, ok bool); +func ifaceT2I(typ1 *byte, typ2 *byte, elem any) (ret any); +func ifaceI2T(typ *byte, iface any) (ret any); +func ifaceI2T2(typ *byte, iface any) (ret any, ok bool); +func ifaceI2I(typ *byte, iface any) (ret any); +func ifaceI2Ix(typ *byte, iface any) (ret any); +func ifaceI2I2(typ *byte, iface any) (ret any, ok bool); func ifaceeq(i1 any, i2 any) (ret bool); func efaceeq(i1 any, i2 any) (ret bool); func ifacethash(i1 any) (ret uint32); diff --git a/src/pkg/runtime/Makefile b/src/pkg/runtime/Makefile index 4e932b0525..f3eb4046a0 100644 --- a/src/pkg/runtime/Makefile +++ b/src/pkg/runtime/Makefile @@ -70,6 +70,7 @@ OFILES=\ 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 6c933b1b2a..cc9eb7eede 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 @@ itype(Sigi *si, Sigt *st, int32 canfail) 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 @@ itype(Sigi *si, Sigt *st, int32 canfail) // 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 @@ itype(Sigi *si, Sigt *st, int32 canfail) } } - 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 @@ copyin(Sigt *st, void *src, void **dst) } 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 @@ copyout(Sigt *st, void **src, void *dst) 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 @@ sys·ifaceE2T2(Sigt *st, Eface e, ...) 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 @@ sys·ifaceI2I(Sigi *si, Iface i, Iface ret) // 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 @@ sys·ifaceI2Ix(Sigi *si, Iface i, Iface ret) // 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 @@ sys·ifaceI2I2(Sigi *si, Iface i, Iface ret, bool ok) // 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 @@ sys·ifaceE2I2(Sigi *si, Eface e, Iface ret, bool ok) } 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 @@ ifacehash1(void *data, Sigt *sigt) 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 @@ efacehash(Eface a) } 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 @@ ifaceeq1(void *data1, void *data2, Sigt *sigt) 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 @@ sys·efaceeq(Eface e1, Eface e2, bool ret) 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 @@ sys·ifacethash(Iface i1, uint32 ret) 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 @@ sys·printeface(Eface e) } 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; ilink) { - // 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; iname, (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) -{ - Sigt *sigt; - - ret = nileface; - - if(cmpstring(type, emptystring) == 0) - goto out; - - if(type.len > 10 && mcmp(type.str, (byte*)"interface ", 10) == 0) { - printf("unsafe.Unreflect: cannot put %S in interface\n", type); - throw("unsafe.Unreflect"); - } - - // 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: + if(e.type == nil) { + ret.type = nil; + ret.data = nil; + } else + ret = *(Eface*)e.type; FLUSH(&ret); } +void +unsafe·Reflect(Eface e, Eface rettype, void *retaddr) +{ + uintptr *p; + uintptr x; + + 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); + + // 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); +} + +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; + } + + FLUSH(&e); +} + diff --git a/src/pkg/runtime/print.c b/src/pkg/runtime/print.c index c7e09030e1..c9929cd454 100644 --- a/src/pkg/runtime/print.c +++ b/src/pkg/runtime/print.c @@ -76,10 +76,10 @@ printf(int8 *s, ...) 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 8f1cfa73b8..26dfe70167 100644 --- a/src/pkg/runtime/runtime.h +++ b/src/pkg/runtime/runtime.h @@ -56,9 +56,9 @@ typedef struct Usema Usema; 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 String }; struct Iface { - Itype* type; + Itab* tab; void* data; }; struct Eface { - Sigt* type; + Type* type; void* data; };