2008-09-22 13:16:19 -06:00
|
|
|
// Copyright 2009 The Go Authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
#include "runtime.h"
|
2009-07-07 12:02:54 -06:00
|
|
|
#include "type.h"
|
2008-09-22 13:16:19 -06:00
|
|
|
|
2009-07-07 12:02:54 -06:00
|
|
|
static void
|
|
|
|
printiface(Iface i)
|
|
|
|
{
|
|
|
|
printf("(%p,%p)", i.tab, i.data);
|
|
|
|
}
|
2008-09-22 17:58:30 -06:00
|
|
|
|
2009-07-07 12:02:54 -06:00
|
|
|
static void
|
|
|
|
printeface(Eface e)
|
|
|
|
{
|
|
|
|
printf("(%p,%p)", e.type, e.data);
|
|
|
|
}
|
2008-09-22 13:16:19 -06:00
|
|
|
|
2008-12-19 13:05:22 -07:00
|
|
|
/*
|
2009-07-07 12:02:54 -06:00
|
|
|
* layout of Itab known to compilers
|
2008-12-19 13:05:22 -07:00
|
|
|
*/
|
2009-07-07 12:02:54 -06:00
|
|
|
struct Itab
|
2008-09-22 13:16:19 -06:00
|
|
|
{
|
2009-07-07 12:02:54 -06:00
|
|
|
InterfaceType* inter;
|
|
|
|
Type* type;
|
|
|
|
Itab* link;
|
2008-09-22 13:16:19 -06:00
|
|
|
int32 bad;
|
|
|
|
int32 unused;
|
|
|
|
void (*fun[])(void);
|
|
|
|
};
|
|
|
|
|
2009-07-07 12:02:54 -06:00
|
|
|
static Itab* hash[1009];
|
2009-01-26 13:36:21 -07:00
|
|
|
static Lock ifacelock;
|
2008-09-22 17:58:30 -06:00
|
|
|
|
2009-07-07 12:02:54 -06:00
|
|
|
static Itab*
|
|
|
|
itab(InterfaceType *inter, Type *type, int32 canfail)
|
2008-09-22 13:16:19 -06:00
|
|
|
{
|
2009-01-26 13:36:21 -07:00
|
|
|
int32 locked;
|
2009-07-07 12:02:54 -06:00
|
|
|
int32 ni;
|
|
|
|
Method *t, *et;
|
|
|
|
IMethod *i, *ei;
|
2008-09-22 13:16:19 -06:00
|
|
|
uint32 ihash, h;
|
2009-07-07 12:02:54 -06:00
|
|
|
String *iname;
|
|
|
|
Itab *m;
|
|
|
|
UncommonType *x;
|
2008-09-22 13:16:19 -06:00
|
|
|
|
2009-08-25 16:54:25 -06:00
|
|
|
if(inter->mhdr.len == 0)
|
2009-07-07 12:02:54 -06:00
|
|
|
throw("internal error - misuse of itab");
|
2009-05-20 15:57:55 -06:00
|
|
|
|
|
|
|
// easy case
|
2009-07-07 12:02:54 -06:00
|
|
|
x = type->x;
|
|
|
|
if(x == nil) {
|
2009-05-20 15:57:55 -06:00
|
|
|
if(canfail)
|
|
|
|
return nil;
|
2009-07-07 12:02:54 -06:00
|
|
|
iname = inter->m[0].name;
|
|
|
|
goto throw;
|
2009-05-20 15:57:55 -06:00
|
|
|
}
|
|
|
|
|
2009-01-26 13:36:21 -07:00
|
|
|
// compiler has provided some good hash codes for us.
|
2009-07-07 12:02:54 -06:00
|
|
|
h = inter->hash;
|
|
|
|
h += 17 * type->hash;
|
|
|
|
// TODO(rsc): h += 23 * x->mhash ?
|
2009-01-26 13:36:21 -07:00
|
|
|
h %= nelem(hash);
|
|
|
|
|
|
|
|
// look twice - once without lock, once with.
|
|
|
|
// common case will be no lock contention.
|
|
|
|
for(locked=0; locked<2; locked++) {
|
|
|
|
if(locked)
|
|
|
|
lock(&ifacelock);
|
|
|
|
for(m=hash[h]; m!=nil; m=m->link) {
|
2009-07-07 12:02:54 -06:00
|
|
|
if(m->inter == inter && m->type == type) {
|
2009-01-26 13:36:21 -07:00
|
|
|
if(m->bad) {
|
|
|
|
m = nil;
|
|
|
|
if(!canfail) {
|
|
|
|
// this can only happen if the conversion
|
|
|
|
// was already done once using the , ok form
|
|
|
|
// and we have a cached negative result.
|
|
|
|
// the cached result doesn't record which
|
|
|
|
// interface function was missing, so jump
|
|
|
|
// down to the interface check, which will
|
2009-07-07 12:02:54 -06:00
|
|
|
// do more work but give a better error.
|
|
|
|
goto search;
|
2009-01-26 13:36:21 -07:00
|
|
|
}
|
2008-11-05 14:05:01 -07:00
|
|
|
}
|
2009-01-26 13:36:21 -07:00
|
|
|
if(locked)
|
|
|
|
unlock(&ifacelock);
|
|
|
|
return m;
|
2008-09-22 13:16:19 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-02-02 19:59:20 -07:00
|
|
|
|
2009-08-25 16:54:25 -06:00
|
|
|
ni = inter->mhdr.len;
|
2009-07-07 12:02:54 -06:00
|
|
|
m = malloc(sizeof(*m) + ni*sizeof m->fun[0]);
|
|
|
|
m->inter = inter;
|
|
|
|
m->type = type;
|
|
|
|
|
|
|
|
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;
|
2009-08-25 16:54:25 -06:00
|
|
|
ei = i + inter->mhdr.len;
|
2009-07-07 12:02:54 -06:00
|
|
|
t = x->m;
|
2009-08-25 16:54:25 -06:00
|
|
|
et = t + x->mhdr.len;
|
2009-07-07 12:02:54 -06:00
|
|
|
for(; i < ei; i++) {
|
|
|
|
ihash = i->hash;
|
|
|
|
iname = i->name;
|
|
|
|
for(;; t++) {
|
|
|
|
if(t >= et) {
|
2008-10-21 16:38:26 -06:00
|
|
|
if(!canfail) {
|
2009-07-07 12:02:54 -06:00
|
|
|
throw:
|
|
|
|
// didn't find method
|
|
|
|
printf("%S is not %S: missing method %S\n",
|
|
|
|
*type->string, *inter->string, *iname);
|
2008-10-21 16:38:26 -06:00
|
|
|
throw("interface conversion");
|
2009-05-20 15:57:55 -06:00
|
|
|
return nil; // not reached
|
2008-10-21 16:38:26 -06:00
|
|
|
}
|
2008-09-30 15:02:53 -06:00
|
|
|
m->bad = 1;
|
2009-07-07 12:02:54 -06:00
|
|
|
goto out;
|
2008-09-30 15:02:53 -06:00
|
|
|
}
|
2009-07-07 12:02:54 -06:00
|
|
|
if(t->hash == ihash && t->name == iname)
|
2008-09-30 15:02:53 -06:00
|
|
|
break;
|
|
|
|
}
|
2009-07-07 12:02:54 -06:00
|
|
|
if(m)
|
|
|
|
m->fun[i->perm] = t->ifn;
|
2008-09-22 13:16:19 -06:00
|
|
|
}
|
2009-07-07 12:02:54 -06:00
|
|
|
|
|
|
|
out:
|
2008-09-30 15:02:53 -06:00
|
|
|
m->link = hash[h];
|
|
|
|
hash[h] = m;
|
2009-01-26 13:36:21 -07:00
|
|
|
if(locked)
|
|
|
|
unlock(&ifacelock);
|
2009-07-07 12:02:54 -06:00
|
|
|
if(m->bad)
|
|
|
|
return nil;
|
2008-09-30 15:02:53 -06:00
|
|
|
return m;
|
2008-09-22 13:16:19 -06:00
|
|
|
}
|
|
|
|
|
2009-05-20 15:57:55 -06:00
|
|
|
static void
|
2009-07-07 12:02:54 -06:00
|
|
|
copyin(Type *t, void *src, void **dst)
|
2009-05-20 15:57:55 -06:00
|
|
|
{
|
|
|
|
int32 wid, alg;
|
|
|
|
void *p;
|
|
|
|
|
2009-07-07 12:02:54 -06:00
|
|
|
wid = t->size;
|
|
|
|
alg = t->alg;
|
2009-05-20 15:57:55 -06:00
|
|
|
|
|
|
|
if(wid <= sizeof(*dst))
|
|
|
|
algarray[alg].copy(wid, dst, src);
|
|
|
|
else {
|
|
|
|
p = mal(wid);
|
|
|
|
algarray[alg].copy(wid, p, src);
|
|
|
|
*dst = p;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2009-07-07 12:02:54 -06:00
|
|
|
copyout(Type *t, void **src, void *dst)
|
2009-05-20 15:57:55 -06:00
|
|
|
{
|
|
|
|
int32 wid, alg;
|
|
|
|
|
2009-07-07 12:02:54 -06:00
|
|
|
wid = t->size;
|
|
|
|
alg = t->alg;
|
2009-05-20 15:57:55 -06:00
|
|
|
|
|
|
|
if(wid <= sizeof(*src))
|
|
|
|
algarray[alg].copy(wid, dst, src);
|
|
|
|
else
|
|
|
|
algarray[alg].copy(wid, dst, *src);
|
|
|
|
}
|
|
|
|
|
2009-07-07 12:02:54 -06:00
|
|
|
// ifaceT2I(sigi *byte, sigt *byte, elem any) (ret Iface);
|
2009-05-20 15:57:55 -06:00
|
|
|
#pragma textflag 7
|
2008-09-22 13:16:19 -06:00
|
|
|
void
|
2009-07-07 12:02:54 -06:00
|
|
|
sys·ifaceT2I(InterfaceType *inter, Type *t, ...)
|
2008-09-22 13:16:19 -06:00
|
|
|
{
|
2008-12-19 18:11:54 -07:00
|
|
|
byte *elem;
|
|
|
|
Iface *ret;
|
2009-05-20 15:57:55 -06:00
|
|
|
int32 wid;
|
2008-12-19 18:11:54 -07:00
|
|
|
|
2009-07-07 12:02:54 -06:00
|
|
|
elem = (byte*)(&t+1);
|
|
|
|
wid = t->size;
|
|
|
|
ret = (Iface*)(elem + rnd(wid, Structrnd));
|
|
|
|
ret->tab = itab(inter, t, 0);
|
|
|
|
copyin(t, elem, &ret->data);
|
2009-05-20 15:57:55 -06:00
|
|
|
}
|
2009-03-16 16:27:08 -06:00
|
|
|
|
2009-07-07 12:02:54 -06:00
|
|
|
// ifaceT2E(sigt *byte, elem any) (ret Eface);
|
2009-05-20 15:57:55 -06:00
|
|
|
#pragma textflag 7
|
|
|
|
void
|
2009-07-07 12:02:54 -06:00
|
|
|
sys·ifaceT2E(Type *t, ...)
|
2009-05-20 15:57:55 -06:00
|
|
|
{
|
|
|
|
byte *elem;
|
|
|
|
Eface *ret;
|
|
|
|
int32 wid;
|
2008-09-22 13:16:19 -06:00
|
|
|
|
2009-07-07 12:02:54 -06:00
|
|
|
elem = (byte*)(&t+1);
|
|
|
|
wid = t->size;
|
|
|
|
ret = (Eface*)(elem + rnd(wid, Structrnd));
|
2008-09-22 13:16:19 -06:00
|
|
|
|
2009-07-07 12:02:54 -06:00
|
|
|
ret->type = t;
|
|
|
|
copyin(t, elem, &ret->data);
|
2008-09-22 13:16:19 -06:00
|
|
|
}
|
|
|
|
|
2008-09-22 17:58:30 -06:00
|
|
|
// ifaceI2T(sigt *byte, iface any) (ret any);
|
2009-05-20 15:57:55 -06:00
|
|
|
#pragma textflag 7
|
2008-09-22 13:16:19 -06:00
|
|
|
void
|
2009-07-07 12:02:54 -06:00
|
|
|
sys·ifaceI2T(Type *t, Iface i, ...)
|
2008-09-22 13:16:19 -06:00
|
|
|
{
|
2009-07-07 12:02:54 -06:00
|
|
|
Itab *tab;
|
2008-12-19 18:11:54 -07:00
|
|
|
byte *ret;
|
|
|
|
|
|
|
|
ret = (byte*)(&i+1);
|
2009-07-07 12:02:54 -06:00
|
|
|
tab = i.tab;
|
|
|
|
if(tab == nil) {
|
|
|
|
printf("interface is nil, not %S\n", *t->string);
|
2008-11-05 14:05:01 -07:00
|
|
|
throw("interface conversion");
|
|
|
|
}
|
2009-07-07 12:02:54 -06:00
|
|
|
if(tab->type != t) {
|
|
|
|
printf("%S is %S, not %S\n", *tab->inter->string, *tab->type->string, *t->string);
|
2008-11-05 14:05:01 -07:00
|
|
|
throw("interface conversion");
|
|
|
|
}
|
2009-07-07 12:02:54 -06:00
|
|
|
copyout(t, &i.data, ret);
|
2008-11-03 18:34:37 -07:00
|
|
|
}
|
|
|
|
|
2009-07-07 12:02:54 -06:00
|
|
|
// ifaceI2T2(sigt *byte, i Iface) (ret any, ok bool);
|
2009-05-20 15:57:55 -06:00
|
|
|
#pragma textflag 7
|
2008-11-03 18:34:37 -07:00
|
|
|
void
|
2009-07-07 12:02:54 -06:00
|
|
|
sys·ifaceI2T2(Type *t, Iface i, ...)
|
2008-11-03 18:34:37 -07:00
|
|
|
{
|
2008-12-19 18:11:54 -07:00
|
|
|
byte *ret;
|
|
|
|
bool *ok;
|
2009-05-20 15:57:55 -06:00
|
|
|
int32 wid;
|
2008-09-22 13:16:19 -06:00
|
|
|
|
2009-03-16 16:27:08 -06:00
|
|
|
ret = (byte*)(&i+1);
|
2009-07-07 12:02:54 -06:00
|
|
|
wid = t->size;
|
2009-03-16 16:27:08 -06:00
|
|
|
ok = (bool*)(ret+rnd(wid, 1));
|
|
|
|
|
2009-07-07 12:02:54 -06:00
|
|
|
if(i.tab == nil || i.tab->type != t) {
|
2008-12-19 18:11:54 -07:00
|
|
|
*ok = false;
|
|
|
|
sys·memclr(ret, wid);
|
2009-05-20 15:57:55 -06:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
*ok = true;
|
2009-07-07 12:02:54 -06:00
|
|
|
copyout(t, &i.data, ret);
|
2009-05-20 15:57:55 -06:00
|
|
|
}
|
|
|
|
|
2009-07-07 12:02:54 -06:00
|
|
|
// ifaceE2T(sigt *byte, e Eface) (ret any);
|
2009-05-20 15:57:55 -06:00
|
|
|
#pragma textflag 7
|
|
|
|
void
|
2009-07-07 12:02:54 -06:00
|
|
|
sys·ifaceE2T(Type *t, Eface e, ...)
|
2009-05-20 15:57:55 -06:00
|
|
|
{
|
|
|
|
byte *ret;
|
|
|
|
|
|
|
|
ret = (byte*)(&e+1);
|
|
|
|
|
2009-07-07 12:02:54 -06:00
|
|
|
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);
|
2009-05-20 15:57:55 -06:00
|
|
|
throw("interface conversion");
|
2008-11-03 18:34:37 -07:00
|
|
|
}
|
2009-07-07 12:02:54 -06:00
|
|
|
copyout(t, &e.data, ret);
|
2009-05-20 15:57:55 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// ifaceE2T2(sigt *byte, iface any) (ret any, ok bool);
|
|
|
|
#pragma textflag 7
|
|
|
|
void
|
2009-07-07 12:02:54 -06:00
|
|
|
sys·ifaceE2T2(Type *t, Eface e, ...)
|
2009-05-20 15:57:55 -06:00
|
|
|
{
|
|
|
|
byte *ret;
|
|
|
|
bool *ok;
|
|
|
|
int32 wid;
|
|
|
|
|
|
|
|
ret = (byte*)(&e+1);
|
2009-07-07 12:02:54 -06:00
|
|
|
wid = t->size;
|
2009-05-20 15:57:55 -06:00
|
|
|
ok = (bool*)(ret+rnd(wid, 1));
|
|
|
|
|
2009-07-07 12:02:54 -06:00
|
|
|
if(t != e.type) {
|
2009-05-20 15:57:55 -06:00
|
|
|
*ok = false;
|
|
|
|
sys·memclr(ret, wid);
|
|
|
|
return;
|
2008-11-03 18:34:37 -07:00
|
|
|
}
|
2009-05-20 15:57:55 -06:00
|
|
|
|
|
|
|
*ok = true;
|
2009-07-07 12:02:54 -06:00
|
|
|
copyout(t, &e.data, ret);
|
2009-05-20 15:57:55 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// ifaceI2E(sigi *byte, iface any) (ret any);
|
|
|
|
// TODO(rsc): Move to back end, throw away function.
|
|
|
|
void
|
|
|
|
sys·ifaceI2E(Iface i, Eface ret)
|
|
|
|
{
|
2009-07-07 12:02:54 -06:00
|
|
|
Itab *tab;
|
2009-05-20 15:57:55 -06:00
|
|
|
|
|
|
|
ret.data = i.data;
|
2009-07-07 12:02:54 -06:00
|
|
|
tab = i.tab;
|
|
|
|
if(tab == nil)
|
2009-05-20 15:57:55 -06:00
|
|
|
ret.type = nil;
|
|
|
|
else
|
2009-07-07 12:02:54 -06:00
|
|
|
ret.type = tab->type;
|
2009-05-20 15:57:55 -06:00
|
|
|
FLUSH(&ret);
|
2008-09-22 13:16:19 -06:00
|
|
|
}
|
|
|
|
|
2008-09-22 17:58:30 -06:00
|
|
|
// ifaceI2I(sigi *byte, iface any) (ret any);
|
2009-07-07 12:02:54 -06:00
|
|
|
// called only for implicit (no type assertion) conversions.
|
|
|
|
// converting nil is okay.
|
2008-09-22 13:16:19 -06:00
|
|
|
void
|
2009-07-07 12:02:54 -06:00
|
|
|
sys·ifaceI2I(InterfaceType *inter, Iface i, Iface ret)
|
2008-09-22 13:16:19 -06:00
|
|
|
{
|
2009-07-07 12:02:54 -06:00
|
|
|
Itab *tab;
|
2008-12-19 18:11:54 -07:00
|
|
|
|
2009-07-07 12:02:54 -06:00
|
|
|
tab = i.tab;
|
|
|
|
if(tab == nil) {
|
2008-10-10 17:21:50 -06:00
|
|
|
// If incoming interface is uninitialized (zeroed)
|
|
|
|
// make the outgoing interface zeroed as well.
|
2009-07-07 12:02:54 -06:00
|
|
|
ret.tab = nil;
|
|
|
|
ret.data = nil;
|
2008-10-10 17:21:50 -06:00
|
|
|
} else {
|
2008-12-19 18:11:54 -07:00
|
|
|
ret = i;
|
2009-07-07 12:02:54 -06:00
|
|
|
if(tab->inter != inter)
|
|
|
|
ret.tab = itab(inter, tab->type, 0);
|
2008-09-22 13:16:19 -06:00
|
|
|
}
|
|
|
|
|
2008-12-19 18:11:54 -07:00
|
|
|
FLUSH(&ret);
|
2008-09-22 13:16:19 -06:00
|
|
|
}
|
2008-09-22 17:58:30 -06:00
|
|
|
|
2009-05-20 19:23:19 -06:00
|
|
|
// ifaceI2Ix(sigi *byte, iface any) (ret any);
|
|
|
|
// called only for explicit conversions (with type assertion).
|
2009-07-07 12:02:54 -06:00
|
|
|
// converting nil is not okay.
|
2009-05-20 19:23:19 -06:00
|
|
|
void
|
2009-07-07 12:02:54 -06:00
|
|
|
sys·ifaceI2Ix(InterfaceType *inter, Iface i, Iface ret)
|
2009-05-20 19:23:19 -06:00
|
|
|
{
|
2009-07-07 12:02:54 -06:00
|
|
|
Itab *tab;
|
2009-05-20 19:23:19 -06:00
|
|
|
|
2009-07-07 12:02:54 -06:00
|
|
|
tab = i.tab;
|
|
|
|
if(tab == nil) {
|
2009-05-20 19:23:19 -06:00
|
|
|
// explicit conversions require non-nil interface value.
|
2009-07-07 12:02:54 -06:00
|
|
|
printf("interface is nil, not %S\n", *inter->string);
|
2009-05-20 19:23:19 -06:00
|
|
|
throw("interface conversion");
|
|
|
|
} else {
|
|
|
|
ret = i;
|
2009-07-07 12:02:54 -06:00
|
|
|
if(tab->inter != inter)
|
|
|
|
ret.tab = itab(inter, tab->type, 0);
|
2009-05-20 19:23:19 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
FLUSH(&ret);
|
|
|
|
}
|
|
|
|
|
2008-11-03 18:34:37 -07:00
|
|
|
// ifaceI2I2(sigi *byte, iface any) (ret any, ok bool);
|
|
|
|
void
|
2009-07-07 12:02:54 -06:00
|
|
|
sys·ifaceI2I2(InterfaceType *inter, Iface i, Iface ret, bool ok)
|
2008-11-03 18:34:37 -07:00
|
|
|
{
|
2009-07-07 12:02:54 -06:00
|
|
|
Itab *tab;
|
2008-12-19 18:11:54 -07:00
|
|
|
|
2009-07-07 12:02:54 -06:00
|
|
|
tab = i.tab;
|
|
|
|
if(tab == nil) {
|
2009-05-20 19:23:19 -06:00
|
|
|
// If incoming interface is nil, the conversion fails.
|
2009-07-07 12:02:54 -06:00
|
|
|
ret.tab = nil;
|
|
|
|
ret.data = nil;
|
2009-05-20 19:23:19 -06:00
|
|
|
ok = false;
|
2008-11-03 18:34:37 -07:00
|
|
|
} else {
|
2008-12-19 18:11:54 -07:00
|
|
|
ret = i;
|
2009-05-20 19:23:19 -06:00
|
|
|
ok = true;
|
2009-07-07 12:02:54 -06:00
|
|
|
if(tab->inter != inter) {
|
|
|
|
ret.tab = itab(inter, tab->type, 1);
|
|
|
|
if(ret.tab == nil) {
|
|
|
|
ret.data = nil;
|
2009-05-20 15:57:55 -06:00
|
|
|
ok = false;
|
2008-11-03 18:34:37 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-05-20 15:57:55 -06:00
|
|
|
FLUSH(&ret);
|
|
|
|
FLUSH(&ok);
|
|
|
|
}
|
|
|
|
|
|
|
|
// ifaceE2I(sigi *byte, iface any) (ret any);
|
2009-05-20 19:23:19 -06:00
|
|
|
// Called only for explicit conversions (with type assertion).
|
2009-05-20 15:57:55 -06:00
|
|
|
void
|
2009-07-10 17:32:26 -06:00
|
|
|
ifaceE2I(InterfaceType *inter, Eface e, Iface *ret)
|
2009-05-20 15:57:55 -06:00
|
|
|
{
|
2009-07-07 12:02:54 -06:00
|
|
|
Type *t;
|
2009-05-20 15:57:55 -06:00
|
|
|
|
|
|
|
t = e.type;
|
|
|
|
if(t == nil) {
|
2009-05-20 19:23:19 -06:00
|
|
|
// explicit conversions require non-nil interface value.
|
2009-07-07 12:02:54 -06:00
|
|
|
printf("interface is nil, not %S\n", *inter->string);
|
2009-05-20 19:23:19 -06:00
|
|
|
throw("interface conversion");
|
2009-05-20 15:57:55 -06:00
|
|
|
} else {
|
2009-07-10 17:32:26 -06:00
|
|
|
ret->data = e.data;
|
|
|
|
ret->tab = itab(inter, t, 0);
|
2008-11-03 18:34:37 -07:00
|
|
|
}
|
2009-07-10 17:32:26 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// ifaceE2I(sigi *byte, iface any) (ret any);
|
|
|
|
// Called only for explicit conversions (with type assertion).
|
|
|
|
void
|
|
|
|
sys·ifaceE2I(InterfaceType *inter, Eface e, Iface ret)
|
|
|
|
{
|
|
|
|
ifaceE2I(inter, e, &ret);
|
2009-05-20 15:57:55 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// ifaceE2I2(sigi *byte, iface any) (ret any, ok bool);
|
|
|
|
void
|
2009-07-07 12:02:54 -06:00
|
|
|
sys·ifaceE2I2(InterfaceType *inter, Eface e, Iface ret, bool ok)
|
2009-05-20 15:57:55 -06:00
|
|
|
{
|
2009-07-07 12:02:54 -06:00
|
|
|
Type *t;
|
2008-11-03 18:34:37 -07:00
|
|
|
|
2009-05-20 15:57:55 -06:00
|
|
|
t = e.type;
|
|
|
|
ok = true;
|
|
|
|
if(t == nil) {
|
2009-05-20 19:23:19 -06:00
|
|
|
// If incoming interface is nil, the conversion fails.
|
2009-07-07 12:02:54 -06:00
|
|
|
ret.data = nil;
|
|
|
|
ret.tab = nil;
|
2009-05-20 19:23:19 -06:00
|
|
|
ok = false;
|
2009-05-20 15:57:55 -06:00
|
|
|
} else {
|
|
|
|
ret.data = e.data;
|
2009-07-07 12:02:54 -06:00
|
|
|
ret.tab = itab(inter, t, 1);
|
|
|
|
if(ret.tab == nil) {
|
|
|
|
ret.data = nil;
|
2009-05-20 15:57:55 -06:00
|
|
|
ok = false;
|
|
|
|
}
|
|
|
|
}
|
2008-12-19 18:11:54 -07:00
|
|
|
FLUSH(&ret);
|
2008-11-03 18:34:37 -07:00
|
|
|
FLUSH(&ok);
|
|
|
|
}
|
|
|
|
|
2009-06-04 22:09:06 -06:00
|
|
|
static uintptr
|
2009-07-07 12:02:54 -06:00
|
|
|
ifacehash1(void *data, Type *t)
|
2009-01-26 10:56:42 -07:00
|
|
|
{
|
|
|
|
int32 alg, wid;
|
2009-02-02 19:59:20 -07:00
|
|
|
|
2009-07-07 12:02:54 -06:00
|
|
|
if(t == nil)
|
2009-01-26 10:56:42 -07:00
|
|
|
return 0;
|
2009-03-16 16:27:08 -06:00
|
|
|
|
2009-07-07 12:02:54 -06:00
|
|
|
alg = t->alg;
|
|
|
|
wid = t->size;
|
2009-01-26 10:56:42 -07:00
|
|
|
if(algarray[alg].hash == nohash) {
|
|
|
|
// calling nohash will throw too,
|
|
|
|
// but we can print a better error.
|
2009-07-07 12:02:54 -06:00
|
|
|
printf("hash of unhashable type %S\n", *t->string);
|
2009-03-31 18:33:04 -06:00
|
|
|
if(alg == AFAKE)
|
|
|
|
throw("fake interface hash");
|
2009-01-26 10:56:42 -07:00
|
|
|
throw("interface hash");
|
|
|
|
}
|
2009-05-20 15:57:55 -06:00
|
|
|
if(wid <= sizeof(data))
|
|
|
|
return algarray[alg].hash(wid, &data);
|
|
|
|
return algarray[alg].hash(wid, data);
|
2009-01-26 10:56:42 -07:00
|
|
|
}
|
|
|
|
|
2009-06-04 22:09:06 -06:00
|
|
|
uintptr
|
2009-05-20 15:57:55 -06:00
|
|
|
ifacehash(Iface a)
|
2008-10-14 16:08:23 -06:00
|
|
|
{
|
2009-07-07 12:02:54 -06:00
|
|
|
if(a.tab == nil)
|
2009-05-20 15:57:55 -06:00
|
|
|
return 0;
|
2009-07-07 12:02:54 -06:00
|
|
|
return ifacehash1(a.data, a.tab->type);
|
2009-05-20 15:57:55 -06:00
|
|
|
}
|
2008-10-14 16:08:23 -06:00
|
|
|
|
2009-06-04 22:09:06 -06:00
|
|
|
uintptr
|
2009-05-20 15:57:55 -06:00
|
|
|
efacehash(Eface a)
|
|
|
|
{
|
|
|
|
return ifacehash1(a.data, a.type);
|
|
|
|
}
|
2008-10-14 16:08:23 -06:00
|
|
|
|
2009-05-20 15:57:55 -06:00
|
|
|
static bool
|
2009-07-07 12:02:54 -06:00
|
|
|
ifaceeq1(void *data1, void *data2, Type *t)
|
2009-05-20 15:57:55 -06:00
|
|
|
{
|
|
|
|
int32 alg, wid;
|
2008-10-14 16:08:23 -06:00
|
|
|
|
2009-07-07 12:02:54 -06:00
|
|
|
alg = t->alg;
|
|
|
|
wid = t->size;
|
2008-10-14 16:08:23 -06:00
|
|
|
|
2009-01-26 10:56:42 -07:00
|
|
|
if(algarray[alg].equal == noequal) {
|
|
|
|
// calling noequal will throw too,
|
|
|
|
// but we can print a better error.
|
2009-07-07 12:02:54 -06:00
|
|
|
printf("comparing uncomparable type %S\n", *t->string);
|
2009-03-31 18:33:04 -06:00
|
|
|
if(alg == AFAKE)
|
|
|
|
throw("fake interface compare");
|
2009-01-26 10:56:42 -07:00
|
|
|
throw("interface compare");
|
|
|
|
}
|
|
|
|
|
2009-05-20 15:57:55 -06:00
|
|
|
if(wid <= sizeof(data1))
|
|
|
|
return algarray[alg].equal(wid, &data1, &data2);
|
|
|
|
return algarray[alg].equal(wid, data1, data2);
|
|
|
|
}
|
2008-10-14 16:08:23 -06:00
|
|
|
|
2009-05-20 15:57:55 -06:00
|
|
|
bool
|
|
|
|
ifaceeq(Iface i1, Iface i2)
|
|
|
|
{
|
2009-07-07 12:02:54 -06:00
|
|
|
if(i1.tab != i2.tab)
|
2009-05-20 15:57:55 -06:00
|
|
|
return false;
|
2009-07-07 12:02:54 -06:00
|
|
|
if(i1.tab == nil)
|
2009-05-20 15:57:55 -06:00
|
|
|
return true;
|
2009-07-07 12:02:54 -06:00
|
|
|
return ifaceeq1(i1.data, i2.data, i1.tab->type);
|
2009-05-20 15:57:55 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
2009-01-26 10:56:42 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// ifaceeq(i1 any, i2 any) (ret bool);
|
|
|
|
void
|
|
|
|
sys·ifaceeq(Iface i1, Iface i2, bool ret)
|
|
|
|
{
|
|
|
|
ret = ifaceeq(i1, i2);
|
2008-10-14 16:08:23 -06:00
|
|
|
FLUSH(&ret);
|
|
|
|
}
|
|
|
|
|
2009-05-20 15:57:55 -06:00
|
|
|
// efaceeq(i1 any, i2 any) (ret bool)
|
|
|
|
void
|
|
|
|
sys·efaceeq(Eface e1, Eface e2, bool ret)
|
|
|
|
{
|
|
|
|
ret = efaceeq(e1, e2);
|
|
|
|
FLUSH(&ret);
|
|
|
|
}
|
|
|
|
|
2009-03-17 14:58:38 -06:00
|
|
|
// ifacethash(i1 any) (ret uint32);
|
|
|
|
void
|
|
|
|
sys·ifacethash(Iface i1, uint32 ret)
|
|
|
|
{
|
2009-07-07 12:02:54 -06:00
|
|
|
Itab *tab;
|
2009-03-17 14:58:38 -06:00
|
|
|
|
|
|
|
ret = 0;
|
2009-07-07 12:02:54 -06:00
|
|
|
tab = i1.tab;
|
|
|
|
if(tab != nil)
|
|
|
|
ret = tab->type->hash;
|
2009-03-17 14:58:38 -06:00
|
|
|
FLUSH(&ret);
|
|
|
|
}
|
|
|
|
|
2009-05-20 15:57:55 -06:00
|
|
|
// efacethash(e1 any) (ret uint32)
|
|
|
|
void
|
|
|
|
sys·efacethash(Eface e1, uint32 ret)
|
|
|
|
{
|
2009-07-07 12:02:54 -06:00
|
|
|
Type *t;
|
2009-05-20 15:57:55 -06:00
|
|
|
|
|
|
|
ret = 0;
|
2009-07-07 12:02:54 -06:00
|
|
|
t = e1.type;
|
|
|
|
if(t != nil)
|
|
|
|
ret = t->hash;
|
2009-05-20 15:57:55 -06:00
|
|
|
FLUSH(&ret);
|
|
|
|
}
|
|
|
|
|
2008-09-22 17:58:30 -06:00
|
|
|
void
|
2009-05-20 15:57:55 -06:00
|
|
|
sys·printiface(Iface i)
|
2008-09-22 17:58:30 -06:00
|
|
|
{
|
2008-12-19 18:11:54 -07:00
|
|
|
printiface(i);
|
2008-09-22 17:58:30 -06:00
|
|
|
}
|
2008-10-21 16:38:26 -06:00
|
|
|
|
|
|
|
void
|
2009-05-20 15:57:55 -06:00
|
|
|
sys·printeface(Eface e)
|
|
|
|
{
|
|
|
|
printeface(e);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2009-07-07 12:02:54 -06:00
|
|
|
unsafe·Typeof(Eface e, Eface ret)
|
2008-11-03 17:03:12 -07:00
|
|
|
{
|
2009-07-07 12:02:54 -06:00
|
|
|
if(e.type == nil) {
|
|
|
|
ret.type = nil;
|
|
|
|
ret.data = nil;
|
|
|
|
} else
|
|
|
|
ret = *(Eface*)e.type;
|
|
|
|
FLUSH(&ret);
|
2008-11-03 17:03:12 -07:00
|
|
|
}
|
|
|
|
|
2009-07-07 12:02:54 -06:00
|
|
|
void
|
|
|
|
unsafe·Reflect(Eface e, Eface rettype, void *retaddr)
|
2008-11-03 17:03:12 -07:00
|
|
|
{
|
2009-07-07 12:02:54 -06:00
|
|
|
uintptr *p;
|
|
|
|
uintptr x;
|
2009-02-02 19:59:20 -07:00
|
|
|
|
2009-07-07 12:02:54 -06:00
|
|
|
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;
|
2009-01-26 13:36:21 -07:00
|
|
|
}
|
2009-07-07 12:02:54 -06:00
|
|
|
FLUSH(&rettype);
|
|
|
|
FLUSH(&retaddr);
|
2008-11-03 17:03:12 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2009-07-07 12:02:54 -06:00
|
|
|
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;
|
2009-04-14 20:03:57 -06:00
|
|
|
}
|
|
|
|
|
2009-07-07 12:02:54 -06:00
|
|
|
FLUSH(&e);
|
2008-11-03 17:03:12 -07:00
|
|
|
}
|