1
0
mirror of https://github.com/golang/go synced 2024-11-26 04:58:00 -07:00

another step toward interface subtypes

put explicit ./ on some runtime tests

R=r
OCL=17839
CL=17839
This commit is contained in:
Ken Thompson 2008-10-24 20:14:28 -07:00
parent cc4dc5a22a
commit b379d54dea
7 changed files with 601 additions and 322 deletions

View File

@ -455,84 +455,122 @@ sigcmp(Sig *a, Sig *b)
return strcmp(a->name, b->name);
}
static Addr at, ao, ac, ad;
static int wi, ot;
void
dumpsignatures(void)
ginsatoa(int fscale, int toffset)
{
Prog *p;
p = pc;
ot = rnd(ot, fscale);
gins(ADATA, N, N);
p->from = at;
p->from.offset = ot;
p->from.scale = fscale;
p->to = ao;
p->to.offset = toffset;
ot += fscale;
}
void
gensatac(int fscale, int toffset)
{
Prog *p;
p = pc;
ot = rnd(ot, fscale);
gins(ADATA, N, N);
p->from = at;
p->from.offset = ot;
p->from.scale = fscale;
p->to = ac;
p->to.offset = toffset;
ot += fscale;
}
void
gensatad(Sym *s)
{
Prog *p;
p = pc;
ot = rnd(ot, widthptr);
gins(ADATA, N, N);
p->from = at;
p->from.offset = ot;
p->from.scale = widthptr;
p->to = ad;
p->to.sym = s;
ot += widthptr;
}
void
gentramp(Type *t, Sig *b)
{
Sym *e;
int c, d;
e = lookup(b->name);
for(d=0; d<nelem(dotlist); d++) {
c = adddot1(e, t, d);
if(c == 1)
goto out;
}
fatal("gentramp");
out:
print("gentramp %d\n", d);
print(" t = %lT\n", t);
print(" name = %s\n", b->name);
print(" sym = %S\n", b->sym);
print(" hash = 0x%ux\n", b->hash);
for(c=d-1; c>=0; c--) {
print(" %d %d %S\n",
dotlist[c].ptr,
dotlist[c].offset,
dotlist[c].sym);
}
//TEXT main·S_test2(SB),7,$0
// MOVQ 8(SP), AX
// MOVQ XX(AX), AX
// ADDQ $XX, AX
// MOVQ AX, 8(SP)
// JMP main·Sub_test2(SB)
}
void
dumpsigt(void)
{
Dcl *d, *x;
Type *t, *f;
Sym *s1, *s;
int et, o, wi, ot;
int et, o;
Sig *a, *b;
Addr at, ao, ac, ad;
Prog *p;
char *sp;
char buf[NSYMB];
// 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;
s = signame(t, 0);
if(s == S)
continue;
x = mal(sizeof(*d));
x->op = OTYPE;
x->dsym = d->dsym;
x->dtype = d->dtype;
x->forw = signatlist;
x->block = 0;
signatlist = x;
//print("SIG = %lS %lS %lT\n", d->dsym, s, t);
}
/*
* put all the names into a linked
* list so that it may be generated in sorted order.
* the runtime will be linear rather than quadradic
*/
memset(&at, 0, sizeof(at));
memset(&ao, 0, sizeof(ao));
memset(&ac, 0, sizeof(ac));
memset(&ad, 0, sizeof(ad));
// sig structure
at.type = D_EXTERN;
at.index = D_NONE;
at.sym = S; // fill in
at.offset = 0; // fill in
// $string
ao.type = D_ADDR;
ao.index = D_STATIC;
ao.etype = TINT32;
ao.sym = symstringo;
ao.offset = 0; // fill in
// constant
ac.type = D_CONST;
ac.index = D_NONE;
ac.offset = 0; // fill in
// $method
ad.type = D_ADDR;
ad.index = D_EXTERN;
ad.sym = S; // fill in
ad.offset = 0;
wi = types[TINT32]->width;
for(d=signatlist; d!=D; d=d->forw) {
if(d->op != OTYPE)
continue;
t = d->dtype;
et = t->etype;
if(et == TINTER)
continue;
at.sym = signame(t, d->block);
if(at.sym == S)
continue;
@ -542,10 +580,6 @@ dumpsignatures(void)
continue;
at.sym->local = 2;
//print("SIGNAME = %lS\n", at.sym);
et = t->etype;
s = d->dsym;
if(s == S)
continue;
@ -556,14 +590,157 @@ dumpsignatures(void)
if(strcmp(s->opackage, package) != 0)
continue;
expandmeth(s, t);
a = nil;
o = 0;
for(f=t->method; f!=T; f=f->down) {
if(f->type->etype != TFUNC)
continue;
f = t->method;
if(et == TINTER)
f = t->type;
if(f->etype != TFIELD)
fatal("dumpsignatures: not field");
for(; f!=T; f=f->down) {
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);
a->perm = o;
snprint(namebuf, sizeof(namebuf), "%s_%s",
at.sym->name+5, f->sym->name);
a->sym = lookup(namebuf);
a->offset = f->embedded; // need trampoline
o++;
}
a = lsort(a, sigcmp);
ot = 0;
ot = rnd(ot, maxround); // base structure
// sigi[0].name = ""
ginsatoa(widthptr, stringo);
// save type name for runtime error message.
// TODO(rsc): the * is a botch but right more often than not.
snprint(buf, sizeof buf, "*%#T", t);
datastring(buf, strlen(buf)+1);
// first field of an type signature contains
// the element parameters and is not a real entry
t = d->dtype;
if(t->methptr & 2)
t = types[tptr];
// sigi[0].hash = elemalg
gensatac(wi, algtype(t));
// sigi[0].offset = width
gensatac(wi, t->width);
// skip the function
gensatac(widthptr, 0);
for(b=a; b!=nil; b=b->link) {
ot = rnd(ot, maxround); // base structure
// sigx[++].name = "fieldname"
ginsatoa(widthptr, stringo);
// sigx[++].hash = hashcode
gensatac(wi, b->hash);
// sigt[++].offset = of embeded struct
gensatac(wi, 0);
// sigt[++].fun = &method
gensatad(b->sym);
datastring(b->name, strlen(b->name)+1);
if(b->offset)
gentramp(d->dtype, b);
}
// nil field name at end
ot = rnd(ot, maxround);
gensatac(widthptr, 0);
p = pc;
gins(AGLOBL, N, N);
p->from = at;
p->to = ac;
p->to.offset = ot;
}
if(stringo > 0) {
p = pc;
gins(AGLOBL, N, N);
p->from = ao;
p->to = ac;
p->to.offset = stringo;
}
}
void
dumpsigi(void)
{
Dcl *d, *x;
Type *t, *f;
Sym *s1, *s;
int et, o;
Sig *a, *b;
Prog *p;
char *sp;
char buf[NSYMB];
/*
* put all the names into a linked
* list so that it may be generated in sorted order.
* the runtime will be linear rather than quadradic
*/
for(d=signatlist; d!=D; d=d->forw) {
if(d->op != OTYPE)
continue;
t = d->dtype;
et = t->etype;
if(et != TINTER)
continue;
at.sym = signame(t, d->block);
if(at.sym == S)
continue;
// make unique
if(at.sym->local != 1)
continue;
at.sym->local = 2;
s = d->dsym;
if(s == S)
continue;
if(s->name[0] == '_')
continue;
if(strcmp(s->opackage, package) != 0)
continue;
//print("sigi: %S\n", s);
a = nil;
o = 0;
for(f=t->type; f!=T; f=f->down) {
if(f->type->etype != TFUNC)
continue;
@ -597,162 +774,47 @@ dumpsignatures(void)
a = lsort(a, sigcmp);
ot = 0;
ot = rnd(ot, maxround); // base structure
// sigi[0].name = ""
ot = rnd(ot, maxround); // array of structures
p = pc;
gins(ADATA, N, N);
p->from = at;
p->from.offset = ot;
p->from.scale = widthptr;
p->to = ao;
p->to.offset = stringo;
ot += widthptr;
ginsatoa(widthptr, stringo);
// save type name for runtime error message.
// TODO(rsc): the * is a botch but right more often than not.
if(et == TINTER)
snprint(buf, sizeof buf, "%#T", t);
else
snprint(buf, sizeof buf, "*%#T", t);
snprint(buf, sizeof buf, "%#T", t);
datastring(buf, strlen(buf)+1);
if(et == TINTER) {
// first field of an interface signature
// contains the count and is not a real entry
o = 0;
for(b=a; b!=nil; b=b->link)
o++;
// first field of an interface signature
// contains the count and is not a real entry
// sigi[0].hash = 0
ot = rnd(ot, wi);
p = pc;
gins(ADATA, N, N);
p->from = at;
p->from.offset = ot;
p->from.scale = wi;
p->to = ac;
p->to.offset = 0;
ot += wi;
// sigi[0].hash = 0
gensatac(wi, 0);
// sigi[0].offset = count
ot = rnd(ot, wi);
p = pc;
gins(ADATA, N, N);
p->from = at;
p->from.offset = ot;
p->from.scale = wi;
p->to = ac;
p->to.offset = o;
ot += wi;
} else {
// first field of an type signature contains
// the element parameters and is not a real entry
t = d->dtype;
if(t->methptr & 2)
t = types[tptr];
// sigi[0].hash = elemalg
ot = rnd(ot, wi);
p = pc;
gins(ADATA, N, N);
p->from = at;
p->from.offset = ot;
p->from.scale = wi;
p->to = ac;
p->to.offset = algtype(t);
ot += wi;
// sigi[0].offset = width
ot = rnd(ot, wi);
p = pc;
gins(ADATA, N, N);
p->from = at;
p->from.offset = ot;
p->from.scale = wi;
p->to = ac;
p->to.offset = t->width;
ot += wi;
// skip the function
ot = rnd(ot, widthptr);
ot += widthptr;
}
// sigi[0].offset = count
o = 0;
for(b=a; b!=nil; b=b->link)
o++;
gensatac(wi, o);
for(b=a; b!=nil; b=b->link) {
//print(" %s\n", b->name);
ot = rnd(ot, maxround); // base structure
// sigx[++].name = "fieldname"
ot = rnd(ot, maxround); // array of structures
p = pc;
gins(ADATA, N, N);
p->from = at;
p->from.offset = ot;
p->from.scale = widthptr;
p->to = ao;
p->to.offset = stringo;
ot += widthptr;
ginsatoa(widthptr, stringo);
// sigx[++].hash = hashcode
ot = rnd(ot, wi);
p = pc;
gins(ADATA, N, N);
p->from = at;
p->from.offset = ot;
p->from.scale = wi;
p->to = ac;
p->to.offset = b->hash;
ot += wi;
gensatac(wi, b->hash);
if(et == TINTER) {
// sigi[++].perm = mapped offset of method
ot = rnd(ot, wi);
p = pc;
gins(ADATA, N, N);
p->from = at;
p->from.offset = ot;
p->from.scale = wi;
p->to = ac;
p->to.offset = b->perm;
ot += wi;
} else {
// sigt[++].offset = of embeded struct
ot = rnd(ot, wi);
p = pc;
gins(ADATA, N, N);
p->from = at;
p->from.offset = ot;
p->from.scale = wi;
p->to = ac;
p->to.offset = b->offset;
ot += wi;
// sigi[++].perm = mapped offset of method
gensatac(wi, b->perm);
// sigt[++].fun = &method
ot = rnd(ot, widthptr);
p = pc;
gins(ADATA, N, N);
p->from = at;
p->from.offset = ot;
p->from.scale = widthptr;
p->to = ad;
p->to.sym = b->sym;
ot += widthptr;
}
datastring(b->name, strlen(b->name)+1);
}
// nil field name at end
ot = rnd(ot, maxround);
p = pc;
gins(ADATA, N, N);
p->from = at;
p->from.offset = ot;
p->from.scale = widthptr;
p->to = ac;
p->to.offset = 0;
ot += widthptr;
gensatac(widthptr, 0);
p = pc;
gins(AGLOBL, N, N);
@ -769,3 +831,67 @@ dumpsignatures(void)
p->to.offset = stringo;
}
}
void
dumpsignatures(void)
{
Dcl *d, *x;
Type *t;
Sym *s;
memset(&at, 0, sizeof(at));
memset(&ao, 0, sizeof(ao));
memset(&ac, 0, sizeof(ac));
memset(&ad, 0, sizeof(ad));
wi = types[TINT32]->width;
// sig structure
at.type = D_EXTERN;
at.index = D_NONE;
at.sym = S; // fill in
at.offset = 0; // fill in
// $string
ao.type = D_ADDR;
ao.index = D_STATIC;
ao.etype = TINT32;
ao.sym = symstringo;
ao.offset = 0; // fill in
// constant
ac.type = D_CONST;
ac.index = D_NONE;
ac.offset = 0; // fill in
// $method
ad.type = D_ADDR;
ad.index = D_EXTERN;
ad.sym = S; // fill in
ad.offset = 0;
// 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;
s = signame(t, 0);
if(s == S)
continue;
x = mal(sizeof(*d));
x->op = OTYPE;
x->dsym = d->dsym;
x->dtype = d->dtype;
x->forw = signatlist;
x->block = 0;
signatlist = x;
//print("SIG = %lS %lS %lT\n", d->dsym, s, t);
}
dumpsigi();
dumpsigt();
}

