diff options
| author | Russ Cox <rsc@golang.org> | 2009-05-20 14:57:55 -0700 |
|---|---|---|
| committer | Russ Cox <rsc@golang.org> | 2009-05-20 14:57:55 -0700 |
| commit | 2da5022bcf578545207ecc0ed0a8c7669e7f708f (patch) | |
| tree | 262689682751a1adebce9c4281e1ab77eb480cb4 /src/runtime | |
| parent | 47e5152790e6dab326237259e4898da22917342a (diff) | |
| download | go-2da5022bcf578545207ecc0ed0a8c7669e7f708f.tar.xz | |
change representation of interface values.
this is not a user-visible change.
before, all interface values were
struct Itype {
Sigt *type;
Sigi *inter;
void *method[n];
}
struct Iface {
void *addr;
Itype *itype;
}
the itype is basically a vtable, but it's unnecessary
if the static type is interface{ }.
for interface values with static type empty, the
new representation is
struct Eface {
void *addr;
Sigt *type;
}
this complicates the code somewhat, but
it reduces the number of Itypes that
have to be computed and cached,
it opens up opportunities to avoid function
calls in a few common cases,
and it will make it possible to lay out
interface{} values at compile time,
which i think i'll need for the new reflection.
R=ken
OCL=28701
CL=29121
Diffstat (limited to 'src/runtime')
| -rw-r--r-- | src/runtime/iface.c | 441 | ||||
| -rw-r--r-- | src/runtime/runtime.c | 24 | ||||
| -rw-r--r-- | src/runtime/runtime.h | 16 |
3 files changed, 306 insertions, 175 deletions
diff --git a/src/runtime/iface.c b/src/runtime/iface.c index cad7370c5f..9e65a267aa 100644 --- a/src/runtime/iface.c +++ b/src/runtime/iface.c @@ -53,6 +53,8 @@ struct Itype }; static Iface niliface; +static Eface nileface; + static Itype* hash[1009]; static Lock ifacelock; @@ -129,6 +131,16 @@ printiface(Iface i) 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) { @@ -138,6 +150,17 @@ itype(Sigi *si, Sigt *st, int32 canfail) byte *sname, *iname; Itype *m; + if(si->size == 0) + throw("internal error - misuse of itype"); + + // easy case + if(st->meth[0].fname == nil) { + if(canfail) + return nil; + iname = si->meth[0].fname; + goto throw1; + } + // compiler has provided some good hash codes for us. h = 0; if(si) @@ -169,7 +192,6 @@ itype(Sigi *si, Sigt *st, int32 canfail) goto throw; } } - // prints("old itype\n"); if(locked) unlock(&ifacelock); return m; @@ -199,6 +221,7 @@ throw: sname = st->meth[nt].fname; if(sname == nil) { if(!canfail) { + throw1: printf("cannot convert type %s to interface %s: missing method %s\n", st->name, si->name, iname); if(iface_debug) { @@ -209,6 +232,7 @@ throw: prints("\n"); } throw("interface conversion"); + return nil; // not reached } m->bad = 1; m->link = hash[h]; @@ -227,124 +251,108 @@ throw: if(locked) unlock(&ifacelock); - // printf("new itype %p\n", m); return m; } +static void +copyin(Sigt *st, void *src, void **dst) +{ + int32 wid, alg; + void *p; + + wid = st->width; + alg = st->alg; + + if(wid <= sizeof(*dst)) + algarray[alg].copy(wid, dst, src); + else { + p = mal(wid); + algarray[alg].copy(wid, p, src); + *dst = p; + } +} + +static void +copyout(Sigt *st, void **src, void *dst) +{ + int32 wid, alg; + + wid = st->width; + alg = st->alg; + + if(wid <= sizeof(*src)) + algarray[alg].copy(wid, dst, src); + else + algarray[alg].copy(wid, dst, *src); +} + // ifaceT2I(sigi *byte, sigt *byte, elem any) (ret any); +#pragma textflag 7 void sys·ifaceT2I(Sigi *si, Sigt *st, ...) { byte *elem; Iface *ret; - int32 alg, wid; + int32 wid; elem = (byte*)(&st+1); - - if(iface_debug) { - prints("T2I sigi="); - printsigi(si); - prints(" sigt="); - printsigt(st); - prints(" elem="); - sys·printpointer(*(void**)elem); - prints("\n"); - } - wid = st->width; - alg = st->alg; ret = (Iface*)(elem + rnd(wid, sizeof(uintptr))); + ret->type = itype(si, st, 0); + copyin(st, elem, &ret->data); +} - if(wid <= sizeof(ret->data)) - algarray[alg].copy(wid, &ret->data, elem); - else { - ret->data = mal(wid); - if(iface_debug) - printf("T2I mal %d %p\n", wid, ret->data); - algarray[alg].copy(wid, ret->data, elem); - } +// ifaceT2E(sigt *byte, elem any) (ret any); +#pragma textflag 7 +void +sys·ifaceT2E(Sigt *st, ...) +{ + byte *elem; + Eface *ret; + int32 wid; - if(iface_debug) { - prints("T2I ret="); - printiface(*ret); - prints("\n"); - } + elem = (byte*)(&st+1); + wid = st->width; + ret = (Eface*)(elem + rnd(wid, sizeof(uintptr))); - FLUSH(&ret); + ret->type = st; + copyin(st, elem, &ret->data); } // ifaceI2T(sigt *byte, iface any) (ret any); +#pragma textflag 7 void sys·ifaceI2T(Sigt *st, Iface i, ...) { Itype *im; byte *ret; - int32 wid, alg; ret = (byte*)(&i+1); - if(iface_debug) { - prints("I2T sigt="); - printsigt(st); - prints(" iface="); - printiface(i); - prints("\n"); - } - im = i.type; if(im == nil) { - prints("interface is nil, not "); - prints((int8*)st->name); - prints("\n"); + printf("interface is nil, not %s\n", st->name); throw("interface conversion"); } - if(im->sigt != st) { - prints((int8*)im->sigi->name); - prints(" is "); - prints((int8*)im->sigt->name); - prints(", not "); - prints((int8*)st->name); - prints("\n"); + printf("%s is %s, not %s\n", im->sigi->name, im->sigt->name, st->name); throw("interface conversion"); } - - alg = st->alg; - wid = st->width; - if(wid <= sizeof(i.data)) - algarray[alg].copy(wid, ret, &i.data); - else - algarray[alg].copy(wid, ret, i.data); - - if(iface_debug) { - prints("I2T ret="); - sys·printpointer(*(void**)ret); - prints("\n"); - } - FLUSH(&ret); + copyout(st, &i.data, ret); } // ifaceI2T2(sigt *byte, iface any) (ret any, ok bool); +#pragma textflag 7 void sys·ifaceI2T2(Sigt *st, Iface i, ...) { byte *ret; bool *ok; Itype *im; - int32 alg, wid; - - - if(iface_debug) { - prints("I2T2 sigt="); - printsigt(st); - prints(" iface="); - printiface(i); - prints("\n"); - } + int32 wid; ret = (byte*)(&i+1); - alg = st->alg; wid = st->width; ok = (bool*)(ret+rnd(wid, 1)); @@ -352,19 +360,74 @@ sys·ifaceI2T2(Sigt *st, Iface i, ...) if(im == nil || im->sigt != st) { *ok = false; sys·memclr(ret, wid); - } else { - *ok = true; - if(wid <= sizeof(i.data)) - algarray[alg].copy(wid, ret, &i.data); - else - algarray[alg].copy(wid, ret, i.data); + return; + } + + *ok = true; + copyout(st, &i.data, ret); +} + +// ifaceE2T(sigt *byte, iface any) (ret any); +#pragma textflag 7 +void +sys·ifaceE2T(Sigt *st, 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); + throw("interface conversion"); } - if(iface_debug) { - prints("I2T2 ret="); - sys·printpointer(*(void**)ret); - sys·printbool(*ok); - prints("\n"); + if(t != st) { + printf("interface is %s, not %s\n", t->name, st->name); + throw("interface conversion"); } + copyout(st, &e.data, ret); +} + +// ifaceE2T2(sigt *byte, iface any) (ret any, ok bool); +#pragma textflag 7 +void +sys·ifaceE2T2(Sigt *st, Eface e, ...) +{ + byte *ret; + bool *ok; + Sigt *t; + int32 wid; + + ret = (byte*)(&e+1); + wid = st->width; + ok = (bool*)(ret+rnd(wid, 1)); + + t = e.type; + if(t != st) { + *ok = false; + sys·memclr(ret, wid); + return; + } + + *ok = true; + copyout(st, &e.data, ret); +} + +// ifaceI2E(sigi *byte, iface any) (ret any); +// TODO(rsc): Move to back end, throw away function. +void +sys·ifaceI2E(Iface i, Eface ret) +{ + Itype *im; + + ret.data = i.data; + im = i.type; + if(im == nil) + ret.type = nil; + else + ret.type = im->sigt; + FLUSH(&ret); } // ifaceI2I(sigi *byte, iface any) (ret any); @@ -373,16 +436,9 @@ sys·ifaceI2I(Sigi *si, Iface i, Iface ret) { Itype *im; - if(iface_debug) { - prints("I2I sigi="); - printsigi(si); - prints(" iface="); - printiface(i); - prints("\n"); - } - im = i.type; if(im == nil) { +//TODO(rsc): fixme // If incoming interface is uninitialized (zeroed) // make the outgoing interface zeroed as well. ret = niliface; @@ -392,12 +448,6 @@ sys·ifaceI2I(Sigi *si, Iface i, Iface ret) ret.type = itype(si, im->sigt, 0); } - if(iface_debug) { - prints("I2I ret="); - printiface(ret); - prints("\n"); - } - FLUSH(&ret); } @@ -407,52 +457,76 @@ sys·ifaceI2I2(Sigi *si, Iface i, Iface ret, bool ok) { Itype *im; - if(iface_debug) { - prints("I2I2 sigi="); - printsigi(si); - prints(" iface="); - printiface(i); - prints("\n"); - } - im = i.type; + ok = true; if(im == nil) { +//TODO: fixme // If incoming interface is uninitialized (zeroed) // make the outgoing interface zeroed as well. ret = niliface; - ok = 1; } else { ret = i; - ok = 1; if(im->sigi != si) { ret.type = itype(si, im->sigt, 1); if(ret.type == nil) { ret = niliface; - ok = 0; + ok = false; } } } - if(iface_debug) { - prints("I2I ret="); - printiface(ret); - prints("\n"); + FLUSH(&ret); + FLUSH(&ok); +} + +// ifaceE2I(sigi *byte, iface any) (ret any); +void +sys·ifaceE2I(Sigi *si, Eface e, Iface ret) +{ + Sigt *t; + + t = e.type; + if(t == nil) { +//TODO(rsc): fixme + ret = niliface; + } else { + ret.data = e.data; + ret.type = itype(si, t, 0); } + FLUSH(&ret); +} + +// ifaceE2I2(sigi *byte, iface any) (ret any, ok bool); +void +sys·ifaceE2I2(Sigi *si, Eface e, Iface ret, bool ok) +{ + Sigt *t; + t = e.type; + ok = true; + if(t == nil) { +//TODO(rsc): fixme + ret = niliface; + } else { + ret.data = e.data; + ret.type = itype(si, t, 1); + if(ret.type == nil) { + ret = niliface; + ok = false; + } + } FLUSH(&ret); FLUSH(&ok); } -uint64 -ifacehash(Iface a) +static uint64 +ifacehash1(void *data, Sigt *sigt) { int32 alg, wid; - Sigt *sigt; - if(a.type == nil) + if(sigt == nil) return 0; - sigt = a.type->sigt; alg = sigt->alg; wid = sigt->width; if(algarray[alg].hash == nohash) { @@ -463,69 +537,65 @@ ifacehash(Iface a) throw("fake interface hash"); throw("interface hash"); } - if(wid <= sizeof(a.data)) - return algarray[alg].hash(wid, &a.data); - return algarray[alg].hash(wid, a.data); + if(wid <= sizeof(data)) + return algarray[alg].hash(wid, &data); + return algarray[alg].hash(wid, data); } -bool -ifaceeq(Iface i1, Iface i2) +uint64 +ifacehash(Iface a) { - int32 alg, wid; - bool ret; - - if(iface_debug) { - prints("Ieq i1="); - printiface(i1); - prints(" i2="); - printiface(i2); - prints("\n"); - } - - ret = false; + if(a.type == nil) + return 0; + return ifacehash1(a.data, a.type->sigt); +} - // are they both nil - if(i1.type == nil) { - if(i2.type == nil) - goto yes; - goto no; - } - if(i2.type == nil) - goto no; +uint64 +efacehash(Eface a) +{ + return ifacehash1(a.data, a.type); +} - // are they the same type? - if(i1.type->sigt != i2.type->sigt) - goto no; +static bool +ifaceeq1(void *data1, void *data2, Sigt *sigt) +{ + int32 alg, wid; - alg = i1.type->sigt->alg; - wid = i1.type->sigt->width; + alg = sigt->alg; + wid = sigt->width; if(algarray[alg].equal == noequal) { // calling noequal will throw too, // but we can print a better error. - printf("comparing uncomparable type %s\n", i1.type->sigt->name); + printf("comparing uncomparable type %s\n", sigt->name); if(alg == AFAKE) throw("fake interface compare"); throw("interface compare"); } - if(wid <= sizeof(i1.data)) { - if(!algarray[alg].equal(wid, &i1.data, &i2.data)) - goto no; - } else { - if(!algarray[alg].equal(wid, i1.data, i2.data)) - goto no; - } + if(wid <= sizeof(data1)) + return algarray[alg].equal(wid, &data1, &data2); + return algarray[alg].equal(wid, data1, data2); +} -yes: - ret = true; -no: - if(iface_debug) { - prints("Ieq ret="); - sys·printbool(ret); - prints("\n"); - } - return ret; +bool +ifaceeq(Iface i1, Iface i2) +{ + if(i1.type != i2.type) + return false; + if(i1.type == nil) + return true; + return ifaceeq1(i1.data, i2.data, i1.type->sigt); +} + +bool +efaceeq(Eface e1, Eface e2) +{ + if(e1.type != e2.type) + return false; + if(e1.type == nil) + return true; + return ifaceeq1(e1.data, e2.data, e1.type); } // ifaceeq(i1 any, i2 any) (ret bool); @@ -536,6 +606,14 @@ sys·ifaceeq(Iface i1, Iface i2, bool ret) FLUSH(&ret); } +// efaceeq(i1 any, i2 any) (ret bool) +void +sys·efaceeq(Eface e1, Eface e2, bool ret) +{ + ret = efaceeq(e1, e2); + FLUSH(&ret); +} + // ifacethash(i1 any) (ret uint32); void sys·ifacethash(Iface i1, uint32 ret) @@ -553,14 +631,33 @@ sys·ifacethash(Iface i1, uint32 ret) FLUSH(&ret); } +// efacethash(e1 any) (ret uint32) +void +sys·efacethash(Eface e1, uint32 ret) +{ + Sigt *st; + + ret = 0; + st = e1.type; + if(st != nil) + ret = st->thash; + FLUSH(&ret); +} + void -sys·printinter(Iface i) +sys·printiface(Iface i) { printiface(i); } void -unsafe·Reflect(Iface i, uint64 retit, String rettype, bool retindir) +sys·printeface(Eface e) +{ + printeface(e); +} + +void +unsafe·Reflect(Eface i, uint64 retit, String rettype, bool retindir) { int32 wid; @@ -570,8 +667,8 @@ unsafe·Reflect(Iface i, uint64 retit, String rettype, bool retindir) retindir = false; } else { retit = (uint64)i.data; - rettype = gostring(i.type->sigt->name); - wid = i.type->sigt->width; + rettype = gostring(i.type->name); + wid = i.type->width; retindir = wid > sizeof(i.data); } FLUSH(&retit); @@ -757,11 +854,11 @@ findtype(String type, bool indir) void -unsafe·Unreflect(uint64 it, String type, bool indir, Iface ret) +unsafe·Unreflect(uint64 it, String type, bool indir, Eface ret) { Sigt *sigt; - ret = niliface; + ret = nileface; if(cmpstring(type, emptystring) == 0) goto out; @@ -777,7 +874,7 @@ unsafe·Unreflect(uint64 it, String type, bool indir, Iface ret) if(indir != (sigt->width > sizeof(ret.data))) goto out; - ret.type = itype(sigi·empty, sigt, 0); + ret.type = sigt; ret.data = (void*)it; out: diff --git a/src/runtime/runtime.c b/src/runtime/runtime.c index afb9cce172..57e2570905 100644 --- a/src/runtime/runtime.c +++ b/src/runtime/runtime.c @@ -363,7 +363,7 @@ static void interprint(uint32 s, Iface *a) { USED(s); - sys·printinter(*a); + sys·printiface(*a); } static uint32 @@ -373,6 +373,27 @@ interequal(uint32 s, Iface *a, Iface *b) return ifaceeq(*a, *b); } +static uint64 +nilinterhash(uint32 s, Eface *a) +{ + USED(s); + return efacehash(*a); +} + +static void +nilinterprint(uint32 s, Eface *a) +{ + USED(s); + sys·printeface(*a); +} + +static uint32 +nilinterequal(uint32 s, Eface *a, Eface *b) +{ + USED(s); + return efaceeq(*a, *b); +} + uint64 nohash(uint32 s, void *a) { @@ -416,6 +437,7 @@ algarray[] = [ANOEQ] { nohash, noequal, memprint, memcopy }, [ASTRING] { strhash, strequal, strprint, memcopy }, [AINTER] { interhash, interequal, interprint, memcopy }, +[ANILINTER] { nilinterhash, nilinterequal, nilinterprint, memcopy }, [AFAKE] { nohash, noequal, noprint, nocopy }, }; diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h index 68d3748f37..f2926037aa 100644 --- a/src/runtime/runtime.h +++ b/src/runtime/runtime.h @@ -57,6 +57,8 @@ typedef struct SigTab SigTab; typedef struct MCache MCache; typedef struct Iface Iface; typedef struct Itype Itype; +typedef struct Eface Eface; +typedef struct Sigt Sigt; typedef struct Defer Defer; /* @@ -118,6 +120,11 @@ struct Iface Itype* type; void* data; }; +struct Eface +{ + Sigt* type; + void* data; +}; struct Array { // must not move anything @@ -238,6 +245,7 @@ enum ANOEQ, ASTRING, AINTER, + ANILINTER, AFAKE, Amax }; @@ -323,7 +331,9 @@ void stackfree(void*); MCache* allocmcache(void); void mallocinit(void); bool ifaceeq(Iface, Iface); +bool efaceeq(Eface, Eface); uint64 ifacehash(Iface); +uint64 efacehash(Eface); uint64 nohash(uint32, void*); uint32 noequal(uint32, void*, void*); void* malloc(uintptr size); @@ -396,7 +406,8 @@ void notewakeup(Note*); #define sys_printfloat sys·printfloat #define sys_printhex sys·printhex #define sys_printint sys·printint -#define sys_printinter sys·printinter +#define sys_printiface sys·printiface +#define sys_printeface sys·printeface #define sys_printpc sys·printpc #define sys_printpointer sys·printpointer #define sys_printstring sys·printstring @@ -420,7 +431,8 @@ void* sys_getcallerpc(void*); void sys_printbool(bool); void sys_printfloat(float64); void sys_printint(int64); -void sys_printinter(Iface); +void sys_printiface(Iface); +void sys_printeface(Eface); void sys_printstring(String); void sys_printpc(void*); void sys_printpointer(void*); |
