mirror of
https://github.com/golang/go
synced 2024-11-25 13:17:56 -07:00
binary search on type switches.
new feature 'case nil:' in type switch will match iff the interface is nil. R=r OCL=26404 CL=26404
This commit is contained in:
parent
e9f4fb2839
commit
0f469a99a3
@ -661,7 +661,7 @@ dumpsigt(Type *progt, Type *ifacet, Type *rcvrt, Type *methodt, Sym *s)
|
|||||||
a = nil;
|
a = nil;
|
||||||
o = 0;
|
o = 0;
|
||||||
oldlist = nil;
|
oldlist = nil;
|
||||||
sighash = typehash(progt, 0);
|
sighash = typehash(progt, 1, 0);
|
||||||
for(f=methodt->method; f!=T; f=f->down) {
|
for(f=methodt->method; f!=T; f=f->down) {
|
||||||
if(f->type->etype != TFUNC)
|
if(f->type->etype != TFUNC)
|
||||||
continue;
|
continue;
|
||||||
@ -678,7 +678,7 @@ dumpsigt(Type *progt, Type *ifacet, Type *rcvrt, Type *methodt, Sym *s)
|
|||||||
a = b;
|
a = b;
|
||||||
|
|
||||||
a->name = method->name;
|
a->name = method->name;
|
||||||
a->hash = PRIME8*stringhash(a->name) + PRIME9*typehash(f->type, 0);
|
a->hash = PRIME8*stringhash(a->name) + PRIME9*typehash(f->type, 0, 0);
|
||||||
if(!exportname(a->name))
|
if(!exportname(a->name))
|
||||||
a->hash += PRIME10*stringhash(package);
|
a->hash += PRIME10*stringhash(package);
|
||||||
a->perm = o;
|
a->perm = o;
|
||||||
@ -735,7 +735,7 @@ dumpsigt(Type *progt, Type *ifacet, Type *rcvrt, Type *methodt, Sym *s)
|
|||||||
// base of type signature contains parameters
|
// base of type signature contains parameters
|
||||||
ginsatoa(widthptr, stringo); // name
|
ginsatoa(widthptr, stringo); // name
|
||||||
ot = rnd(ot, widthptr)+widthptr; // skip link
|
ot = rnd(ot, widthptr)+widthptr; // skip link
|
||||||
gensatac(wi, typehash(progt, 0)); // thash
|
gensatac(wi, typehash(progt, 1, 0)); // thash
|
||||||
gensatac(wi, sighash); // mhash
|
gensatac(wi, sighash); // mhash
|
||||||
gensatac(ws, progt->width); // width
|
gensatac(ws, progt->width); // width
|
||||||
gensatac(ws, algtype(progt)); // algorithm
|
gensatac(ws, algtype(progt)); // algorithm
|
||||||
@ -815,7 +815,7 @@ dumpsigi(Type *t, Sym *s)
|
|||||||
a = b;
|
a = b;
|
||||||
|
|
||||||
a->name = s1->name;
|
a->name = s1->name;
|
||||||
a->hash = PRIME8*stringhash(a->name) + PRIME9*typehash(f->type, 0);
|
a->hash = PRIME8*stringhash(a->name) + PRIME9*typehash(f->type, 0, 0);
|
||||||
if(!exportname(a->name))
|
if(!exportname(a->name))
|
||||||
a->hash += PRIME10*stringhash(package);
|
a->hash += PRIME10*stringhash(package);
|
||||||
a->perm = o;
|
a->perm = o;
|
||||||
|
@ -26,6 +26,7 @@ char *sysimport =
|
|||||||
"func sys.ifaceI2I (sigi *uint8, iface any) (ret any)\n"
|
"func sys.ifaceI2I (sigi *uint8, iface any) (ret any)\n"
|
||||||
"func sys.ifaceI2I2 (sigi *uint8, iface any) (ret any, ok bool)\n"
|
"func sys.ifaceI2I2 (sigi *uint8, iface any) (ret any, ok bool)\n"
|
||||||
"func sys.ifaceeq (i1 any, i2 any) (ret bool)\n"
|
"func sys.ifaceeq (i1 any, i2 any) (ret bool)\n"
|
||||||
|
"func sys.ifacethash (i1 any) (ret uint32)\n"
|
||||||
"func sys.newmap (keysize int, valsize int, keyalg int, valalg int, hint int) (hmap map[any] any)\n"
|
"func sys.newmap (keysize int, valsize int, keyalg int, valalg int, hint int) (hmap map[any] any)\n"
|
||||||
"func sys.mapaccess1 (hmap map[any] any, key any) (val any)\n"
|
"func sys.mapaccess1 (hmap map[any] any, key any) (val any)\n"
|
||||||
"func sys.mapaccess2 (hmap map[any] any, key any) (val any, pres bool)\n"
|
"func sys.mapaccess2 (hmap map[any] any, key any) (val any, pres bool)\n"
|
||||||
|
@ -659,7 +659,7 @@ int eqtype(Type*, Type*, int);
|
|||||||
int eqtypenoname(Type*, Type*);
|
int eqtypenoname(Type*, Type*);
|
||||||
void argtype(Node*, Type*);
|
void argtype(Node*, Type*);
|
||||||
int eqargs(Type*, Type*);
|
int eqargs(Type*, Type*);
|
||||||
uint32 typehash(Type*, int);
|
uint32 typehash(Type*, int, int);
|
||||||
void frame(int);
|
void frame(int);
|
||||||
Node* dobad(void);
|
Node* dobad(void);
|
||||||
Node* nodintconst(int64);
|
Node* nodintconst(int64);
|
||||||
|
@ -484,6 +484,13 @@ complex_stmt:
|
|||||||
// right will point to next case
|
// right will point to next case
|
||||||
// done in casebody()
|
// done in casebody()
|
||||||
poptodcl();
|
poptodcl();
|
||||||
|
if(typeswvar != N && typeswvar->right != N)
|
||||||
|
if($2->op == OLITERAL && $2->val.ctype == CTNIL) {
|
||||||
|
// this version in type switch case nil
|
||||||
|
$$ = nod(OTYPESW, N, N);
|
||||||
|
$$ = nod(OXCASE, $$, N);
|
||||||
|
break;
|
||||||
|
}
|
||||||
$$ = nod(OXCASE, $2, N);
|
$$ = nod(OXCASE, $2, N);
|
||||||
}
|
}
|
||||||
| LCASE name '=' expr ':'
|
| LCASE name '=' expr ':'
|
||||||
@ -821,7 +828,6 @@ pexpr:
|
|||||||
| LNIL
|
| LNIL
|
||||||
{
|
{
|
||||||
Val v;
|
Val v;
|
||||||
|
|
||||||
v.ctype = CTNIL;
|
v.ctype = CTNIL;
|
||||||
$$ = nodlit(v);
|
$$ = nodlit(v);
|
||||||
}
|
}
|
||||||
|
@ -1919,7 +1919,7 @@ eqargs(Type *t1, Type *t2)
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint32
|
uint32
|
||||||
typehash(Type *at, int d)
|
typehash(Type *at, int addsym, int d)
|
||||||
{
|
{
|
||||||
uint32 h;
|
uint32 h;
|
||||||
Type *t;
|
Type *t;
|
||||||
@ -1931,20 +1931,23 @@ typehash(Type *at, int d)
|
|||||||
|
|
||||||
h = at->etype*PRIME4;
|
h = at->etype*PRIME4;
|
||||||
|
|
||||||
|
if(addsym && at->sym != S)
|
||||||
|
h += stringhash(at->sym->name);
|
||||||
|
|
||||||
switch(at->etype) {
|
switch(at->etype) {
|
||||||
default:
|
default:
|
||||||
h += PRIME5 * typehash(at->type, d+1);
|
h += PRIME5 * typehash(at->type, addsym, d+1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TINTER:
|
case TINTER:
|
||||||
// botch -- should be sorted?
|
// botch -- should be sorted?
|
||||||
for(t=at->type; t!=T; t=t->down)
|
for(t=at->type; t!=T; t=t->down)
|
||||||
h += PRIME6 * typehash(t, d+1);
|
h += PRIME6 * typehash(t, addsym, d+1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TSTRUCT:
|
case TSTRUCT:
|
||||||
for(t=at->type; t!=T; t=t->down)
|
for(t=at->type; t!=T; t=t->down)
|
||||||
h += PRIME7 * typehash(t, d+1);
|
h += PRIME7 * typehash(t, addsym, d+1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TFUNC:
|
case TFUNC:
|
||||||
@ -1953,7 +1956,7 @@ typehash(Type *at, int d)
|
|||||||
if(t != T)
|
if(t != T)
|
||||||
t = t->down;
|
t = t->down;
|
||||||
for(; t!=T; t=t->down)
|
for(; t!=T; t=t->down)
|
||||||
h += PRIME7 * typehash(t, d+1);
|
h += PRIME7 * typehash(t, addsym, d+1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2756,9 +2759,9 @@ ifaceokT2I(Type *t0, Type *iface, Type **m)
|
|||||||
// so we can both be wrong together.
|
// so we can both be wrong together.
|
||||||
|
|
||||||
for(im=iface->type; im; im=im->down) {
|
for(im=iface->type; im; im=im->down) {
|
||||||
imhash = typehash(im, 0);
|
imhash = typehash(im, 0, 0);
|
||||||
tm = ifacelookdot(im->sym, t);
|
tm = ifacelookdot(im->sym, t);
|
||||||
if(tm == T || typehash(tm, 0) != imhash) {
|
if(tm == T || typehash(tm, 0, 0) != imhash) {
|
||||||
*m = im;
|
*m = im;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -2778,7 +2781,7 @@ ifaceokI2I(Type *i1, Type *i2, Type **m)
|
|||||||
|
|
||||||
for(m2=i2->type; m2; m2=m2->down) {
|
for(m2=i2->type; m2; m2=m2->down) {
|
||||||
for(m1=i1->type; m1; m1=m1->down)
|
for(m1=i1->type; m1; m1=m1->down)
|
||||||
if(m1->sym == m2->sym && typehash(m1, 0) == typehash(m2, 0))
|
if(m1->sym == m2->sym && typehash(m1, 0, 0) == typehash(m2, 0, 0))
|
||||||
goto found;
|
goto found;
|
||||||
*m = m2;
|
*m = m2;
|
||||||
return 0;
|
return 0;
|
||||||
|
345
src/cmd/gc/swt.c
345
src/cmd/gc/swt.c
@ -10,8 +10,22 @@ enum
|
|||||||
Strue,
|
Strue,
|
||||||
Sfalse,
|
Sfalse,
|
||||||
Stype,
|
Stype,
|
||||||
|
|
||||||
|
Ncase = 4, // needed to binary search
|
||||||
};
|
};
|
||||||
Node* binarysw(Node *t, Iter *save, Node *name);
|
Node* exprbsw(Node *t, Iter *save, Node *name);
|
||||||
|
void typeswitch(Node *sw);
|
||||||
|
|
||||||
|
typedef struct Case Case;
|
||||||
|
struct Case
|
||||||
|
{
|
||||||
|
Node* node; // points at case statement
|
||||||
|
uint32 hash; // hash of a type switch
|
||||||
|
uint8 uniq; // first of multiple identical hashes
|
||||||
|
uint8 diag; // suppress multiple diagnostics
|
||||||
|
Case* link; // linked list to link
|
||||||
|
};
|
||||||
|
#define C ((Case*)nil)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* walktype
|
* walktype
|
||||||
@ -263,7 +277,6 @@ exprswitch(Node *sw, int arg)
|
|||||||
Iter save;
|
Iter save;
|
||||||
Node *name, *bool, *cas;
|
Node *name, *bool, *cas;
|
||||||
Node *t, *a;
|
Node *t, *a;
|
||||||
//dump("exprswitch before", sw->nbody->left);
|
|
||||||
|
|
||||||
cas = N;
|
cas = N;
|
||||||
name = N;
|
name = N;
|
||||||
@ -280,7 +293,6 @@ exprswitch(Node *sw, int arg)
|
|||||||
loop:
|
loop:
|
||||||
if(t == N) {
|
if(t == N) {
|
||||||
sw->nbody->left = rev(cas);
|
sw->nbody->left = rev(cas);
|
||||||
//dump("exprswitch after", sw->nbody->left);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -295,7 +307,6 @@ loop:
|
|||||||
// this should be done better to prevent
|
// this should be done better to prevent
|
||||||
// multiple (unused) heap allocations per switch.
|
// multiple (unused) heap allocations per switch.
|
||||||
if(t->ninit != N && t->ninit->op == ODCL) {
|
if(t->ninit != N && t->ninit->op == ODCL) {
|
||||||
//dump("exprswitch case init", t->ninit);
|
|
||||||
cas = list(cas, t->ninit);
|
cas = list(cas, t->ninit);
|
||||||
t->ninit = N;
|
t->ninit = N;
|
||||||
}
|
}
|
||||||
@ -305,7 +316,6 @@ loop:
|
|||||||
bool = nod(OXXX, N, N);
|
bool = nod(OXXX, N, N);
|
||||||
tempname(bool, types[TBOOL]);
|
tempname(bool, types[TBOOL]);
|
||||||
}
|
}
|
||||||
//dump("oas", t);
|
|
||||||
t->left->left = nod(OLIST, t->left->left, bool);
|
t->left->left = nod(OLIST, t->left->left, bool);
|
||||||
cas = list(cas, t->left); // v,bool = rhs
|
cas = list(cas, t->left); // v,bool = rhs
|
||||||
|
|
||||||
@ -324,7 +334,7 @@ loop:
|
|||||||
switch(arg) {
|
switch(arg) {
|
||||||
default:
|
default:
|
||||||
// not bool const
|
// not bool const
|
||||||
a = binarysw(t, &save, name);
|
a = exprbsw(t, &save, name);
|
||||||
if(a != N)
|
if(a != N)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -351,96 +361,12 @@ loop:
|
|||||||
goto loop;
|
goto loop;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* convert switch of the form
|
|
||||||
* switch v := i.(type) { case t1: ..; case t2: ..; }
|
|
||||||
* into if statements
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
typeswitch(Node *sw)
|
|
||||||
{
|
|
||||||
Iter save;
|
|
||||||
Node *face, *bool, *cas;
|
|
||||||
Node *t, *a, *b;
|
|
||||||
|
|
||||||
//dump("typeswitch", sw);
|
|
||||||
|
|
||||||
walktype(sw->ntest->right, Erv);
|
|
||||||
if(!istype(sw->ntest->right->type, TINTER)) {
|
|
||||||
yyerror("type switch must be on an interface");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
walkcases(sw, sw0, Stype);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* predeclare variables for the interface var
|
|
||||||
* and the boolean var
|
|
||||||
*/
|
|
||||||
face = nod(OXXX, N, N);
|
|
||||||
tempname(face, sw->ntest->right->type);
|
|
||||||
cas = nod(OAS, face, sw->ntest->right);
|
|
||||||
|
|
||||||
bool = nod(OXXX, N, N);
|
|
||||||
tempname(bool, types[TBOOL]);
|
|
||||||
|
|
||||||
t = listfirst(&save, &sw->nbody->left);
|
|
||||||
|
|
||||||
loop:
|
|
||||||
if(t == N) {
|
|
||||||
sw->nbody->left = rev(cas);
|
|
||||||
walkstate(sw->nbody);
|
|
||||||
//dump("done", sw->nbody->left);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(t->left == N) {
|
|
||||||
cas = list(cas, t->right); // goto default
|
|
||||||
t = listnext(&save);
|
|
||||||
goto loop;
|
|
||||||
}
|
|
||||||
if(t->left->op != OTYPESW) {
|
|
||||||
t = listnext(&save);
|
|
||||||
goto loop;
|
|
||||||
}
|
|
||||||
|
|
||||||
// pull out the dcl in case this
|
|
||||||
// variable is allocated on the heap.
|
|
||||||
// this should be done better to prevent
|
|
||||||
// multiple (unused) heap allocations per switch.
|
|
||||||
// not worth doing now -- make a binary search
|
|
||||||
// on contents of signature instead.
|
|
||||||
if(t->ninit != N && t->ninit->op == ODCL) {
|
|
||||||
//dump("typeswitch case init", t->ninit);
|
|
||||||
cas = list(cas, t->ninit);
|
|
||||||
t->ninit = N;
|
|
||||||
}
|
|
||||||
|
|
||||||
a = t->left->left; // var
|
|
||||||
a = nod(OLIST, a, bool); // var,bool
|
|
||||||
|
|
||||||
b = nod(ODOTTYPE, face, N);
|
|
||||||
b->type = t->left->left->type; // interface.(type)
|
|
||||||
|
|
||||||
a = nod(OAS, a, b); // var,bool = interface.(type)
|
|
||||||
cas = list(cas, a);
|
|
||||||
|
|
||||||
a = nod(OIF, N, N);
|
|
||||||
a->ntest = bool;
|
|
||||||
a->nbody = t->right; // if bool { goto l }
|
|
||||||
cas = list(cas, a);
|
|
||||||
|
|
||||||
t = listnext(&save);
|
|
||||||
goto loop;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
walkswitch(Node *sw)
|
walkswitch(Node *sw)
|
||||||
{
|
{
|
||||||
Type *t;
|
Type *t;
|
||||||
int arg;
|
int arg;
|
||||||
|
|
||||||
//dump("walkswitch", sw);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* reorder the body into (OLIST, cases, statements)
|
* reorder the body into (OLIST, cases, statements)
|
||||||
* cases have OGOTO into statements.
|
* cases have OGOTO into statements.
|
||||||
@ -476,7 +402,6 @@ walkswitch(Node *sw)
|
|||||||
* init statement is nothing important
|
* init statement is nothing important
|
||||||
*/
|
*/
|
||||||
walktype(sw->ntest, Erv);
|
walktype(sw->ntest, Erv);
|
||||||
//print("after walkwalks\n");
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* pass 0,1,2,3
|
* pass 0,1,2,3
|
||||||
@ -492,32 +417,14 @@ walkswitch(Node *sw)
|
|||||||
return;
|
return;
|
||||||
walkcases(sw, sw3, arg);
|
walkcases(sw, sw3, arg);
|
||||||
convlit(sw->ntest, t);
|
convlit(sw->ntest, t);
|
||||||
//print("after walkcases\n");
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* convert the switch into OIF statements
|
* convert the switch into OIF statements
|
||||||
*/
|
*/
|
||||||
exprswitch(sw, arg);
|
exprswitch(sw, arg);
|
||||||
walkstate(sw->nbody);
|
walkstate(sw->nbody);
|
||||||
//print("normal done\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* binary search on cases
|
|
||||||
*/
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
Ncase = 4, // needed to binary search
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct Case Case;
|
|
||||||
struct Case
|
|
||||||
{
|
|
||||||
Node* node; // points at case statement
|
|
||||||
Case* link; // linked list to link
|
|
||||||
};
|
|
||||||
#define C ((Case*)nil)
|
|
||||||
|
|
||||||
int
|
int
|
||||||
iscaseconst(Node *t)
|
iscaseconst(Node *t)
|
||||||
{
|
{
|
||||||
@ -662,18 +569,18 @@ constsw(Case *c0, int ncase, Node *name)
|
|||||||
// find center and recur
|
// find center and recur
|
||||||
c = c0;
|
c = c0;
|
||||||
n = ncase>>1;
|
n = ncase>>1;
|
||||||
for(i=0; i<n; i++)
|
for(i=1; i<n; i++)
|
||||||
c = c->link;
|
c = c->link;
|
||||||
|
|
||||||
a = nod(OIF, N, N);
|
a = nod(OIF, N, N);
|
||||||
a->ntest = nod(OLE, name, c->node->left);
|
a->ntest = nod(OLE, name, c->node->left);
|
||||||
a->nbody = constsw(c0, n+1, name); // include center
|
a->nbody = constsw(c0, n, name); // include center
|
||||||
a->nelse = constsw(c->link, ncase-n-1, name); // exclude center
|
a->nelse = constsw(c->link, ncase-n, name); // exclude center
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
Node*
|
Node*
|
||||||
binarysw(Node *t, Iter *save, Node *name)
|
exprbsw(Node *t, Iter *save, Node *name)
|
||||||
{
|
{
|
||||||
Case *c, *c1;
|
Case *c, *c1;
|
||||||
int i, ncase;
|
int i, ncase;
|
||||||
@ -701,6 +608,216 @@ binarysw(Node *t, Iter *save, Node *name)
|
|||||||
|
|
||||||
c = csort(c, casecmp);
|
c = csort(c, casecmp);
|
||||||
a = constsw(c, ncase, name);
|
a = constsw(c, ncase, name);
|
||||||
//dump("bin", a);
|
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
hashcmp(Case *c1, Case *c2)
|
||||||
|
{
|
||||||
|
|
||||||
|
if(c1->hash > c2->hash)
|
||||||
|
return +1;
|
||||||
|
if(c1->hash < c2->hash)
|
||||||
|
return -1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
counthash(Case *c)
|
||||||
|
{
|
||||||
|
Case *c1, *c2;
|
||||||
|
Type *t1, *t2;
|
||||||
|
char buf1[NSYMB], buf2[NSYMB];
|
||||||
|
int ncase;
|
||||||
|
|
||||||
|
ncase = 0;
|
||||||
|
while(c != C) {
|
||||||
|
c->uniq = 1;
|
||||||
|
ncase++;
|
||||||
|
|
||||||
|
for(c1=c->link; c1!=C; c1=c1->link) {
|
||||||
|
if(c->hash != c1->hash)
|
||||||
|
break;
|
||||||
|
|
||||||
|
// c1 is a non-unique hash
|
||||||
|
// compare its type to all types c upto c1
|
||||||
|
for(c2=c; c2!=c1; c2=c2->link) {
|
||||||
|
if(c->diag)
|
||||||
|
continue;
|
||||||
|
t1 = c1->node->left->left->type;
|
||||||
|
t2 = c2->node->left->left->type;
|
||||||
|
if(!eqtype(t1, t2, 0))
|
||||||
|
continue;
|
||||||
|
snprint(buf1, sizeof(buf1), "%#T", t1);
|
||||||
|
snprint(buf2, sizeof(buf2), "%#T", t2);
|
||||||
|
if(strcmp(buf1, buf2) != 0)
|
||||||
|
continue;
|
||||||
|
setlineno(c1->node);
|
||||||
|
yyerror("duplicate type case: %T\n", t1);
|
||||||
|
c->diag = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c = c1;
|
||||||
|
}
|
||||||
|
return ncase;
|
||||||
|
}
|
||||||
|
|
||||||
|
Case*
|
||||||
|
nextuniq(Case *c)
|
||||||
|
{
|
||||||
|
for(c=c->link; c!=C; c=c->link)
|
||||||
|
if(c->uniq)
|
||||||
|
return c;
|
||||||
|
return C;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Node* hashname;
|
||||||
|
static Node* facename;
|
||||||
|
static Node* boolname;
|
||||||
|
static Node* gotodefault;
|
||||||
|
|
||||||
|
Node*
|
||||||
|
typebsw(Case *c0, int ncase)
|
||||||
|
{
|
||||||
|
Node *cas, *cmp;
|
||||||
|
Node *a, *b, *t;
|
||||||
|
Case *c, *c1;
|
||||||
|
int i, n;
|
||||||
|
|
||||||
|
cas = N;
|
||||||
|
|
||||||
|
if(ncase < Ncase) {
|
||||||
|
for(i=0; i<ncase; i++) {
|
||||||
|
c1 = nextuniq(c0);
|
||||||
|
cmp = N;
|
||||||
|
for(c=c0; c!=c1; c=c->link) {
|
||||||
|
t = c->node;
|
||||||
|
|
||||||
|
if(t->left->left == N) {
|
||||||
|
// case nil
|
||||||
|
Val v;
|
||||||
|
v.ctype = CTNIL;
|
||||||
|
a = nod(OIF, N, N);
|
||||||
|
a->ntest = nod(OEQ, facename, nodlit(v));
|
||||||
|
a->nbody = t->right; // if i==nil { goto l }
|
||||||
|
cmp = list(cmp, a);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
a = t->left->left; // var
|
||||||
|
a = nod(OLIST, a, boolname); // var,bool
|
||||||
|
|
||||||
|
b = nod(ODOTTYPE, facename, N);
|
||||||
|
b->type = t->left->left->type; // interface.(type)
|
||||||
|
|
||||||
|
a = nod(OAS, a, b); // var,bool = interface.(type)
|
||||||
|
cmp = list(cmp, a);
|
||||||
|
|
||||||
|
a = nod(OIF, N, N);
|
||||||
|
a->ntest = boolname;
|
||||||
|
a->nbody = t->right; // if bool { goto l }
|
||||||
|
cmp = list(cmp, a);
|
||||||
|
}
|
||||||
|
cmp = list(cmp, gotodefault);
|
||||||
|
a = nod(OIF, N, N);
|
||||||
|
a->ntest = nod(OEQ, hashname, nodintconst(c0->hash));
|
||||||
|
a->nbody = rev(cmp);
|
||||||
|
cas = list(cas, a);
|
||||||
|
c0 = c1;
|
||||||
|
}
|
||||||
|
cas = list(cas, gotodefault);
|
||||||
|
return rev(cas);
|
||||||
|
}
|
||||||
|
|
||||||
|
// find the middle and recur
|
||||||
|
c = c0;
|
||||||
|
n = ncase>>1;
|
||||||
|
for(i=1; i<n; i++)
|
||||||
|
c = nextuniq(c);
|
||||||
|
a = nod(OIF, N, N);
|
||||||
|
a->ntest = nod(OLE, hashname, nodintconst(c->hash));
|
||||||
|
a->nbody = typebsw(c0, n);
|
||||||
|
a->nelse = typebsw(nextuniq(c), ncase-n);
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* convert switch of the form
|
||||||
|
* switch v := i.(type) { case t1: ..; case t2: ..; }
|
||||||
|
* into if statements
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
typeswitch(Node *sw)
|
||||||
|
{
|
||||||
|
Iter save;
|
||||||
|
Node *cas;
|
||||||
|
Node *t, *a;
|
||||||
|
Case *c, *c1;
|
||||||
|
int ncase;
|
||||||
|
|
||||||
|
walktype(sw->ntest->right, Erv);
|
||||||
|
if(!istype(sw->ntest->right->type, TINTER)) {
|
||||||
|
yyerror("type switch must be on an interface");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
walkcases(sw, sw0, Stype);
|
||||||
|
cas = N;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* predeclare temporary variables
|
||||||
|
* and the boolean var
|
||||||
|
*/
|
||||||
|
facename = nod(OXXX, N, N);
|
||||||
|
tempname(facename, sw->ntest->right->type);
|
||||||
|
a = nod(OAS, facename, sw->ntest->right);
|
||||||
|
cas = list(cas, a);
|
||||||
|
|
||||||
|
boolname = nod(OXXX, N, N);
|
||||||
|
tempname(boolname, types[TBOOL]);
|
||||||
|
|
||||||
|
hashname = nod(OXXX, N, N);
|
||||||
|
tempname(hashname, types[TUINT32]);
|
||||||
|
|
||||||
|
a = syslook("ifacethash", 1);
|
||||||
|
argtype(a, sw->ntest->right->type);
|
||||||
|
a = nod(OCALL, a, sw->ntest->right);
|
||||||
|
a = nod(OAS, hashname, a);
|
||||||
|
cas = list(cas, a);
|
||||||
|
|
||||||
|
gotodefault = N;
|
||||||
|
|
||||||
|
c = C;
|
||||||
|
t = listfirst(&save, &sw->nbody->left);
|
||||||
|
|
||||||
|
loop:
|
||||||
|
if(t == N) {
|
||||||
|
if(gotodefault == N)
|
||||||
|
gotodefault = nod(OBREAK, N, N);
|
||||||
|
c = csort(c, hashcmp);
|
||||||
|
ncase = counthash(c);
|
||||||
|
a = typebsw(c, ncase);
|
||||||
|
sw->nbody->left = list(rev(cas), rev(a));
|
||||||
|
walkstate(sw->nbody);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(t->left == N) {
|
||||||
|
gotodefault = t->right;
|
||||||
|
t = listnext(&save);
|
||||||
|
goto loop;
|
||||||
|
}
|
||||||
|
if(t->left->op != OTYPESW) {
|
||||||
|
t = listnext(&save);
|
||||||
|
goto loop;
|
||||||
|
}
|
||||||
|
|
||||||
|
c1 = mal(sizeof(*c));
|
||||||
|
c1->link = c;
|
||||||
|
c1->node = t;
|
||||||
|
c1->hash = 0;
|
||||||
|
if(t->left->left != N)
|
||||||
|
c1->hash = typehash(t->left->left->type, 1, 0);
|
||||||
|
c = c1;
|
||||||
|
|
||||||
|
t = listnext(&save);
|
||||||
|
goto loop;
|
||||||
|
}
|
||||||
|
@ -36,6 +36,7 @@ func ifaceI2T2(sigt *byte, iface any) (ret any, ok bool);
|
|||||||
func ifaceI2I(sigi *byte, iface any) (ret any);
|
func ifaceI2I(sigi *byte, iface any) (ret any);
|
||||||
func ifaceI2I2(sigi *byte, iface any) (ret any, ok bool);
|
func ifaceI2I2(sigi *byte, iface any) (ret any, ok bool);
|
||||||
func ifaceeq(i1 any, i2 any) (ret bool);
|
func ifaceeq(i1 any, i2 any) (ret bool);
|
||||||
|
func ifacethash(i1 any) (ret uint32);
|
||||||
|
|
||||||
func newmap(keysize int, valsize int,
|
func newmap(keysize int, valsize int,
|
||||||
keyalg int, valalg int,
|
keyalg int, valalg int,
|
||||||
|
@ -532,6 +532,23 @@ sys·ifaceeq(Iface i1, Iface i2, bool ret)
|
|||||||
FLUSH(&ret);
|
FLUSH(&ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
sys·printinter(Iface i)
|
sys·printinter(Iface i)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user