View File

@ -208,6 +208,7 @@ struct Sym
uchar exported; // exported
uchar sym; // huffman encoding in object file
uchar local; // created in this file
uchar uniq; // imbedded field name first found
char* opackage; // original package name
char* package; // package name
@ -398,6 +399,16 @@ struct Io
char* cp; // used for content when bin==nil
};
typedef struct Dlist Dlist;
struct Dlist
{
Sym* sym;
uchar ptr;
int offset;
};
EXTERN Dlist dotlist[10]; // size is max depth of embeddeds
EXTERN Io curio;
EXTERN Io pushedio;
EXTERN int32 lineno;
@ -631,6 +642,13 @@ int Nconv(Fmt*);
int Wconv(Fmt*);
int Zconv(Fmt*);
int lookdot0(Sym*, Type*);
int adddot1(Sym*, Type*, int);
Node* adddot(Node*);
void expand0(Type*);
void expand1(Type*, int);
void expandmeth(Sym*, Type*);
/*
* dcl.c
*/
@ -748,7 +766,6 @@ Node* arraylit(Node*);
Node* maplit(Node*);
Node* selectas(Node*, Node*);
Node* old2new(Node*, Type*);
Node* adddot(Node*);
/*
* const.c

View File

@ -2377,3 +2377,251 @@ getinargx(Type *t)
{
return *getinarg(t);
}
/*
* code to resolve elided DOTs
* in embedded types
*/
// search depth 0 --
// return count of fields+methods
// found with a given name
int
lookdot0(Sym *s, Type *t)
{
Type *f, *u;
int c;
u = t;
if(isptr[u->etype])
u = u->type;
c = 0;
if(u->etype == TSTRUCT || u->etype == TINTER) {
for(f=u->type; f!=T; f=f->down)
if(f->sym == s)
c++;
}
u = methtype(t);
if(u != T) {
for(f=u->method; f!=T; f=f->down)
if(f->sym == s && f->embedded == 0)
c++;
}
return c;
}
// search depth d --
// return count of fields+methods
// found at search depth.
// answer is in dotlist array and
// count of number of ways is returned.
int
adddot1(Sym *s, Type *t, int d)
{
Type *f, *u;
int c, a;
if(t->trecur)
return 0;
t->trecur = 1;
if(d == 0) {
c = lookdot0(s, t);
goto out;
}
c = 0;
u = t;
if(isptr[u->etype])
u = u->type;
if(u->etype != TSTRUCT && u->etype != TINTER)
goto out;
d--;
for(f=u->type; f!=T; f=f->down) {
if(!f->embedded)
continue;
if(f->sym == S)
continue;
a = adddot1(s, f->type, d);
if(a != 0 && c == 0) {
dotlist[d].sym = f->sym;
dotlist[d].offset = f->width;
dotlist[d].ptr = 0;
if(isptr[f->type->etype])
dotlist[d].ptr = 1;
}
c += a;
}
out:
t->trecur = 0;
return c;
}
// in T.field
// find missing fields that
// will give shortest unique addressing.
// modify the tree with missing type names.
Node*
adddot(Node *n)
{
Type *t;
Sym *s;
Node *l;
int c, d;
walktype(n->left, Erv);
t = n->left->type;
if(t == T)
return n;
if(n->right->op != ONAME)
return n;
s = n->right->sym;
if(s == S)
return n;
for(d=0; d<nelem(dotlist); d++) {
c = adddot1(s, t, d);
if(c > 0)
goto out;
}
return n;
out:
if(c > 1)
yyerror("ambiguous DOT reference %S", s);
// rebuild elided dots
for(c=d-1; c>=0; c--) {
n = nod(ODOT, n, n->right);
n->left->right = newname(dotlist[c].sym);
}
return n;
}
/*
* code to help generate trampoline
* functions for methods on embedded
* subtypes.
* these are approx the same as
* the corresponding adddot routines
* except that they expect to be called
* with unique tasks and they return
* the actual methods.
*/
typedef struct Symlink Symlink;
struct Symlink
{
Type* field;
uchar good;
Symlink* link;
};
static Symlink* slist;
void
expand0(Type *t)
{
Type *f, *u;
Symlink *sl;
u = t;
if(isptr[u->etype])
u = u->type;
u = methtype(t);
if(u != T) {
for(f=u->method; f!=T; f=f->down) {
if(f->sym->uniq)
continue;
f->sym->uniq = 1;
sl = mal(sizeof(*sl));
sl->field = f;
sl->link = slist;
slist = sl;
}
}
}
void
expand1(Type *t, int d)
{
Type *f, *u;
if(t->trecur)
return;
if(d == 0)
return;
t->trecur = 1;
if(d != nelem(dotlist)-1)
expand0(t);
u = t;
if(isptr[u->etype])
u = u->type;
if(u->etype != TSTRUCT && u->etype != TINTER)
goto out;
for(f=u->type; f!=T; f=f->down) {
if(!f->embedded)
continue;
if(f->sym == S)
continue;
expand1(f->type, d-1);
}
out:
t->trecur = 0;
}
void
expandmeth(Sym *s, Type *t)
{
Symlink *sl;
Type *f;
int c, d;
if(s == S)
return;
if(t == T)
return;
if(strcmp(s->name, "S") != 0)
return;
// generate all reachable methods
slist = nil;
expand1(t, nelem(dotlist)-1);
// check each method to be uniquely reachable
for(sl=slist; sl!=nil; sl=sl->link) {
for(d=0; d<nelem(dotlist); d++) {
c = adddot1(sl->field->sym, t, d);
if(c == 0)
continue;
if(c == 1)
sl->good = 1;
break;
}
}
//print("expand %S: %lT", s, t);
for(sl=slist; sl!=nil; sl=sl->link) {
if(sl->good) {
// add it to the base type method list
f = typ(TFIELD);
*f = *sl->field;
f->embedded = 1; // needs a trampoline
f->down = t->method;
t->method = f;
//print(" %T", f);
}
}
//print("\n");
}

