Commit 541e638f authored by Russ Cox's avatar Russ Cox

6g, 8g: generate data structures for new reflect interface (CL 31107)

R=ken
OCL=31122
CL=31278
parent c7513eac
......@@ -488,6 +488,46 @@ dstringptr(Sym *s, int off, char *str)
return off;
}
int
dgostrlitptr(Sym *s, int off, Strlit *lit)
{
Prog *p;
if(lit == nil)
return duintptr(s, off, 0);
off = rnd(off, widthptr);
p = gins(ADATA, N, N);
p->from.type = D_EXTERN;
p->from.index = D_NONE;
p->from.sym = s;
p->from.offset = off;
p->from.scale = widthptr;
datagostring(lit, &p->to);
p->to.index = p->to.type;
p->to.type = D_ADDR;
p->to.etype = TINT32;
off += widthptr;
return off;
}
int
dgostringptr(Sym *s, int off, char *str)
{
int n;
Strlit *lit;
if(str == nil)
return duintptr(s, off, 0);
n = strlen(str);
lit = mal(sizeof *lit + n);
strcpy(lit->s, str);
lit->len = n;
return dgostrlitptr(s, off, lit);
}
int
duintxx(Sym *s, int off, uint64 v, int wid)
{
......
......@@ -486,6 +486,47 @@ dstringptr(Sym *s, int off, char *str)
return off;
}
int
dgostrlitptr(Sym *s, int off, Strlit *lit)
{
Prog *p;
if(lit == nil)
return duintptr(s, off, 0);
off = rnd(off, widthptr);
p = gins(ADATA, N, N);
p->from.type = D_EXTERN;
p->from.index = D_NONE;
p->from.sym = s;
p->from.offset = off;
p->from.scale = widthptr;
datagostring(lit, &p->to);
p->to.index = p->to.type;
p->to.type = D_ADDR;
p->to.etype = TINT32;
off += widthptr;
return off;
}
int
dgostringptr(Sym *s, int off, char *str)
{
int n;
Strlit *lit;
if(str == nil)
return duintptr(s, off, 0);
n = strlen(str);
lit = mal(sizeof *lit + n);
strcpy(lit->s, str);
lit->len = n;
return dgostrlitptr(s, off, lit);
}
int
duintxx(Sym *s, int off, uint64 v, int wid)
{
......
......@@ -15,6 +15,7 @@ YFILES=\
go.y\
OFILES=\
reflect.$O\
y.tab.$O\
lex.$O\
subr.$O\
......
......@@ -243,6 +243,10 @@ typeinit(void)
isptr[TPTR32] = 1;
isptr[TPTR64] = 1;
isforw[TFORW] = 1;
isforw[TFORWSTRUCT] = 1;
isforw[TFORWINTER] = 1;
issigned[TINT] = 1;
issigned[TINT8] = 1;
issigned[TINT16] = 1;
......
......@@ -26,17 +26,17 @@ char *sysimport =
"func sys.stringiter (? string, ? int) (? int)\n"
"func sys.stringiter2 (? string, ? int) (retk int, retv int)\n"
"func sys.ifaceI2E (iface any) (ret any)\n"
"func sys.ifaceE2I (sigi *uint8, iface any) (ret any)\n"
"func sys.ifaceT2E (sigt *uint8, elem any) (ret any)\n"
"func sys.ifaceE2T (sigt *uint8, elem any) (ret any)\n"
"func sys.ifaceE2I2 (sigi *uint8, iface any) (ret any, ok bool)\n"
"func sys.ifaceE2T2 (sigt *uint8, elem any) (ret any, ok bool)\n"
"func sys.ifaceT2I (sigi *uint8, sigt *uint8, elem any) (ret any)\n"
"func sys.ifaceI2T (sigt *uint8, iface any) (ret any)\n"
"func sys.ifaceI2T2 (sigt *uint8, iface any) (ret any, ok bool)\n"
"func sys.ifaceI2I (sigi *uint8, iface any) (ret any)\n"
"func sys.ifaceI2Ix (sigi *uint8, iface any) (ret any)\n"
"func sys.ifaceI2I2 (sigi *uint8, iface any) (ret any, ok bool)\n"
"func sys.ifaceE2I (typ *uint8, iface any) (ret any)\n"
"func sys.ifaceT2E (typ *uint8, elem any) (ret any)\n"
"func sys.ifaceE2T (typ *uint8, elem any) (ret any)\n"
"func sys.ifaceE2I2 (typ *uint8, iface any) (ret any, ok bool)\n"
"func sys.ifaceE2T2 (typ *uint8, elem any) (ret any, ok bool)\n"
"func sys.ifaceT2I (typ1 *uint8, typ2 *uint8, elem any) (ret any)\n"
"func sys.ifaceI2T (typ *uint8, iface any) (ret any)\n"
"func sys.ifaceI2T2 (typ *uint8, iface any) (ret any, ok bool)\n"
"func sys.ifaceI2I (typ *uint8, iface any) (ret any)\n"
"func sys.ifaceI2Ix (typ *uint8, iface any) (ret any)\n"
"func sys.ifaceI2I2 (typ *uint8, iface any) (ret any, ok bool)\n"
"func sys.ifaceeq (i1 any, i2 any) (ret bool)\n"
"func sys.efaceeq (i1 any, i2 any) (ret bool)\n"
"func sys.ifacethash (i1 any) (ret uint32)\n"
......@@ -80,7 +80,8 @@ char *unsafeimport =
"func unsafe.Offsetof (? any) (? int)\n"
"func unsafe.Sizeof (? any) (? int)\n"
"func unsafe.Alignof (? any) (? int)\n"
"func unsafe.Reflect (i interface { }) (? uint64, ? string, ? bool)\n"
"func unsafe.Unreflect (? uint64, ? string, ? bool) (ret interface { })\n"
"func unsafe.Typeof (i interface { }) (typ interface { })\n"
"func unsafe.Reflect (i interface { }) (typ interface { }, addr unsafe.Pointer)\n"
"func unsafe.Unreflect (typ interface { }, addr unsafe.Pointer) (ret interface { })\n"
"\n"
"$$\n";
......@@ -391,6 +391,7 @@ enum
enum
{
/* types of channel */
/* must match ../../pkg/nreflect/type.go:/Chandir */
Cxxx,
Crecv = 1<<0,
Csend = 1<<1,
......@@ -457,7 +458,10 @@ typedef struct Sig Sig;
struct Sig
{
char* name;
Sym* sym;
char* package;
Sym* isym;
Sym* tsym;
Type* type;
uint32 hash;
int32 perm;
int32 offset;
......@@ -736,7 +740,7 @@ int isnilinter(Type*);
int isddd(Type*);
Type* maptype(Type*, Type*);
Type* methtype(Type*);
Node* signame(Type*);
Node* typename(Type*);
int eqtype(Type*, Type*);
int cvttype(Type*, Type*);
int eqtypenoname(Type*, Type*);
......@@ -782,7 +786,6 @@ Type* funcnext(Iter*);
int brcom(int);
int brrev(int);
void setmaxarg(Type*);
Sig* lsort(Sig*, int(*)(Sig*, Sig*));
int dotoffset(Node*, int*, Node**);
void tempname(Node*, Type*);
......@@ -1073,7 +1076,7 @@ int isfat(Type*);
void clearfat(Node *n);
void cgen(Node*, Node*);
void gused(Node*);
void dumpsignatures(void);
void dumptypestructs(void);
void dumpfuncs(void);
void dumpdata(void);
void ggloblnod(Node *nam, int32 width);
......
......@@ -28,7 +28,7 @@ dumpobj(void)
newplist();
dumpglobls();
dumpsignatures();
dumptypestructs();
dumpdata();
dumpfuncs();
......@@ -169,414 +169,3 @@ duintptr(Sym *s, int off, uint64 v)
{
return duintxx(s, off, v, widthptr);
}
static int
sigcmp(Sig *a, Sig *b)
{
return strcmp(a->name, b->name);
}
/*
* Add DATA for signature s.
* progt - type in program
* ifacet - type stored in interface (==progt if small, ==ptrto(progt) if large)
* rcvrt - type used as method interface. eqtype(ifacet, rcvrt) is always true,
* but ifacet might have a name that rcvrt does not.
* methodt - type with methods hanging off it (progt==*methodt sometimes)
*
* memory layout is Sigt struct from iface.c:
* 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
* 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
* };
*/
void
dumpsigt(Type *progt, Type *ifacet, Type *rcvrt, Type *methodt, Sym *s)
{
Type *f;
int o;
Sig *a, *b;
char buf[NSYMB];
Type *this;
Prog *oldlist;
Sym *method;
uint32 sighash;
int ot;
if(debug['r']) {
print("dumpsigt progt=%T ifacet=%T rcvrt=%T methodt=%T s=%S\n",
progt, ifacet, rcvrt, methodt, s);
}
a = nil;
o = 0;
oldlist = nil;
sighash = typehash(progt, 1, 0);
for(f=methodt->method; f!=T; f=f->down) {
if(f->type->etype != TFUNC)
continue;
if(f->etype != TFIELD)
fatal("dumpsignatures: not field");
method = f->sym;
if(method == nil)
continue;
// get receiver type for this particular method.
this = getthisx(f->type)->type->type;
if(f->embedded != 2 && isptr[this->etype] && !isptr[progt->etype] && !isifacemethod(f)) {
// pointer receiver method but value method set.
// ignore.
if(debug['r'])
print("ignore %T for %T\n", f, progt);
continue;
}
b = mal(sizeof(*b));
b->link = a;
a = b;
a->name = method->name;
a->hash = PRIME8*stringhash(a->name) + PRIME9*typehash(f->type, 0, 0);
if(!exportname(a->name))
a->hash += PRIME10*stringhash(package);
a->perm = o;
a->sym = methodsym(method, rcvrt);
sighash = sighash*100003 + a->hash;
if(!a->sym->siggen) {
a->sym->siggen = 1;
if(!eqtype(this, ifacet)) {
if(oldlist == nil)
oldlist = pc;
// It would be okay to call genwrapper here always,
// but we can generate more efficient code
// using genembedtramp if all that is necessary
// is a pointer adjustment and a JMP.
if(f->embedded && isptr[ifacet->etype] && !isifacemethod(f))
genembedtramp(ifacet, f, a->sym);
else
genwrapper(ifacet, f, a->sym);
}
}
o++;
}
// restore data output
if(oldlist) {
// old list ended with AEND; change to ANOP
// so that the trampolines that follow can be found.
nopout(oldlist);
// start new data list
newplist();
}
a = lsort(a, sigcmp);
ot = 0;
ot = rnd(ot, maxround); // base structure
// base of type signature contains parameters
snprint(buf, sizeof buf, "%#T", progt);
ot = dstringptr(s, ot, buf); // name
ot = duintptr(s, ot, 0); // skip link
ot = duint32(s, ot, typehash(progt, 1, 0)); // thash
ot = duint32(s, ot, sighash); // mhash
ot = duint16(s, ot, progt->width); // width
ot = duint16(s, ot, algtype(progt)); // algorithm
for(b=a; b!=nil; b=b->link) {
ot = rnd(ot, maxround); // base of substructure
ot = dstringptr(s, ot, b->name); // field name
ot = duint32(s, ot, b->hash); // hash
ot = duint32(s, ot, 0); // offset
ot = dsymptr(s, ot, b->sym, 0); // &method
}
// nil field name at end
ot = rnd(ot, maxround);
ot = duintptr(s, ot, 0);
// set DUPOK to allow other .6s to contain
// the same signature. only one will be chosen.
// should only happen for empty signatures
ggloblsym(s, ot, a == nil);
}
/*
* memory layout is Sigi struct from iface.c:
* 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
* };
*/
void
dumpsigi(Type *t, Sym *s)
{
Type *f;
Sym *s1;
int o;
Sig *a, *b;
char buf[NSYMB];
uint32 sighash;
int ot;
a = nil;
o = 0;
sighash = 0;
for(f=t->type; f!=T; f=f->down) {
if(f->type->etype != TFUNC)
continue;
if(f->etype != TFIELD)
fatal("dumpsignatures: not field");
s1 = f->sym;
if(s1 == nil)
continue;
b = mal(sizeof(*b));
b->link = a;
a = b;
a->name = s1->name;
a->hash = PRIME8*stringhash(a->name) + PRIME9*typehash(f->type, 0, 0);
if(!exportname(a->name))
a->hash += PRIME10*stringhash(package);
a->perm = o;
a->sym = methodsym(f->sym, t);
a->offset = 0;
sighash = sighash*100003 + a->hash;
o++;
}
a = lsort(a, sigcmp);
ot = 0;
ot = rnd(ot, maxround); // base structure
// sigi[0].name = type name, for runtime error message
snprint(buf, sizeof buf, "%#T", t);
ot = dstringptr(s, ot, buf);
// first field of an interface signature
// contains the count and is not a real entry
// sigi[0].hash = sighash
ot = duint32(s, ot, sighash);
// sigi[0].offset = count
o = 0;
for(b=a; b!=nil; b=b->link)
o++;
ot = duint32(s, ot, o);
for(b=a; b!=nil; b=b->link) {
//print(" %s\n", b->name);
ot = rnd(ot, maxround); // base structure
// sigx[++].name = "fieldname"
// sigx[++].hash = hashcode
// sigi[++].perm = mapped offset of method
ot = dstringptr(s, ot, b->name);
ot = duint32(s, ot, b->hash);
ot = duint32(s, ot, b->perm);
}
// nil field name at end
ot = rnd(ot, maxround);
ot = duintptr(s, ot, 0);
// TODO(rsc): DUPOK should not be necessary here,
// and I am a bit worried that it is. If I turn it off,
// I get multiple definitions for sigi.dotdotdot.
ggloblsym(s, ot, 1);
}
void
dumpsignatures(void)
{
int et;
Dcl *d, *x;
Type *t, *progt, *methodt, *ifacet, *rcvrt;
Sym *s;
Node *n;
// copy externdcl list to signatlist
for(d=externdcl; d!=D; d=d->forw) {
if(d->op != OTYPE)
continue;
t = d->dtype;
if(t == T)
continue;
n = signame(t);
if(n == N || n->sym == S)
continue;
s = n->sym;
x = mal(sizeof(*d));
x->op = OTYPE;
if(t->etype == TINTER)
x->dtype = t;
else
x->dtype = ptrto(t);
x->forw = signatlist;
x->block = 0;
signatlist = x;
//print("SIG = %lS %lS %lT\n", d->dsym, s, t);
}
// process signatlist
for(d=signatlist; d!=D; d=d->forw) {
if(d->op != OTYPE)
continue;
t = d->dtype;
et = t->etype;
n = signame(t);
//print("signame %S for %T\n", s, t);
if(n == N || n->sym == S)
continue;
s = n->sym;
// only emit one
if(s->siggen)
continue;
s->siggen = 1;
// interface is easy
if(et == TINTER || et == TDDD) {
if(t->sym && !t->local)
continue;
dumpsigi(t, s);
continue;
}
// non-interface is more complex
progt = t;
methodt = t;
ifacet = t;
rcvrt = t;
// if there's a pointer, methods are on base.
methodt = methtype(progt);
if(methodt == T) {
// if that failed, go back to progt,
// assuming we're writing out a signature
// for a type with no methods
methodt = progt;
} else {
expandmeth(methodt->sym, methodt);
}
// if ifacet is too wide, the methods will see a pointer.
if(ifacet->width > widthptr) {
ifacet = ptrto(progt);
rcvrt = ptrto(progt);
}
// don't emit non-trivial signatures for types defined outside this file.
// non-trivial signatures might also drag in generated trampolines,
// and ar can't handle duplicate functions.
// only pay attention to types with symbols, because
// the ... structs and maybe other internal structs
// don't get marked as local.
if(methodt->method && methodt->sym && !methodt->local)
continue;
//print("s=%S\n", s);
dumpsigt(progt, ifacet, rcvrt, methodt, s);
}
}
Sig*
lsort(Sig *l, int(*f)(Sig*, Sig*))
{
Sig *l1, *l2, *le;
if(l == 0 || l->link == 0)
return l;
l1 = l;
l2 = l;
for(;;) {
l2 = l2->link;
if(l2 == 0)
break;
l2 = l2->link;
if(l2 == 0)
break;
l1 = l1->link;
}
l2 = l1->link;
l1->link = 0;
l1 = lsort(l, f);
l2 = lsort(l2, f);
/* set up lead element */
if((*f)(l1, l2) < 0) {
l = l1;
l1 = l1->link;
} else {
l = l2;
l2 = l2->link;
}
le = l;
for(;;) {
if(l1 == 0) {
while(l2) {
le->link = l2;
le = l2;
l2 = l2->link;
}
le->link = 0;
break;
}
if(l2 == 0) {
while(l1) {
le->link = l1;
le = l1;
l1 = l1->link;
}
break;
}
if((*f)(l1, l2) < 0) {
le->link = l1;
le = l1;
l1 = l1->link;
} else {
le->link = l2;
le = l2;
l2 = l2->link;
}
}
le->link = 0;
return l;
}
This diff is collapsed.
......@@ -1613,64 +1613,6 @@ iscomposite(Type *t)
return 0;
}
Node*
signame(Type *t)
{
Sym *ss;
char *e;
Dcl *x;
char buf[NSYMB];
//print("signame %T\n", t);
if(t == T)
goto bad;
e = "sigt";
if(t->etype == TINTER || t->etype == TDDD)
e = "sigi";
// name is exported name, like *[]byte or *Struct or Interface
// (special symbols don't bother the linker).
snprint(buf, sizeof(buf), "%#T", t);
// special case: empty interface is named sigi.empty
// so that it can be referred to by the runtime.
if(strcmp(buf, "interface { }") == 0)
strcpy(buf, "empty");
// special case: sigi.... is just too hard to read in assembly.
if(strcmp(buf, "...") == 0)
strcpy(buf, "dotdotdot");
ss = pkglookup(buf, e);
if(ss->def == N) {
ss->def = newname(ss);
ss->def->type = types[TUINT8];
ss->def->class = PEXTERN;
}
//print("siggen %T %d\n", t, t->siggen);
if(!t->siggen) {
// special case: don't generate the empty interface
if(strcmp(buf, "empty") == 0)
goto out;
// record internal type for signature generation
x = mal(sizeof(*x));
x->op = OTYPE;
x->dtype = t;
x->forw = signatlist;
t->siggen = 1;
signatlist = x;
}
out:
return ss->def;
bad:
return N;
}
int
eqtype1(Type *t1, Type *t2, int d, int names)
{
......
......@@ -2,12 +2,12 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package PACKAGE
type Pointer *any;
func Offsetof(any) int;
func Sizeof(any) int;
func Alignof(any) int;
func Reflect(i interface { }) (uint64, string, bool);
func Unreflect(uint64, string, bool) (ret interface { });
func Typeof(i interface { }) (typ interface{});
func Reflect(i interface { }) (typ interface{}, addr Pointer);
func Unreflect(typ interface{}, addr Pointer) (ret interface { });
......@@ -1309,7 +1309,7 @@ walkconv(Node *n)
n->op = OCONVNOP;
return;
}
// to/from interface.
// ifaceas1 will generate a good error
// if the conversion is invalid.
......@@ -1940,7 +1940,6 @@ loop:
Type*
sigtype(Type *st)
{
Dcl *x;
Sym *s;
Type *t;
static int sigdddgen;
......@@ -1954,16 +1953,6 @@ sigtype(Type *st)
t = dodcltype(t);
updatetype(t, st);
t->local = 1;
// record internal type for signature generation
x = mal(sizeof(*x));
x->op = OTYPE;
x->dsym = s;
x->dtype = t;
x->forw = signatlist;
x->block = block;
signatlist = x;
return t;
}
......@@ -3260,10 +3249,10 @@ ifacecvt(Type *tl, Node *n, int et)
a = n; // elem
r = a;
a = nod(OADDR, signame(tr), N); // sigt
a = typename(tr); // sigt
r = list(a, r);
a = nod(OADDR, signame(tl), N); // sigi
a = typename(tl); // sigi
r = list(a, r);
on = syslook("ifaceT2I", 1);
......@@ -3284,7 +3273,7 @@ ifacecvt(Type *tl, Node *n, int et)
a = n; // interface
r = a;
a = nod(OADDR, signame(tl), N); // sigi or sigt
a = typename(tl); // sigi or sigt
r = list(a, r);
on = syslook(ifacename[et], 1);
......@@ -3308,7 +3297,7 @@ ifacecvt(Type *tl, Node *n, int et)
a = n; // elem
r = a;
a = nod(OADDR, signame(tr), N); // sigt
a = typename(tr); // sigt
r = list(a, r);
on = syslook("ifaceT2E", 1);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment