Commit 2da5022b authored by Russ Cox's avatar Russ Cox

change representation of interface values.

this is not a user-visible change.

before, all interface values were

	struct Itype {
		Sigt *type;
		Sigi *inter;
		void *method[n];
	}

	struct Iface {
		void *addr;
		Itype *itype;
	}

the itype is basically a vtable, but it's unnecessary
if the static type is interface{ }.
for interface values with static type empty, the
new representation is

	struct Eface {
		void *addr;
		Sigt *type;
	}

this complicates the code somewhat, but
it reduces the number of Itypes that
have to be computed and cached,
it opens up opportunities to avoid function
calls in a few common cases,
and it will make it possible to lay out
interface{} values at compile time,
which i think i'll need for the new reflection.

R=ken
OCL=28701
CL=29121
parent 47e51527
......@@ -9,7 +9,8 @@ char *sysimport =
"func sys.printint (? int64)\n"
"func sys.printstring (? string)\n"
"func sys.printpointer (? any)\n"
"func sys.printinter (? any)\n"
"func sys.printiface (? any)\n"
"func sys.printeface (? any)\n"
"func sys.printarray (? any)\n"
"func sys.printnl ()\n"
"func sys.printsp ()\n"
......@@ -21,13 +22,21 @@ char *sysimport =
"func sys.arraystring (? []uint8) (? string)\n"
"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.ifaceI2I2 (sigi *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"
"func sys.efacethash (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.mapaccess1 (hmap map[any] any, key any) (val any)\n"
"func sys.mapaccess2 (hmap map[any] any, key any) (val any, pres bool)\n"
......
......@@ -43,6 +43,7 @@ enum
ANOEQ,
ASTRING,
AINTER,
ANILINTER,
BADWIDTH = -1000000000
};
......
......@@ -323,11 +323,11 @@ algtype(Type *t)
if(issimple[t->etype] || isptr[t->etype] || t->etype == TCHAN || t->etype == TFUNC)
a = AMEM; // just bytes (int, ptr, etc)
else
if(t->etype == TSTRING)
else if(t->etype == TSTRING)
a = ASTRING; // string
else
if(t->etype == TINTER)
else if(isnilinter(t))
a = ANILINTER; // nil interface
else if(t->etype == TINTER)
a = AINTER; // interface
else
a = ANOEQ; // just bytes, but no hash/eq
......
......@@ -762,6 +762,7 @@ typeswitch(Node *sw)
Node *a;
Case *c, *c0, *c1;
int ncase;
Type *t;
if(sw->ntest == nil)
return;
......@@ -793,8 +794,12 @@ typeswitch(Node *sw)
hashname = nod(OXXX, N, N);
tempname(hashname, types[TUINT32]);
a = syslook("ifacethash", 1);
argtype(a, sw->ntest->right->type);
t = sw->ntest->right->type;
if(isnilinter(t))
a = syslook("efacethash", 1);
else
a = syslook("ifacethash", 1);
argtype(a, t);
a = nod(OCALL, a, facename);
a = nod(OAS, hashname, a);
cas = list(cas, a);
......
......@@ -17,7 +17,8 @@ func printfloat(float64);
func printint(int64);
func printstring(string);
func printpointer(any);
func printinter(any);
func printiface(any);
func printeface(any);
func printarray(any);
func printnl();
func printsp();
......@@ -31,13 +32,21 @@ func arraystring([]byte) string;
func stringiter(string, int) int;
func stringiter2(string, int) (retk int, retv int);
func ifaceI2E(iface any) (ret any);
func ifaceE2I(sigi *byte, iface any) (ret any);
func ifaceT2E(sigt *byte, elem any) (ret any);
func ifaceE2T(sigt *byte, elem any) (ret any);
func ifaceE2I2(sigi *byte, iface any) (ret any, ok bool);
func ifaceE2T2(sigt *byte, elem any) (ret any, ok bool);
func ifaceT2I(sigi *byte, sigt *byte, elem any) (ret any);
func ifaceI2T(sigt *byte, iface any) (ret any);
func ifaceI2T2(sigt *byte, iface any) (ret any, ok bool);
func ifaceI2I(sigi *byte, iface any) (ret any);
func ifaceI2I2(sigi *byte, iface any) (ret any, ok bool);
func ifaceeq(i1 any, i2 any) (ret bool);
func efaceeq(i1 any, i2 any) (ret bool);
func ifacethash(i1 any) (ret uint32);
func efacethash(i1 any) (ret uint32);
func newmap(keysize int, valsize int,
keyalg int, valalg int,
......
......@@ -15,6 +15,14 @@ enum
I2I2,
T2I,
I2Isame,
E2T,
E2T2,
E2I,
E2I2,
I2E,
I2E2,
T2E,
E2Esame,
};
// can this code branch reach the end
......@@ -444,6 +452,7 @@ loop:
cr = listcount(r);
if(cl == cr) {
simpleas:
walktype(r, Erv);
l = ascompatee(n->op, &n->left, &n->right);
if(l != N)
......@@ -505,13 +514,25 @@ loop:
break;
et = ifaceas1(r->type, r->left->type, 1);
switch(et) {
case I2Isame:
case E2Esame:
n->right = nod(OLIST, r->left, nodbool(1));
goto simpleas;
case I2E:
n->right = nod(OLIST, n->right, nodbool(1));
goto simpleas;
case I2T:
et = I2T2;
break;
case I2Isame:
case I2I:
et = I2I2;
break;
case E2I:
et = E2I2;
break;
case E2T:
et = E2T2;
break;
default:
et = Inone;
break;
......@@ -1180,6 +1201,7 @@ void
walkconv(Node *n)
{
int et;
char *what;
Type *t;
Node *l;
......@@ -1199,9 +1221,13 @@ walkconv(Node *n)
defaultlit(l, T);
if(!isinter(l->type))
yyerror("type assertion requires interface on left, have %T", l->type);
et = ifaceas(n->type, l->type, 1);
et = ifaceas1(t, l->type, 1);
if(et == I2Isame || et == E2Esame) {
n->op = OCONV;
goto nop;
}
if(et != Inone) {
indir(n, ifaceop(n->type, l, et));
indir(n, ifaceop(t, l, et));
return;
}
goto bad;
......@@ -1212,8 +1238,9 @@ walkconv(Node *n)
if(l->type == T)
return;
// nil conversion
// no-op conversion
if(cvttype(t, l->type)) {
nop:
if(l->op != ONAME) {
indir(n, l);
n->type = t;
......@@ -1267,9 +1294,9 @@ walkconv(Node *n)
// convert from unsafe.pointer
if(isptrto(l->type, TANY)) {
if(isptr[n->type->etype])
if(isptr[t->etype])
return;
if(n->type->etype == TUINTPTR)
if(t->etype == TUINTPTR)
return;
}
......@@ -1277,8 +1304,12 @@ bad:
if(n->diag)
return;
n->diag = 1;
if(n->op == ODOTTYPE)
what = "type assertion";
else
what = "conversion";
if(l->type != T)
yyerror("invalid conversion: %T to %T", l->type, t);
yyerror("invalid %s: %T to %T", what, l->type, t);
else
if(n->left->op == OLIST)
yyerror("invalid type for composite literal: %T", t);
......@@ -2095,7 +2126,10 @@ loop:
et = l->type->etype;
if(isinter(l->type)) {
on = syslook("printinter", 1);
if(isnilinter(l->type))
on = syslook("printeface", 1);
else
on = syslook("printiface", 1);
argtype(on, l->type); // any-1
} else if(isptr[et] || et == TCHAN || et == TMAP || et == TFUNC) {
on = syslook("printpointer", 1);
......@@ -2903,19 +2937,27 @@ ifaceas1(Type *dst, Type *src, int explicit)
if(isinter(dst)) {
if(isinter(src)) {
if(isnilinter(dst)) {
if(isnilinter(src))
return E2Esame;
return I2E;
}
if(eqtype(dst, src))
return I2Isame;
if(!isnilinter(dst))
ifacecheck(dst, src, lineno, explicit);
ifacecheck(dst, src, lineno, explicit);
if(isnilinter(src))
return E2I;
return I2I;
}
if(isnilinter(dst))
return T2I;
return T2E;
ifacecheck(dst, src, lineno, explicit);
return T2I;
}
if(isinter(src)) {
ifacecheck(dst, src, lineno, explicit);
if(isnilinter(src))
return E2T;
return I2T;
}
return Inone;
......@@ -2930,7 +2972,7 @@ ifaceas(Type *dst, Type *src, int explicit)
int et;
et = ifaceas1(dst, src, explicit);
if(et == I2Isame)
if(et == I2Isame || et == E2Esame)
et = Inone;
return et;
}
......@@ -2943,6 +2985,15 @@ ifacename[] =
[I2I] = "ifaceI2I",
[I2I2] = "ifaceI2I2",
[I2Isame] = "ifaceI2Isame",
[E2T] = "ifaceE2T",
[E2T2] = "ifaceE2T2",
[E2I] = "ifaceE2I",
[E2I2] = "ifaceE2I2",
[I2E] = "ifaceI2E",
[I2E2] = "ifaceI2E2",
[T2I] = "ifaceT2I",
[T2E] = "ifaceT2E",
[E2Esame] = "ifaceE2Esame",
};
Node*
......@@ -2982,19 +3033,21 @@ ifaceop(Type *tl, Node *n, int op)
on = syslook("ifaceT2I", 1);
argtype(on, tr);
argtype(on, tl);
break;
case I2T:
case I2T2:
case I2I:
case I2I2:
case E2T:
case E2T2:
case E2I:
case E2I2:
// iface[IT]2[IT][2](sigt *byte, iface any) (ret any[, ok bool]);
a = n; // interface
r = a;
s = signame(tl); // sigi
s = signame(tl); // sigi or sigt
if(s == S)
fatal("ifaceop: signame %d", op);
a = s->oname;
......@@ -3004,7 +3057,34 @@ ifaceop(Type *tl, Node *n, int op)
on = syslook(ifacename[op], 1);
argtype(on, tr);
argtype(on, tl);
break;
case I2E:
// TODO(rsc): Should do this in back end, without a call.
// ifaceI2E(elem any) (ret any);
a = n; // interface
r = a;
on = syslook("ifaceI2E", 1);
argtype(on, tr);
argtype(on, tl);
break;
case T2E:
// TODO(rsc): Should do this in back end for pointer case, without a call.
// ifaceT2E(sigt *byte, elem any) (ret any);
a = n; // elem
r = a;
s = signame(tr); // sigt
if(s == S)
fatal("ifaceop: signame-1 T2E: %lT", tr);
a = s->oname;
a = nod(OADDR, a, N);
r = list(a, r);
on = syslook("ifaceT2E", 1);
argtype(on, tr);
argtype(on, tl);
break;
case OEQ:
......@@ -3016,7 +3096,12 @@ ifaceop(Type *tl, Node *n, int op)
a = n->left; // i1
r = list(a, r);
on = syslook("ifaceeq", 1);
if(!eqtype(n->left->type, n->right->type))
fatal("ifaceop %O %T %T", op, n->left->type, n->right->type);
if(isnilinter(n->left->type))
on = syslook("efaceeq", 1);
else
on = syslook("ifaceeq", 1);
argtype(on, n->right->type);
argtype(on, n->left->type);
......
This diff is collapsed.
......@@ -363,7 +363,7 @@ static void
interprint(uint32 s, Iface *a)
{
USED(s);
sys·printinter(*a);
sys·printiface(*a);
}
static uint32
......@@ -373,6 +373,27 @@ interequal(uint32 s, Iface *a, Iface *b)
return ifaceeq(*a, *b);
}
static uint64
nilinterhash(uint32 s, Eface *a)
{
USED(s);
return efacehash(*a);
}
static void
nilinterprint(uint32 s, Eface *a)
{
USED(s);
sys·printeface(*a);
}
static uint32
nilinterequal(uint32 s, Eface *a, Eface *b)
{
USED(s);
return efaceeq(*a, *b);
}
uint64
nohash(uint32 s, void *a)
{
......@@ -416,6 +437,7 @@ algarray[] =
[ANOEQ] { nohash, noequal, memprint, memcopy },
[ASTRING] { strhash, strequal, strprint, memcopy },
[AINTER] { interhash, interequal, interprint, memcopy },
[ANILINTER] { nilinterhash, nilinterequal, nilinterprint, memcopy },
[AFAKE] { nohash, noequal, noprint, nocopy },
};
......
......@@ -57,6 +57,8 @@ typedef struct SigTab SigTab;
typedef struct MCache MCache;
typedef struct Iface Iface;
typedef struct Itype Itype;
typedef struct Eface Eface;
typedef struct Sigt Sigt;
typedef struct Defer Defer;
/*
......@@ -118,6 +120,11 @@ struct Iface
Itype* type;
void* data;
};
struct Eface
{
Sigt* type;
void* data;
};
struct Array
{ // must not move anything
......@@ -238,6 +245,7 @@ enum
ANOEQ,
ASTRING,
AINTER,
ANILINTER,
AFAKE,
Amax
};
......@@ -323,7 +331,9 @@ void stackfree(void*);
MCache* allocmcache(void);
void mallocinit(void);
bool ifaceeq(Iface, Iface);
bool efaceeq(Eface, Eface);
uint64 ifacehash(Iface);
uint64 efacehash(Eface);
uint64 nohash(uint32, void*);
uint32 noequal(uint32, void*, void*);
void* malloc(uintptr size);
......@@ -396,7 +406,8 @@ void notewakeup(Note*);
#define sys_printfloat sys·printfloat
#define sys_printhex sys·printhex
#define sys_printint sys·printint
#define sys_printinter sys·printinter
#define sys_printiface sys·printiface
#define sys_printeface sys·printeface
#define sys_printpc sys·printpc
#define sys_printpointer sys·printpointer
#define sys_printstring sys·printstring
......@@ -420,7 +431,8 @@ void* sys_getcallerpc(void*);
void sys_printbool(bool);
void sys_printfloat(float64);
void sys_printint(int64);
void sys_printinter(Iface);
void sys_printiface(Iface);
void sys_printeface(Eface);
void sys_printstring(String);
void sys_printpc(void*);
void sys_printpointer(void*);
......
......@@ -225,7 +225,7 @@ fixedbugs/bug103.go:8: illegal types for operand: AS
int
=========== fixedbugs/bug113.go
main.I is int, not int32
interface is int, not int32
throw: interface conversion
panic PC=xxx
......
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