View File

@ -3203,116 +3203,3 @@ loop:
r = listnext(&saver);
goto loop;
}
static int prdot = 0;
int
lookdot0(Sym *s, Type *t)
{
Type *f, *u;
int c;
u = t;
if(isptr[u->etype])
u = u->type;
c = 0;
if(u->etype == TSTRUCT || u->etype == TINTER) {
for(f=u->type; f!=T; f=f->down)
if(f->sym == s)
c++;
}
u = methtype(t);
if(u != T) {
for(f=u->method; f!=T; f=f->down)
if(f->sym == s)
{
if(prdot)
print("found method %S\n", s);
c++;
}
}
return c;
}
enum { maxembed = 10 }; // max depth search for embedded types
static Sym* dotlist[maxembed+1]; // maxembed..1
int
adddot1(Sym *s, Type *t, int d)
{
Type *f, *u;
int c, a;
if(d == 0)
return lookdot0(s, t);
u = t;
if(isptr[u->etype])
u = u->type;
if(u->etype != TSTRUCT && u->etype != TINTER)
return 0;
c = 0;
for(f=u->type; f!=T; f=f->down) {
if(!f->embedded)
continue;
if(f->sym == S)
continue;
a = adddot1(s, f->type, d-1);
if(a != 0 && c == 0)
dotlist[d] = f->sym;
c += a;
}
return c;
}
Node*
adddot(Node *n)
{
Type *t;
Sym *s;
Node *l;
int c, d;
walktype(n->left, Erv);
t = n->left->type;
if(t == T)
return n;
if(n->right->op != ONAME)
return n;
s = n->right->sym;
if(s == S)
return n;
for(d=0; d<maxembed; d++) {
c = adddot1(s, t, d);
if(c > 0)
goto out;
}
if(prdot) {
print("missed");
dump("", n);
}
return n;
out:
if(c > 1)
yyerror("ambiguous DOT reference %S", s);
if(prdot)
if(d > 0)
print("add dots:");
// rebuild elided dots
for(c=d; c>0; c--) {
n = nod(ODOT, n, n->right);
n->left->right = newname(dotlist[c]);
if(prdot)
print(" %S", dotlist[c]);
}
if(prdot)
if(d > 0)
print("\n");
return n;
}

