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"
|
|
|
|
|
2008-09-22 17:58:30 -06:00
|
|
|
static int32 debug = 0;
|
|
|
|
|
2008-10-15 18:08:10 -06:00
|
|
|
enum
|
|
|
|
{
|
|
|
|
ASIMP = 0,
|
|
|
|
ASTRING,
|
|
|
|
APTR,
|
|
|
|
AINTER,
|
|
|
|
};
|
|
|
|
|
2008-09-22 13:16:19 -06:00
|
|
|
typedef struct Sigt Sigt;
|
|
|
|
typedef struct Sigi Sigi;
|
|
|
|
typedef struct Map Map;
|
|
|
|
|
|
|
|
struct Sigt
|
|
|
|
{
|
|
|
|
byte* name;
|
2008-10-15 18:08:10 -06:00
|
|
|
uint32 hash; // hash of type // first is alg
|
|
|
|
uint32 offset; // offset of substruct // first is width
|
2008-09-22 13:16:19 -06:00
|
|
|
void (*fun)(void);
|
|
|
|
};
|
|
|
|
|
|
|
|
struct Sigi
|
|
|
|
{
|
|
|
|
byte* name;
|
|
|
|
uint32 hash;
|
2008-10-15 18:08:10 -06:00
|
|
|
uint32 perm; // location of fun in Sigt // first is size
|
2008-09-22 13:16:19 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
struct Map
|
|
|
|
{
|
|
|
|
Sigi* sigi;
|
|
|
|
Sigt* sigt;
|
|
|
|
Map* link;
|
|
|
|
int32 bad;
|
|
|
|
int32 unused;
|
|
|
|
void (*fun[])(void);
|
|
|
|
};
|
|
|
|
|
|
|
|
static Map* hash[1009];
|
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("{");
|
2008-10-03 17:12:21 -06:00
|
|
|
for(i=1;; i++) {
|
2008-09-22 17:58:30 -06:00
|
|
|
name = si[i].name;
|
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("\"");
|
2008-09-28 21:22:31 -06:00
|
|
|
sys·printint(si[i].hash%999);
|
2008-09-22 17:58:30 -06:00
|
|
|
prints("/");
|
2008-09-28 21:22:31 -06:00
|
|
|
sys·printint(si[i].perm);
|
2008-09-22 17:58:30 -06:00
|
|
|
}
|
|
|
|
prints("}");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
printsigt(Sigt *st)
|
|
|
|
{
|
|
|
|
int32 i;
|
|
|
|
byte *name;
|
|
|
|
|
|
|
|
sys·printpointer(st);
|
|
|
|
prints("{");
|
2008-10-03 17:12:21 -06:00
|
|
|
sys·printint(st[0].hash); // first element has alg
|
|
|
|
prints(",");
|
|
|
|
sys·printint(st[0].offset); // first element has width
|
|
|
|
for(i=1;; i++) {
|
2008-09-22 17:58:30 -06:00
|
|
|
name = st[i].name;
|
|
|
|
if(name == nil)
|
|
|
|
break;
|
|
|
|
prints("[");
|
|
|
|
sys·printint(i);
|
|
|
|
prints("]\"");
|
|
|
|
prints((int8*)name);
|
|
|
|
prints("\"");
|
2008-09-28 21:22:31 -06:00
|
|
|
sys·printint(st[i].hash%999);
|
|
|
|
prints("/");
|
|
|
|
sys·printint(st[i].offset);
|
2008-09-22 17:58:30 -06:00
|
|
|
prints("/");
|
|
|
|
sys·printpointer(st[i].fun);
|
|
|
|
}
|
|
|
|
prints("}");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
printiface(Map *im, void *it)
|
|
|
|
{
|
|
|
|
prints("(");
|
|
|
|
sys·printpointer(im);
|
|
|
|
prints(",");
|
|
|
|
sys·printpointer(it);
|
|
|
|
prints(")");
|
|
|
|
}
|
2008-09-22 13:16:19 -06:00
|
|
|
|
|
|
|
static Map*
|
2008-10-21 16:38:26 -06:00
|
|
|
hashmap(Sigi *si, Sigt *st, int32 canfail)
|
2008-09-22 13:16:19 -06:00
|
|
|
{
|
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;
|
|
|
|
Map *m;
|
|
|
|
|
2008-09-22 17:58:30 -06:00
|
|
|
h = ((uint32)(uint64)si + (uint32)(uint64)st) % nelem(hash);
|
2008-09-22 13:16:19 -06:00
|
|
|
for(m=hash[h]; m!=nil; m=m->link) {
|
2008-09-22 17:58:30 -06:00
|
|
|
if(m->sigi == si && m->sigt == st) {
|
2008-09-22 13:16:19 -06:00
|
|
|
if(m->bad) {
|
|
|
|
m = nil;
|
2008-11-05 14:05:01 -07:00
|
|
|
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-09-22 13:16:19 -06:00
|
|
|
}
|
|
|
|
// prints("old hashmap\n");
|
|
|
|
return m;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-09-28 21:22:31 -06:00
|
|
|
ni = si[0].perm; // first entry has size
|
2008-09-22 13:16:19 -06:00
|
|
|
m = mal(sizeof(*m) + ni*sizeof(m->fun[0]));
|
|
|
|
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:
|
2008-10-08 10:21:57 -06:00
|
|
|
nt = 1;
|
2008-10-15 18:08:10 -06:00
|
|
|
for(ni=1;; ni++) { // ni=1: skip first word
|
|
|
|
iname = si[ni].name;
|
|
|
|
if(iname == nil)
|
|
|
|
break;
|
|
|
|
|
2008-09-30 15:02:53 -06:00
|
|
|
// pick up next name from
|
|
|
|
// interface signature
|
|
|
|
ihash = si[ni].hash;
|
|
|
|
|
|
|
|
for(;; nt++) {
|
|
|
|
// pick up and compare next name
|
|
|
|
// from structure signature
|
|
|
|
sname = st[nt].name;
|
|
|
|
if(sname == nil) {
|
2008-10-21 16:38:26 -06:00
|
|
|
if(!canfail) {
|
|
|
|
prints("cannot convert type ");
|
|
|
|
prints((int8*)st[0].name);
|
|
|
|
prints(" to interface ");
|
|
|
|
prints((int8*)si[0].name);
|
|
|
|
prints(": missing method ");
|
|
|
|
prints((int8*)iname);
|
|
|
|
prints("\n");
|
|
|
|
throw("interface conversion");
|
|
|
|
}
|
2008-09-30 15:02:53 -06:00
|
|
|
m->bad = 1;
|
|
|
|
m->link = hash[h];
|
|
|
|
hash[h] = m;
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
if(ihash == st[nt].hash && strcmp(sname, iname) == 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
m->fun[si[ni].perm] = st[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;
|
|
|
|
// prints("new hashmap\n");
|
|
|
|
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
|
|
|
|
sys·ifaceT2I(Sigi *si, Sigt *st, void *elem, Map *retim, void *retit)
|
|
|
|
{
|
2008-10-03 17:12:21 -06:00
|
|
|
// int32 alg, wid;
|
2008-09-22 13:16:19 -06:00
|
|
|
|
|
|
|
if(debug) {
|
|
|
|
prints("T2I sigi=");
|
|
|
|
printsigi(si);
|
|
|
|
prints(" sigt=");
|
|
|
|
printsigt(st);
|
|
|
|
prints(" elem=");
|
|
|
|
sys·printpointer(elem);
|
|
|
|
prints("\n");
|
|
|
|
}
|
|
|
|
|
2008-10-21 16:38:26 -06:00
|
|
|
retim = hashmap(si, st, 0);
|
2008-10-03 17:12:21 -06:00
|
|
|
|
|
|
|
// alg = st->hash;
|
|
|
|
// wid = st->offset;
|
|
|
|
// algarray[alg].copy(wid, &retit, &elem);
|
|
|
|
retit = elem; // for speed could do this
|
2008-09-22 13:16:19 -06:00
|
|
|
|
|
|
|
if(debug) {
|
|
|
|
prints("T2I ret=");
|
|
|
|
printiface(retim, retit);
|
|
|
|
prints("\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
FLUSH(&retim);
|
2008-09-30 15:02:53 -06:00
|
|
|
FLUSH(&retit);
|
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
|
|
|
|
sys·ifaceI2T(Sigt *st, Map *im, void *it, void *ret)
|
|
|
|
{
|
|
|
|
if(debug) {
|
|
|
|
prints("I2T sigt=");
|
|
|
|
printsigt(st);
|
|
|
|
prints(" iface=");
|
|
|
|
printiface(im, it);
|
|
|
|
prints("\n");
|
|
|
|
}
|
|
|
|
|
2008-11-05 14:05:01 -07:00
|
|
|
if(im == nil) {
|
|
|
|
prints("interface is nil, not ");
|
|
|
|
prints((int8*)st[0].name);
|
|
|
|
prints("\n");
|
|
|
|
throw("interface conversion");
|
|
|
|
}
|
|
|
|
|
|
|
|
if(im->sigt != st) {
|
|
|
|
prints((int8*)im->sigi[0].name);
|
|
|
|
prints(" is ");
|
|
|
|
prints((int8*)im->sigt[0].name);
|
|
|
|
prints(", not ");
|
|
|
|
prints((int8*)st[0].name);
|
|
|
|
prints("\n");
|
|
|
|
throw("interface conversion");
|
|
|
|
}
|
|
|
|
|
2008-09-22 13:16:19 -06:00
|
|
|
ret = it;
|
|
|
|
if(debug) {
|
|
|
|
prints("I2T ret=");
|
|
|
|
sys·printpointer(ret);
|
|
|
|
prints("\n");
|
|
|
|
}
|
2008-11-03 18:34:37 -07:00
|
|
|
FLUSH(&ret);
|
|
|
|
}
|
|
|
|
|
|
|
|
// ifaceI2T2(sigt *byte, iface any) (ret any, ok bool);
|
|
|
|
void
|
|
|
|
sys·ifaceI2T2(Sigt *st, Map *im, void *it, void *ret, bool ok)
|
|
|
|
{
|
|
|
|
if(debug) {
|
|
|
|
prints("I2T2 sigt=");
|
|
|
|
printsigt(st);
|
|
|
|
prints(" iface=");
|
|
|
|
printiface(im, it);
|
|
|
|
prints("\n");
|
|
|
|
}
|
2008-09-22 13:16:19 -06:00
|
|
|
|
2008-11-03 18:34:37 -07:00
|
|
|
if(im == nil || im->sigt != st) {
|
|
|
|
ret = 0;
|
|
|
|
ok = 0;
|
|
|
|
} else {
|
|
|
|
ret = it;
|
|
|
|
ok = 1;
|
|
|
|
}
|
|
|
|
if(debug) {
|
|
|
|
prints("I2T2 ret=");
|
|
|
|
sys·printpointer(ret);
|
|
|
|
sys·printbool(ok);
|
|
|
|
prints("\n");
|
|
|
|
}
|
2008-09-22 13:16:19 -06:00
|
|
|
FLUSH(&ret);
|
2008-11-03 18:34:37 -07:00
|
|
|
FLUSH(&ok);
|
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
|
|
|
|
sys·ifaceI2I(Sigi *si, Map *im, void *it, Map *retim, void *retit)
|
|
|
|
{
|
|
|
|
if(debug) {
|
|
|
|
prints("I2I sigi=");
|
2008-09-22 17:58:30 -06:00
|
|
|
printsigi(si);
|
2008-09-22 13:16:19 -06:00
|
|
|
prints(" iface=");
|
|
|
|
printiface(im, it);
|
|
|
|
prints("\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
if(im == nil) {
|
2008-10-10 17:21:50 -06:00
|
|
|
// If incoming interface is uninitialized (zeroed)
|
|
|
|
// make the outgoing interface zeroed as well.
|
|
|
|
retim = nil;
|
|
|
|
retit = nil;
|
|
|
|
} else {
|
|
|
|
retit = it;
|
|
|
|
retim = im;
|
|
|
|
if(im->sigi != si)
|
2008-10-21 16:38:26 -06:00
|
|
|
retim = hashmap(si, im->sigt, 0);
|
2008-09-22 13:16:19 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
if(debug) {
|
|
|
|
prints("I2I ret=");
|
|
|
|
printiface(retim, retit);
|
|
|
|
prints("\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
FLUSH(&retim);
|
2008-09-30 15:02:53 -06:00
|
|
|
FLUSH(&retit);
|
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
|
|
|
|
sys·ifaceI2I2(Sigi *si, Map *im, void *it, Map *retim, void *retit, bool ok)
|
|
|
|
{
|
|
|
|
if(debug) {
|
|
|
|
prints("I2I2 sigi=");
|
|
|
|
printsigi(si);
|
|
|
|
prints(" iface=");
|
|
|
|
printiface(im, it);
|
|
|
|
prints("\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
if(im == nil) {
|
|
|
|
// If incoming interface is uninitialized (zeroed)
|
|
|
|
// make the outgoing interface zeroed as well.
|
|
|
|
retim = nil;
|
|
|
|
retit = nil;
|
|
|
|
ok = 1;
|
|
|
|
} else {
|
|
|
|
retit = it;
|
|
|
|
retim = im;
|
|
|
|
ok = 1;
|
|
|
|
if(im->sigi != si) {
|
|
|
|
retim = hashmap(si, im->sigt, 1);
|
|
|
|
if(retim == nil) {
|
|
|
|
retit = nil;
|
|
|
|
retim = nil;
|
|
|
|
ok = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(debug) {
|
|
|
|
prints("I2I ret=");
|
|
|
|
printiface(retim, retit);
|
|
|
|
prints("\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
FLUSH(&retim);
|
|
|
|
FLUSH(&retit);
|
|
|
|
FLUSH(&ok);
|
|
|
|
}
|
|
|
|
|
2008-10-14 16:08:23 -06:00
|
|
|
// ifaceeq(i1 any, i2 any) (ret bool);
|
|
|
|
void
|
|
|
|
sys·ifaceeq(Map *im1, void *it1, Map *im2, void *it2, byte ret)
|
|
|
|
{
|
2008-10-14 17:10:44 -06:00
|
|
|
int32 alg, wid;
|
|
|
|
|
2008-10-14 16:08:23 -06:00
|
|
|
if(debug) {
|
|
|
|
prints("Ieq i1=");
|
|
|
|
printiface(im1, it1);
|
|
|
|
prints(" i2=");
|
|
|
|
printiface(im2, it2);
|
|
|
|
prints("\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = false;
|
|
|
|
|
|
|
|
// are they both nil
|
|
|
|
if(im1 == nil) {
|
|
|
|
if(im2 == nil)
|
|
|
|
goto yes;
|
|
|
|
goto no;
|
|
|
|
}
|
|
|
|
if(im2 == nil)
|
|
|
|
goto no;
|
|
|
|
|
2008-10-14 17:10:44 -06:00
|
|
|
// value
|
|
|
|
alg = im1->sigt->hash;
|
|
|
|
if(alg != im2->sigt->hash)
|
2008-10-14 16:08:23 -06:00
|
|
|
goto no;
|
|
|
|
|
2008-10-14 17:10:44 -06:00
|
|
|
wid = im1->sigt->offset;
|
|
|
|
if(wid != im2->sigt->offset)
|
2008-10-14 16:08:23 -06:00
|
|
|
goto no;
|
|
|
|
|
2008-10-14 17:10:44 -06:00
|
|
|
if(!algarray[alg].equal(wid, &it1, &it2))
|
|
|
|
goto no;
|
2008-10-14 16:08:23 -06:00
|
|
|
|
|
|
|
yes:
|
|
|
|
ret = true;
|
|
|
|
no:
|
|
|
|
if(debug) {
|
|
|
|
prints("Ieq ret=");
|
|
|
|
sys·printbool(ret);
|
|
|
|
prints("\n");
|
|
|
|
}
|
|
|
|
FLUSH(&ret);
|
|
|
|
}
|
|
|
|
|
2008-09-22 17:58:30 -06:00
|
|
|
void
|
|
|
|
sys·printinter(Map *im, void *it)
|
|
|
|
{
|
|
|
|
printiface(im, it);
|
|
|
|
}
|
2008-10-21 16:38:26 -06:00
|
|
|
|
|
|
|
void
|
|
|
|
sys·reflect(Map *im, void *it, uint64 retit, string rettype)
|
|
|
|
{
|
|
|
|
string s;
|
|
|
|
int32 n;
|
|
|
|
byte *type;
|
|
|
|
|
|
|
|
if(im == nil) {
|
|
|
|
retit = 0;
|
|
|
|
rettype = nil;
|
|
|
|
} else {
|
|
|
|
retit = (uint64)it;
|
|
|
|
type = im->sigt->name;
|
|
|
|
n = findnull((int8*)type);
|
|
|
|
s = mal(sizeof *s + n + 1);
|
|
|
|
s->len = n;
|
|
|
|
mcpy(s->str, type, n);
|
|
|
|
rettype = s;
|
|
|
|
}
|
|
|
|
FLUSH(&retit);
|
|
|
|
FLUSH(&rettype);
|
|
|
|
}
|
2008-11-03 17:03:12 -07:00
|
|
|
|
|
|
|
extern Sigt *gotypesigs[];
|
|
|
|
extern int32 ngotypesigs;
|
|
|
|
|
|
|
|
static Sigt*
|
|
|
|
fakesigt(string type)
|
|
|
|
{
|
|
|
|
// TODO(rsc): Cache these by type string.
|
|
|
|
Sigt *sigt;
|
|
|
|
|
|
|
|
sigt = mal(2*sizeof sigt[0]);
|
|
|
|
sigt[0].name = mal(type->len + 1);
|
|
|
|
mcpy(sigt[0].name, type->str, type->len);
|
|
|
|
sigt[0].hash = ASIMP; // alg
|
|
|
|
sigt[0].offset = sizeof(void*); // width
|
|
|
|
return sigt;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int32
|
|
|
|
cmpstringchars(string a, uint8 *b)
|
|
|
|
{
|
|
|
|
int32 i;
|
|
|
|
|
|
|
|
for(i=0;; i++) {
|
|
|
|
if(i == a->len) {
|
|
|
|
if(b[i] == 0)
|
|
|
|
return 0;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if(b[i] == 0)
|
|
|
|
return 1;
|
|
|
|
if(a->str[i] != b[i]) {
|
|
|
|
if((uint8)a->str[i] < (uint8)b[i])
|
|
|
|
return -1;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static Sigt*
|
|
|
|
findtype(string type)
|
|
|
|
{
|
|
|
|
int32 i;
|
|
|
|
|
|
|
|
for(i=0; i<ngotypesigs; i++)
|
|
|
|
if(cmpstringchars(type, gotypesigs[i]->name) == 0)
|
|
|
|
return gotypesigs[i];
|
|
|
|
return fakesigt(type);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
sys·unreflect(uint64 it, string type, Map *retim, void *retit)
|
|
|
|
{
|
|
|
|
if(cmpstring(type, emptystring) == 0) {
|
|
|
|
retim = 0;
|
|
|
|
retit = 0;
|
|
|
|
} else {
|
2008-11-05 12:27:50 -07:00
|
|
|
retim = hashmap(sigi·empty, findtype(type), 0);
|
2008-11-03 17:03:12 -07:00
|
|
|
retit = (void*)it;
|
|
|
|
}
|
|
|
|
FLUSH(&retim);
|
|
|
|
FLUSH(&retit);
|
|
|
|
}
|
|
|
|
|