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-01-08 15:30:00 -07:00
|
|
|
int32 iface_debug = 0;
|
2008-09-22 17:58:30 -06:00
|
|
|
|
2008-09-22 13:16:19 -06:00
|
|
|
typedef struct Sigt Sigt;
|
|
|
|
typedef struct Sigi Sigi;
|
2008-12-19 18:11:54 -07:00
|
|
|
typedef struct Itype Itype;
|
2008-09-22 13:16:19 -06:00
|
|
|
|
2008-12-19 13:05:22 -07:00
|
|
|
/*
|
2008-12-19 18:11:54 -07:00
|
|
|
* the layout of Iface, Sigt and Sigi are known to the compiler
|
2008-12-19 13:05:22 -07:00
|
|
|
*/
|
2008-09-22 13:16:19 -06:00
|
|
|
struct Sigt
|
|
|
|
{
|
2009-03-16 16:27:08 -06:00
|
|
|
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
|
2009-03-30 01:01:07 -06:00
|
|
|
// note: on amd64 there is a 32-bit pad here.
|
2009-03-16 16:27:08 -06:00
|
|
|
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
|
2008-09-22 13:16:19 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
struct Sigi
|
|
|
|
{
|
|
|
|
byte* name;
|
|
|
|
uint32 hash;
|
2009-03-16 16:27:08 -06:00
|
|
|
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
|
2008-09-22 13:16:19 -06:00
|
|
|
};
|
|
|
|
|
2008-12-19 18:11:54 -07:00
|
|
|
struct Itype
|
2008-09-22 13:16:19 -06:00
|
|
|
{
|
|
|
|
Sigi* sigi;
|
|
|
|
Sigt* sigt;
|
2008-12-19 18:11:54 -07:00
|
|
|
Itype* link;
|
2008-09-22 13:16:19 -06:00
|
|
|
int32 bad;
|
|
|
|
int32 unused;
|
|
|
|
void (*fun[])(void);
|
|
|
|
};
|
|
|
|
|
2009-01-09 01:17:46 -07:00
|
|
|
static Iface niliface;
|
2008-12-19 18:11:54 -07:00
|
|
|
static Itype* hash[1009];
|
2009-01-26 13:36:21 -07:00
|
|
|
static Lock ifacelock;
|
2008-09-22 17:58:30 -06:00
|
|
|
|
2008-11-05 12:27:50 -07:00
|
|
|
Sigi sigi·empty[2] = { (byte*)"interface { }" };
|
2008-10-29 17:55:52 -06:00
|
|
|
|
2008-09-22 17:58:30 -06:00
|
|
|
static void
|
|
|
|
printsigi(Sigi *si)
|
|
|
|
{
|
2008-10-08 10:21:57 -06:00
|
|
|
int32 i;
|
2008-09-22 17:58:30 -06:00
|
|
|
byte *name;
|
|
|
|
|
|
|
|
sys·printpointer(si);
|
|
|
|
prints("{");
|
2009-03-16 16:27:08 -06:00
|
|
|
prints((int8*)si->name);
|
2008-12-19 18:11:54 -07:00
|
|
|
prints(":");
|
2009-03-16 16:27:08 -06:00
|
|
|
for(i=0;; i++) {
|
|
|
|
name = si->meth[i].fname;
|
2008-10-03 17:12:21 -06:00
|
|
|
if(name == nil)
|
2008-09-22 17:58:30 -06:00
|
|
|
break;
|
|
|
|
prints("[");
|
|
|
|
sys·printint(i);
|
|
|
|
prints("]\"");
|
|
|
|
prints((int8*)name);
|
|
|
|
prints("\"");
|
2009-03-16 16:27:08 -06:00
|
|
|
sys·printint(si->meth[i].fhash%999);
|
2008-09-22 17:58:30 -06:00
|
|
|
prints("/");
|
2009-03-16 16:27:08 -06:00
|
|
|
sys·printint(si->meth[i].perm);
|
2008-09-22 17:58:30 -06:00
|
|
|
}
|
|
|
|
prints("}");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
printsigt(Sigt *st)
|
|
|
|
{
|
|
|
|
int32 i;
|
|
|
|
byte *name;
|
|
|
|
|
|
|
|
sys·printpointer(st);
|
|
|
|
prints("{");
|
2009-03-16 16:27:08 -06:00
|
|
|
prints((int8*)st->name);
|
2008-12-19 18:11:54 -07:00
|
|
|
prints(":");
|
2009-03-16 16:27:08 -06:00
|
|
|
sys·printint(st->thash%999); // type hash
|
|
|
|
prints(",");
|
|
|
|
sys·printint(st->mhash%999); // method hash
|
|
|
|
prints(",");
|
|
|
|
sys·printint(st->width); // width
|
2008-10-03 17:12:21 -06:00
|
|
|
prints(",");
|
2009-03-16 16:27:08 -06:00
|
|
|
sys·printint(st->alg); // algorithm
|
|
|
|
for(i=0;; i++) {
|
|
|
|
name = st->meth[i].fname;
|
2008-09-22 17:58:30 -06:00
|
|
|
if(name == nil)
|
|
|
|
break;
|
|
|
|
prints("[");
|
|
|
|
sys·printint(i);
|
|
|
|
prints("]\"");
|
|
|
|
prints((int8*)name);
|
|
|
|
prints("\"");
|
2009-03-16 16:27:08 -06:00
|
|
|
sys·printint(st->meth[i].fhash%999);
|
2008-09-28 21:22:31 -06:00
|
|
|
prints("/");
|
2009-03-16 16:27:08 -06:00
|
|
|
sys·printint(st->meth[i].offset);
|
2008-09-22 17:58:30 -06:00
|
|
|
prints("/");
|
2009-03-16 16:27:08 -06:00
|
|
|
sys·printpointer(st->meth[i].fun);
|
2008-09-22 17:58:30 -06:00
|
|
|
}
|
|
|
|
prints("}");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2008-12-19 18:11:54 -07:00
|
|
|
printiface(Iface i)
|
2008-09-22 17:58:30 -06:00
|
|
|
{
|
|
|
|
prints("(");
|
2008-12-19 18:11:54 -07:00
|
|
|
sys·printpointer(i.type);
|
2008-09-22 17:58:30 -06:00
|
|
|
prints(",");
|
2009-01-09 01:17:46 -07:00
|
|
|
sys·printpointer(i.data);
|
2008-09-22 17:58:30 -06:00
|
|
|
prints(")");
|
|
|
|
}
|
2008-09-22 13:16:19 -06:00
|
|
|
|
2008-12-19 18:11:54 -07:00
|
|
|
static Itype*
|
|
|
|
itype(Sigi *si, Sigt *st, int32 canfail)
|
2008-09-22 13:16:19 -06:00
|
|
|
{
|
2009-01-26 13:36:21 -07:00
|
|
|
int32 locked;
|
2008-09-22 17:58:30 -06:00
|
|
|
int32 nt, ni;
|
2008-09-22 13:16:19 -06:00
|
|
|
uint32 ihash, h;
|
|
|
|
byte *sname, *iname;
|
2008-12-19 18:11:54 -07:00
|
|
|
Itype *m;
|
2008-09-22 13:16:19 -06:00
|
|
|
|
2009-01-26 13:36:21 -07:00
|
|
|
// compiler has provided some good hash codes for us.
|
|
|
|
h = 0;
|
|
|
|
if(si)
|
|
|
|
h += si->hash;
|
2009-03-16 16:27:08 -06:00
|
|
|
if(st) {
|
|
|
|
h += st->thash;
|
|
|
|
h += st->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) {
|
|
|
|
if(m->sigi == si && m->sigt == st) {
|
|
|
|
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
|
|
|
|
// give a better error.
|
|
|
|
goto throw;
|
|
|
|
}
|
2008-11-05 14:05:01 -07:00
|
|
|
}
|
2009-01-26 13:36:21 -07:00
|
|
|
// prints("old itype\n");
|
|
|
|
if(locked)
|
|
|
|
unlock(&ifacelock);
|
|
|
|
return m;
|
2008-09-22 13:16:19 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-02-02 19:59:20 -07:00
|
|
|
|
2009-03-16 16:27:08 -06:00
|
|
|
ni = si->size;
|
2009-04-01 01:26:00 -06:00
|
|
|
m = malloc(sizeof(*m) + ni*sizeof(m->fun[0]));
|
2008-09-22 13:16:19 -06:00
|
|
|
m->sigi = si;
|
2008-09-22 17:58:30 -06:00
|
|
|
m->sigt = st;
|
2008-09-22 13:16:19 -06:00
|
|
|
|
2008-11-05 14:05:01 -07:00
|
|
|
throw:
|
2009-03-16 16:27:08 -06:00
|
|
|
nt = 0;
|
|
|
|
for(ni=0;; ni++) {
|
|
|
|
iname = si->meth[ni].fname;
|
2008-10-15 18:08:10 -06:00
|
|
|
if(iname == nil)
|
|
|
|
break;
|
|
|
|
|
2008-09-30 15:02:53 -06:00
|
|
|
// pick up next name from
|
|
|
|
// interface signature
|
2009-03-16 16:27:08 -06:00
|
|
|
ihash = si->meth[ni].fhash;
|
2008-09-30 15:02:53 -06:00
|
|
|
|
|
|
|
for(;; nt++) {
|
|
|
|
// pick up and compare next name
|
|
|
|
// from structure signature
|
2009-03-16 16:27:08 -06:00
|
|
|
sname = st->meth[nt].fname;
|
2008-09-30 15:02:53 -06:00
|
|
|
if(sname == nil) {
|
2008-10-21 16:38:26 -06:00
|
|
|
if(!canfail) {
|
2009-02-02 19:59:20 -07:00
|
|
|
printf("cannot convert type %s to interface %s: missing method %s\n",
|
2009-03-16 16:27:08 -06:00
|
|
|
st->name, si->name, iname);
|
2009-01-21 15:51:57 -07:00
|
|
|
if(iface_debug) {
|
|
|
|
prints("interface");
|
|
|
|
printsigi(si);
|
|
|
|
prints("\ntype");
|
|
|
|
printsigt(st);
|
|
|
|
prints("\n");
|
|
|
|
}
|
2008-10-21 16:38:26 -06:00
|
|
|
throw("interface conversion");
|
|
|
|
}
|
2008-09-30 15:02:53 -06:00
|
|
|
m->bad = 1;
|
|
|
|
m->link = hash[h];
|
|
|
|
hash[h] = m;
|
2009-01-26 13:36:21 -07:00
|
|
|
if(locked)
|
|
|
|
unlock(&ifacelock);
|
2008-09-30 15:02:53 -06:00
|
|
|
return nil;
|
|
|
|
}
|
2009-03-16 16:27:08 -06:00
|
|
|
if(ihash == st->meth[nt].fhash && strcmp(sname, iname) == 0)
|
2008-09-30 15:02:53 -06:00
|
|
|
break;
|
|
|
|
}
|
2009-03-16 16:27:08 -06:00
|
|
|
m->fun[si->meth[ni].perm] = st->meth[nt].fun;
|
2008-09-22 13:16:19 -06:00
|
|
|
}
|
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-03-16 16:27:08 -06:00
|
|
|
|
|
|
|
// printf("new itype %p\n", m);
|
2008-09-30 15:02:53 -06:00
|
|
|
return m;
|
2008-09-22 13:16:19 -06:00
|
|
|
}
|
|
|
|
|
2008-09-22 17:58:30 -06:00
|
|
|
// ifaceT2I(sigi *byte, sigt *byte, elem any) (ret any);
|
2008-09-22 13:16:19 -06:00
|
|
|
void
|
2008-12-19 18:11:54 -07:00
|
|
|
sys·ifaceT2I(Sigi *si, Sigt *st, ...)
|
2008-09-22 13:16:19 -06:00
|
|
|
{
|
2008-12-19 18:11:54 -07:00
|
|
|
byte *elem;
|
|
|
|
Iface *ret;
|
|
|
|
int32 alg, wid;
|
|
|
|
|
|
|
|
elem = (byte*)(&st+1);
|
2008-09-22 13:16:19 -06:00
|
|
|
|
2009-01-08 15:30:00 -07:00
|
|
|
if(iface_debug) {
|
2008-09-22 13:16:19 -06:00
|
|
|
prints("T2I sigi=");
|
|
|
|
printsigi(si);
|
|
|
|
prints(" sigt=");
|
|
|
|
printsigt(st);
|
|
|
|
prints(" elem=");
|
2008-12-19 18:11:54 -07:00
|
|
|
sys·printpointer(*(void**)elem);
|
2008-09-22 13:16:19 -06:00
|
|
|
prints("\n");
|
|
|
|
}
|
|
|
|
|
2009-03-16 16:27:08 -06:00
|
|
|
wid = st->width;
|
|
|
|
alg = st->alg;
|
2009-03-30 01:01:07 -06:00
|
|
|
ret = (Iface*)(elem + rnd(wid, sizeof(uintptr)));
|
2009-03-16 16:27:08 -06:00
|
|
|
ret->type = itype(si, st, 0);
|
|
|
|
|
|
|
|
if(wid <= sizeof(ret->data))
|
2009-01-09 01:17:46 -07:00
|
|
|
algarray[alg].copy(wid, &ret->data, elem);
|
2009-03-16 16:27:08 -06:00
|
|
|
else {
|
2009-01-09 01:17:46 -07:00
|
|
|
ret->data = mal(wid);
|
2009-01-08 15:30:00 -07:00
|
|
|
if(iface_debug)
|
2009-01-09 01:17:46 -07:00
|
|
|
printf("T2I mal %d %p\n", wid, ret->data);
|
|
|
|
algarray[alg].copy(wid, ret->data, elem);
|
2008-12-19 18:11:54 -07:00
|
|
|
}
|
2008-09-22 13:16:19 -06:00
|
|
|
|
2009-01-08 15:30:00 -07:00
|
|
|
if(iface_debug) {
|
2008-09-22 13:16:19 -06:00
|
|
|
prints("T2I ret=");
|
2008-12-19 18:11:54 -07:00
|
|
|
printiface(*ret);
|
2008-09-22 13:16:19 -06:00
|
|
|
prints("\n");
|
|
|
|
}
|
|
|
|
|
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
|
|
|
// ifaceI2T(sigt *byte, iface any) (ret any);
|
2008-09-22 13:16:19 -06:00
|
|
|
void
|
2008-12-19 18:11:54 -07:00
|
|
|
sys·ifaceI2T(Sigt *st, Iface i, ...)
|
2008-09-22 13:16:19 -06:00
|
|
|
{
|
2008-12-19 18:11:54 -07:00
|
|
|
Itype *im;
|
|
|
|
byte *ret;
|
|
|
|
int32 wid, alg;
|
|
|
|
|
|
|
|
ret = (byte*)(&i+1);
|
|
|
|
|
2009-01-08 15:30:00 -07:00
|
|
|
if(iface_debug) {
|
2008-09-22 13:16:19 -06:00
|
|
|
prints("I2T sigt=");
|
|
|
|
printsigt(st);
|
|
|
|
prints(" iface=");
|
2008-12-19 18:11:54 -07:00
|
|
|
printiface(i);
|
2008-09-22 13:16:19 -06:00
|
|
|
prints("\n");
|
|
|
|
}
|
|
|
|
|
2008-12-19 18:11:54 -07:00
|
|
|
im = i.type;
|
2008-11-05 14:05:01 -07:00
|
|
|
if(im == nil) {
|
|
|
|
prints("interface is nil, not ");
|
2009-03-16 16:27:08 -06:00
|
|
|
prints((int8*)st->name);
|
2008-11-05 14:05:01 -07:00
|
|
|
prints("\n");
|
|
|
|
throw("interface conversion");
|
|
|
|
}
|
|
|
|
|
|
|
|
if(im->sigt != st) {
|
2009-03-16 16:27:08 -06:00
|
|
|
prints((int8*)im->sigi->name);
|
2008-11-05 14:05:01 -07:00
|
|
|
prints(" is ");
|
2009-03-16 16:27:08 -06:00
|
|
|
prints((int8*)im->sigt->name);
|
2008-11-05 14:05:01 -07:00
|
|
|
prints(", not ");
|
2009-03-16 16:27:08 -06:00
|
|
|
prints((int8*)st->name);
|
2008-11-05 14:05:01 -07:00
|
|
|
prints("\n");
|
|
|
|
throw("interface conversion");
|
|
|
|
}
|
|
|
|
|
2009-03-16 16:27:08 -06:00
|
|
|
alg = st->alg;
|
|
|
|
wid = st->width;
|
|
|
|
if(wid <= sizeof(i.data))
|
2009-01-09 01:17:46 -07:00
|
|
|
algarray[alg].copy(wid, ret, &i.data);
|
2008-12-19 18:11:54 -07:00
|
|
|
else
|
2009-01-09 01:17:46 -07:00
|
|
|
algarray[alg].copy(wid, ret, i.data);
|
2008-12-19 18:11:54 -07:00
|
|
|
|
2009-01-08 15:30:00 -07:00
|
|
|
if(iface_debug) {
|
2008-09-22 13:16:19 -06:00
|
|
|
prints("I2T ret=");
|
2008-12-19 18:11:54 -07:00
|
|
|
sys·printpointer(*(void**)ret);
|
2008-09-22 13:16:19 -06:00
|
|
|
prints("\n");
|
|
|
|
}
|
2008-11-03 18:34:37 -07:00
|
|
|
FLUSH(&ret);
|
|
|
|
}
|
|
|
|
|
|
|
|
// ifaceI2T2(sigt *byte, iface any) (ret any, ok bool);
|
|
|
|
void
|
2008-12-19 18:11:54 -07:00
|
|
|
sys·ifaceI2T2(Sigt *st, Iface i, ...)
|
2008-11-03 18:34:37 -07:00
|
|
|
{
|
2008-12-19 18:11:54 -07:00
|
|
|
byte *ret;
|
|
|
|
bool *ok;
|
|
|
|
Itype *im;
|
|
|
|
int32 alg, wid;
|
|
|
|
|
|
|
|
|
2009-01-08 15:30:00 -07:00
|
|
|
if(iface_debug) {
|
2008-11-03 18:34:37 -07:00
|
|
|
prints("I2T2 sigt=");
|
|
|
|
printsigt(st);
|
|
|
|
prints(" iface=");
|
2008-12-19 18:11:54 -07:00
|
|
|
printiface(i);
|
2008-11-03 18:34:37 -07:00
|
|
|
prints("\n");
|
|
|
|
}
|
2008-09-22 13:16:19 -06:00
|
|
|
|
2009-03-16 16:27:08 -06:00
|
|
|
ret = (byte*)(&i+1);
|
|
|
|
alg = st->alg;
|
|
|
|
wid = st->width;
|
|
|
|
ok = (bool*)(ret+rnd(wid, 1));
|
|
|
|
|
2008-12-19 18:11:54 -07:00
|
|
|
im = i.type;
|
2008-11-03 18:34:37 -07:00
|
|
|
if(im == nil || im->sigt != st) {
|
2008-12-19 18:11:54 -07:00
|
|
|
*ok = false;
|
|
|
|
sys·memclr(ret, wid);
|
2008-11-03 18:34:37 -07:00
|
|
|
} else {
|
2008-12-19 18:11:54 -07:00
|
|
|
*ok = true;
|
2009-03-16 16:27:08 -06:00
|
|
|
if(wid <= sizeof(i.data))
|
2009-01-09 01:17:46 -07:00
|
|
|
algarray[alg].copy(wid, ret, &i.data);
|
2008-12-19 18:11:54 -07:00
|
|
|
else
|
2009-01-09 01:17:46 -07:00
|
|
|
algarray[alg].copy(wid, ret, i.data);
|
2008-11-03 18:34:37 -07:00
|
|
|
}
|
2009-01-08 15:30:00 -07:00
|
|
|
if(iface_debug) {
|
2008-11-03 18:34:37 -07:00
|
|
|
prints("I2T2 ret=");
|
2008-12-19 18:11:54 -07:00
|
|
|
sys·printpointer(*(void**)ret);
|
|
|
|
sys·printbool(*ok);
|
2008-11-03 18:34:37 -07:00
|
|
|
prints("\n");
|
|
|
|
}
|
2008-09-22 13:16:19 -06:00
|
|
|
}
|
|
|
|
|
2008-09-22 17:58:30 -06:00
|
|
|
// ifaceI2I(sigi *byte, iface any) (ret any);
|
2008-09-22 13:16:19 -06:00
|
|
|
void
|
2008-12-19 18:11:54 -07:00
|
|
|
sys·ifaceI2I(Sigi *si, Iface i, Iface ret)
|
2008-09-22 13:16:19 -06:00
|
|
|
{
|
2008-12-19 18:11:54 -07:00
|
|
|
Itype *im;
|
|
|
|
|
2009-01-08 15:30:00 -07:00
|
|
|
if(iface_debug) {
|
2008-09-22 13:16:19 -06:00
|
|
|
prints("I2I sigi=");
|
2008-09-22 17:58:30 -06:00
|
|
|
printsigi(si);
|
2008-09-22 13:16:19 -06:00
|
|
|
prints(" iface=");
|
2008-12-19 18:11:54 -07:00
|
|
|
printiface(i);
|
2008-09-22 13:16:19 -06:00
|
|
|
prints("\n");
|
|
|
|
}
|
|
|
|
|
2008-12-19 18:11:54 -07:00
|
|
|
im = i.type;
|
2008-09-22 13:16:19 -06:00
|
|
|
if(im == nil) {
|
2008-10-10 17:21:50 -06:00
|
|
|
// If incoming interface is uninitialized (zeroed)
|
|
|
|
// make the outgoing interface zeroed as well.
|
2009-01-09 01:17:46 -07:00
|
|
|
ret = niliface;
|
2008-10-10 17:21:50 -06:00
|
|
|
} else {
|
2008-12-19 18:11:54 -07:00
|
|
|
ret = i;
|
2008-10-10 17:21:50 -06:00
|
|
|
if(im->sigi != si)
|
2008-12-19 18:11:54 -07:00
|
|
|
ret.type = itype(si, im->sigt, 0);
|
2008-09-22 13:16:19 -06:00
|
|
|
}
|
|
|
|
|
2009-01-08 15:30:00 -07:00
|
|
|
if(iface_debug) {
|
2008-09-22 13:16:19 -06:00
|
|
|
prints("I2I ret=");
|
2008-12-19 18:11:54 -07:00
|
|
|
printiface(ret);
|
2008-09-22 13:16:19 -06:00
|
|
|
prints("\n");
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
2008-11-03 18:34:37 -07:00
|
|
|
// ifaceI2I2(sigi *byte, iface any) (ret any, ok bool);
|
|
|
|
void
|
2008-12-19 18:11:54 -07:00
|
|
|
sys·ifaceI2I2(Sigi *si, Iface i, Iface ret, bool ok)
|
2008-11-03 18:34:37 -07:00
|
|
|
{
|
2008-12-19 18:11:54 -07:00
|
|
|
Itype *im;
|
|
|
|
|
2009-01-08 15:30:00 -07:00
|
|
|
if(iface_debug) {
|
2008-11-03 18:34:37 -07:00
|
|
|
prints("I2I2 sigi=");
|
|
|
|
printsigi(si);
|
|
|
|
prints(" iface=");
|
2008-12-19 18:11:54 -07:00
|
|
|
printiface(i);
|
2008-11-03 18:34:37 -07:00
|
|
|
prints("\n");
|
|
|
|
}
|
|
|
|
|
2008-12-19 18:11:54 -07:00
|
|
|
im = i.type;
|
2008-11-03 18:34:37 -07:00
|
|
|
if(im == nil) {
|
|
|
|
// If incoming interface is uninitialized (zeroed)
|
|
|
|
// make the outgoing interface zeroed as well.
|
2009-01-09 01:17:46 -07:00
|
|
|
ret = niliface;
|
2008-11-03 18:34:37 -07:00
|
|
|
ok = 1;
|
|
|
|
} else {
|
2008-12-19 18:11:54 -07:00
|
|
|
ret = i;
|
2008-11-03 18:34:37 -07:00
|
|
|
ok = 1;
|
|
|
|
if(im->sigi != si) {
|
2008-12-19 18:11:54 -07:00
|
|
|
ret.type = itype(si, im->sigt, 1);
|
|
|
|
if(ret.type == nil) {
|
2009-01-09 01:17:46 -07:00
|
|
|
ret = niliface;
|
2008-11-03 18:34:37 -07:00
|
|
|
ok = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-01-08 15:30:00 -07:00
|
|
|
if(iface_debug) {
|
2008-11-03 18:34:37 -07:00
|
|
|
prints("I2I ret=");
|
2008-12-19 18:11:54 -07:00
|
|
|
printiface(ret);
|
2008-11-03 18:34:37 -07:00
|
|
|
prints("\n");
|
|
|
|
}
|
|
|
|
|
2008-12-19 18:11:54 -07:00
|
|
|
FLUSH(&ret);
|
2008-11-03 18:34:37 -07:00
|
|
|
FLUSH(&ok);
|
|
|
|
}
|
|
|
|
|
2009-01-26 10:56:42 -07:00
|
|
|
uint64
|
|
|
|
ifacehash(Iface a)
|
|
|
|
{
|
|
|
|
int32 alg, wid;
|
2009-03-16 16:27:08 -06:00
|
|
|
Sigt *sigt;
|
2009-02-02 19:59:20 -07:00
|
|
|
|
2009-01-26 10:56:42 -07:00
|
|
|
if(a.type == nil)
|
|
|
|
return 0;
|
2009-03-16 16:27:08 -06:00
|
|
|
|
|
|
|
sigt = a.type->sigt;
|
|
|
|
alg = sigt->alg;
|
|
|
|
wid = sigt->width;
|
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-03-16 16:27:08 -06:00
|
|
|
printf("hash of unhashable type %s\n", sigt->name);
|
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-03-16 16:27:08 -06:00
|
|
|
if(wid <= sizeof(a.data))
|
2009-01-26 10:56:42 -07:00
|
|
|
return algarray[alg].hash(wid, &a.data);
|
2009-03-16 16:27:08 -06:00
|
|
|
return algarray[alg].hash(wid, a.data);
|
2009-01-26 10:56:42 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
ifaceeq(Iface i1, Iface i2)
|
2008-10-14 16:08:23 -06:00
|
|
|
{
|
2008-10-14 17:10:44 -06:00
|
|
|
int32 alg, wid;
|
2009-01-26 10:56:42 -07:00
|
|
|
bool ret;
|
2008-10-14 17:10:44 -06:00
|
|
|
|
2009-01-08 15:30:00 -07:00
|
|
|
if(iface_debug) {
|
2008-10-14 16:08:23 -06:00
|
|
|
prints("Ieq i1=");
|
2008-12-19 18:11:54 -07:00
|
|
|
printiface(i1);
|
2008-10-14 16:08:23 -06:00
|
|
|
prints(" i2=");
|
2008-12-19 18:11:54 -07:00
|
|
|
printiface(i2);
|
2008-10-14 16:08:23 -06:00
|
|
|
prints("\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = false;
|
|
|
|
|
|
|
|
// are they both nil
|
2008-12-19 18:11:54 -07:00
|
|
|
if(i1.type == nil) {
|
|
|
|
if(i2.type == nil)
|
2008-10-14 16:08:23 -06:00
|
|
|
goto yes;
|
|
|
|
goto no;
|
|
|
|
}
|
2008-12-19 18:11:54 -07:00
|
|
|
if(i2.type == nil)
|
2008-10-14 16:08:23 -06:00
|
|
|
goto no;
|
|
|
|
|
2009-01-26 13:36:21 -07:00
|
|
|
// are they the same type?
|
|
|
|
if(i1.type->sigt != i2.type->sigt)
|
2008-10-14 16:08:23 -06:00
|
|
|
goto no;
|
|
|
|
|
2009-03-16 16:27:08 -06:00
|
|
|
alg = i1.type->sigt->alg;
|
|
|
|
wid = i1.type->sigt->width;
|
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.
|
|
|
|
printf("comparing uncomparable type %s\n", i1.type->sigt->name);
|
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-03-16 16:27:08 -06:00
|
|
|
if(wid <= sizeof(i1.data)) {
|
2009-01-09 01:17:46 -07:00
|
|
|
if(!algarray[alg].equal(wid, &i1.data, &i2.data))
|
2008-12-19 18:11:54 -07:00
|
|
|
goto no;
|
|
|
|
} else {
|
2009-01-09 01:17:46 -07:00
|
|
|
if(!algarray[alg].equal(wid, i1.data, i2.data))
|
2008-12-19 18:11:54 -07:00
|
|
|
goto no;
|
|
|
|
}
|
2008-10-14 16:08:23 -06:00
|
|
|
|
|
|
|
yes:
|
|
|
|
ret = true;
|
|
|
|
no:
|
2009-01-08 15:30:00 -07:00
|
|
|
if(iface_debug) {
|
2008-10-14 16:08:23 -06:00
|
|
|
prints("Ieq ret=");
|
|
|
|
sys·printbool(ret);
|
|
|
|
prints("\n");
|
|
|
|
}
|
2009-01-26 10:56:42 -07:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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-03-17 14:58:38 -06:00
|
|
|
// ifacethash(i1 any) (ret uint32);
|
|
|
|
void
|
|
|
|
sys·ifacethash(Iface i1, uint32 ret)
|
|
|
|
{
|
|
|
|
Itype *im;
|
|
|
|
Sigt *st;
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
im = i1.type;
|
|
|
|
if(im != nil) {
|
|
|
|
st = im->sigt;
|
|
|
|
if(st != nil)
|
|
|
|
ret = st->thash;
|
|
|
|
}
|
|
|
|
FLUSH(&ret);
|
|
|
|
}
|
|
|
|
|
2008-09-22 17:58:30 -06:00
|
|
|
void
|
2008-12-19 18:11:54 -07:00
|
|
|
sys·printinter(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-01-16 15:58:14 -07:00
|
|
|
sys·Reflect(Iface i, uint64 retit, string rettype, bool retindir)
|
2008-10-21 16:38:26 -06:00
|
|
|
{
|
2009-01-09 01:17:46 -07:00
|
|
|
int32 wid;
|
|
|
|
|
|
|
|
if(i.type == nil) {
|
2008-10-21 16:38:26 -06:00
|
|
|
retit = 0;
|
|
|
|
rettype = nil;
|
2009-01-09 01:17:46 -07:00
|
|
|
retindir = false;
|
2008-10-21 16:38:26 -06:00
|
|
|
} else {
|
2009-01-09 01:17:46 -07:00
|
|
|
retit = (uint64)i.data;
|
|
|
|
rettype = gostring(i.type->sigt->name);
|
2009-03-16 16:27:08 -06:00
|
|
|
wid = i.type->sigt->width;
|
|
|
|
retindir = wid > sizeof(i.data);
|
2008-10-21 16:38:26 -06:00
|
|
|
}
|
|
|
|
FLUSH(&retit);
|
|
|
|
FLUSH(&rettype);
|
2009-01-09 01:17:46 -07:00
|
|
|
FLUSH(&retindir);
|
2008-10-21 16:38:26 -06:00
|
|
|
}
|
2008-11-03 17:03:12 -07:00
|
|
|
|
|
|
|
extern Sigt *gotypesigs[];
|
|
|
|
extern int32 ngotypesigs;
|
|
|
|
|
2009-01-09 01:17:46 -07:00
|
|
|
|
|
|
|
// 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");
|
|
|
|
// }
|
|
|
|
//
|
2009-01-16 15:58:14 -07:00
|
|
|
// vv.Interface() returns the result of sys.Unreflect with
|
2009-01-09 01:17:46 -07:00
|
|
|
// a typestring of "[]int". If []int is not used with interfaces
|
|
|
|
// in the rest of the program, there will be no signature in gotypesigs
|
2009-03-31 18:33:04 -06:00
|
|
|
// for "[]int", so we have to invent one. The requirements
|
2009-01-09 01:17:46 -07:00
|
|
|
// on the fake signature are:
|
|
|
|
//
|
|
|
|
// (1) any interface conversion using the signature will fail
|
2009-01-16 15:58:14 -07:00
|
|
|
// (2) calling sys.Reflect() returns the args to unreflect
|
2009-03-31 18:33:04 -06:00
|
|
|
// (3) the right algorithm type is used, for == and map insertion
|
2009-01-09 01:17:46 -07:00
|
|
|
//
|
|
|
|
// (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.
|
2009-03-31 18:33:04 -06:00
|
|
|
// (3) is ensured by sniffing the type string.
|
2009-01-09 01:17:46 -07:00
|
|
|
//
|
|
|
|
// 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.
|
2009-01-26 13:36:21 -07:00
|
|
|
|
2009-03-16 16:27:08 -06:00
|
|
|
static Sigt* fake[1009];
|
2009-01-26 13:36:21 -07:00
|
|
|
static int32 nfake;
|
|
|
|
|
2009-03-31 18:33:04 -06:00
|
|
|
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),
|
|
|
|
};
|
|
|
|
|
2008-11-03 17:03:12 -07:00
|
|
|
static Sigt*
|
2009-01-09 01:17:46 -07:00
|
|
|
fakesigt(string type, bool indir)
|
2008-11-03 17:03:12 -07:00
|
|
|
{
|
|
|
|
Sigt *sigt;
|
2009-01-26 13:36:21 -07:00
|
|
|
uint32 h;
|
|
|
|
int32 i, locked;
|
|
|
|
|
|
|
|
if(type == nil)
|
|
|
|
type = emptystring;
|
|
|
|
|
|
|
|
h = 0;
|
|
|
|
for(i=0; i<type->len; i++)
|
|
|
|
h = h*37 + type->str[i];
|
|
|
|
h += indir;
|
|
|
|
h %= nelem(fake);
|
2009-02-02 19:59:20 -07:00
|
|
|
|
2009-01-26 13:36:21 -07:00
|
|
|
for(locked=0; locked<2; locked++) {
|
|
|
|
if(locked)
|
|
|
|
lock(&ifacelock);
|
2009-03-16 16:27:08 -06:00
|
|
|
for(sigt = fake[h]; sigt != nil; sigt = sigt->link) {
|
2009-01-26 13:36:21 -07:00
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-11-03 17:03:12 -07:00
|
|
|
|
2009-04-01 01:26:00 -06:00
|
|
|
sigt = malloc(sizeof(*sigt));
|
|
|
|
sigt->name = malloc(type->len + 1);
|
2009-03-16 16:27:08 -06:00
|
|
|
mcpy(sigt->name, type->str, type->len);
|
2009-03-31 18:33:04 -06:00
|
|
|
|
2009-03-16 16:27:08 -06:00
|
|
|
sigt->alg = AFAKE;
|
|
|
|
sigt->width = 1; // small width
|
2009-01-09 01:17:46 -07:00
|
|
|
if(indir)
|
2009-03-16 16:27:08 -06:00
|
|
|
sigt->width = 2*sizeof(niliface.data); // big width
|
2009-03-31 18:33:04 -06:00
|
|
|
|
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-03-16 16:27:08 -06:00
|
|
|
sigt->link = fake[h];
|
2009-01-26 13:36:21 -07:00
|
|
|
fake[h] = sigt;
|
2009-03-16 16:27:08 -06:00
|
|
|
|
2009-01-26 13:36:21 -07:00
|
|
|
unlock(&ifacelock);
|
2008-11-03 17:03:12 -07:00
|
|
|
return sigt;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int32
|
|
|
|
cmpstringchars(string a, uint8 *b)
|
|
|
|
{
|
|
|
|
int32 i;
|
2009-01-26 13:36:21 -07:00
|
|
|
byte c1, c2;
|
2008-11-03 17:03:12 -07:00
|
|
|
|
|
|
|
for(i=0;; i++) {
|
2009-01-26 13:36:21 -07:00
|
|
|
if(i == a->len)
|
|
|
|
c1 = 0;
|
|
|
|
else
|
|
|
|
c1 = a->str[i];
|
|
|
|
c2 = b[i];
|
|
|
|
if(c1 < c2)
|
2008-11-03 17:03:12 -07:00
|
|
|
return -1;
|
2009-01-26 13:36:21 -07:00
|
|
|
if(c1 > c2)
|
|
|
|
return +1;
|
|
|
|
if(c1 == 0)
|
|
|
|
return 0;
|
2008-11-03 17:03:12 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static Sigt*
|
2009-01-09 01:17:46 -07:00
|
|
|
findtype(string type, bool indir)
|
2008-11-03 17:03:12 -07:00
|
|
|
{
|
2009-01-26 13:36:21 -07:00
|
|
|
int32 i, lo, hi, m;
|
2009-02-02 19:59:20 -07:00
|
|
|
|
2009-01-26 13:36:21 -07:00
|
|
|
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;
|
|
|
|
}
|
2009-01-09 01:17:46 -07:00
|
|
|
return fakesigt(type, indir);
|
2008-11-03 17:03:12 -07:00
|
|
|
}
|
|
|
|
|
2009-01-09 01:17:46 -07:00
|
|
|
|
2008-11-03 17:03:12 -07:00
|
|
|
void
|
2009-01-16 15:58:14 -07:00
|
|
|
sys·Unreflect(uint64 it, string type, bool indir, Iface ret)
|
2008-11-03 17:03:12 -07:00
|
|
|
{
|
2009-01-09 01:17:46 -07:00
|
|
|
Sigt *sigt;
|
|
|
|
|
|
|
|
ret = niliface;
|
|
|
|
|
|
|
|
if(cmpstring(type, emptystring) == 0)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
// if we think the type should be indirect
|
|
|
|
// and caller does not, play it safe, return nil.
|
|
|
|
sigt = findtype(type, indir);
|
2009-03-16 16:27:08 -06:00
|
|
|
if(indir != (sigt->width > sizeof(ret.data)))
|
2009-01-09 01:17:46 -07:00
|
|
|
goto out;
|
|
|
|
|
|
|
|
ret.type = itype(sigi·empty, sigt, 0);
|
|
|
|
ret.data = (void*)it;
|
|
|
|
|
|
|
|
out:
|
|
|
|
FLUSH(&ret);
|
2008-11-03 17:03:12 -07:00
|
|
|
}
|
|
|
|
|