View File

@ -6,8 +6,9 @@
set -e
xcd() {
builtin cd $1
echo
echo --- cd $1
builtin cd $1
}
(xcd lib/reflect
@ -41,7 +42,7 @@ rm -f *.6 6.out
6g printf.go
6g main.go
6l main.6
6.out
./6.out
)
(xcd ../test

View File

@ -9,7 +9,7 @@ pretty: pretty.6
$(L) -o pretty pretty.6
test: pretty
test.sh
./test.sh
install: pretty
cp pretty $(HOME)/bin/pretty

View File

@ -61,7 +61,7 @@ cleanup() {
silent() {
cleanup
pretty -s $1 > $TMP1
./pretty -s $1 > $TMP1
if [ $? != 0 ]; then
cat $TMP1
echo "Error (silent mode test): test.sh $1"
@ -72,8 +72,8 @@ silent() {
idempotent() {
cleanup
pretty $1 > $TMP1
pretty $TMP1 > $TMP2
./pretty $1 > $TMP1
./pretty $TMP1 > $TMP2
cmp -s $TMP1 $TMP2
if [ $? != 0 ]; then
diff $TMP1 $TMP2
@ -85,7 +85,7 @@ idempotent() {
valid() {
cleanup
pretty $1 > $TMP1
./pretty $1 > $TMP1
6g -o /dev/null $TMP1
if [ $? != 0 ]; then
echo "Error (validity test): test.sh $1"
@ -122,7 +122,7 @@ runtests() {
# run selftest always
pretty -t selftest.go > $TMP1
./pretty -t selftest.go > $TMP1
if [ $? != 0 ]; then
cat $TMP1
echo "Error (selftest): pretty -t selftest.go"