Commit 484ba939 authored by Russ Cox's avatar Russ Cox

update sys.reflect and sys.unreflect to accomodate

the possibility of large objects in interface values.

R=r
DELTA=171  (97 added, 22 deleted, 52 changed)
OCL=22382
CL=22382
parent 51c3ac7e
...@@ -35,8 +35,8 @@ export func ifaceI2T2(sigt *byte, iface any) (ret any, ok bool); ...@@ -35,8 +35,8 @@ export func ifaceI2T2(sigt *byte, iface any) (ret any, ok bool);
export func ifaceI2I(sigi *byte, iface any) (ret any); export func ifaceI2I(sigi *byte, iface any) (ret any);
export func ifaceI2I2(sigi *byte, iface any) (ret any, ok bool); export func ifaceI2I2(sigi *byte, iface any) (ret any, ok bool);
export func ifaceeq(i1 any, i2 any) (ret bool); export func ifaceeq(i1 any, i2 any) (ret bool);
export func reflect(i interface { }) (uint64, string); export func reflect(i interface { }) (uint64, string, bool);
export func unreflect(uint64, string) (ret interface { }); export func unreflect(uint64, string, bool) (ret interface { });
export func argc() int; export func argc() int;
export func envc() int; export func envc() int;
......
...@@ -27,8 +27,8 @@ char *sysimport = ...@@ -27,8 +27,8 @@ char *sysimport =
"export func sys.ifaceI2I (sigi *uint8, iface any) (ret any)\n" "export func sys.ifaceI2I (sigi *uint8, iface any) (ret any)\n"
"export func sys.ifaceI2I2 (sigi *uint8, iface any) (ret any, ok bool)\n" "export func sys.ifaceI2I2 (sigi *uint8, iface any) (ret any, ok bool)\n"
"export func sys.ifaceeq (i1 any, i2 any) (ret bool)\n" "export func sys.ifaceeq (i1 any, i2 any) (ret bool)\n"
"export func sys.reflect (i interface { }) (? uint64, ? string)\n" "export func sys.reflect (i interface { }) (? uint64, ? string, ? bool)\n"
"export func sys.unreflect (? uint64, ? string) (ret interface { })\n" "export func sys.unreflect (? uint64, ? string, ? bool) (ret interface { })\n"
"export func sys.argc () (? int)\n" "export func sys.argc () (? int)\n"
"export func sys.envc () (? int)\n" "export func sys.envc () (? int)\n"
"export func sys.argv (? int) (? string)\n" "export func sys.argv (? int) (? string)\n"
......
...@@ -332,3 +332,24 @@ export func TestCopyArray(t *testing.T) { ...@@ -332,3 +332,24 @@ export func TestCopyArray(t *testing.T) {
} }
} }
} }
export func TestBigUnnamedStruct(t *testing.T) {
b := struct{a,b,c,d int64}{1, 2, 3, 4};
v := NewValue(b);
b1 := v.Interface().(struct{a,b,c,d int64});
if b1.a != b.a || b1.b != b.b || b1.c != b.c || b1.d != b.d {
t.Errorf("NewValue(%v).Interface().(Big) = %v", b, b1);
}
}
type Big struct {
a, b, c, d, e int64
}
export func TestBigStruct(t *testing.T) {
b := Big{1, 2, 3, 4, 5};
v := NewValue(b);
b1 := v.Interface().(Big);
if b1.a != b.a || b1.b != b.b || b1.c != b.c || b1.d != b.d || b1.e != b.e {
t.Errorf("NewValue(%v).Interface().(Big) = %v", b, b1);
}
}
...@@ -75,6 +75,12 @@ func (c *Common) Name() string { ...@@ -75,6 +75,12 @@ func (c *Common) Name() string {
} }
func (c *Common) String() string { func (c *Common) String() string {
// If there is a name, show that instead of its expansion.
// This is important for reflection: a named type
// might have methods that the unnamed type does not.
if c.name != "" {
return c.name
}
return c.str return c.str
} }
......
...@@ -46,10 +46,16 @@ func (c *Common) Addr() Addr { ...@@ -46,10 +46,16 @@ func (c *Common) Addr() Addr {
} }
func (c *Common) Interface() interface {} { func (c *Common) Interface() interface {} {
if uintptr(c.addr) == 0 { var i interface {};
panicln("reflect: address 0 for", c.typ.String()); if c.typ.Size() > 8 { // TODO(rsc): how do we know it is 8?
i = sys.unreflect(c.addr.(uintptr).(uint64), c.typ.String(), true);
} else {
if uintptr(c.addr) == 0 {
panicln("reflect: address 0 for", c.typ.String());
}
i = sys.unreflect(uint64(uintptr(*c.addr.(*Addr))), c.typ.String(), false);
} }
return sys.unreflect(uint64(uintptr(*c.addr.(*Addr))), c.typ.String()); return i;
} }
func NewValueAddr(typ Type, addr Addr) Value func NewValueAddr(typ Type, addr Addr) Value
...@@ -783,7 +789,7 @@ var creator = map[int] Creator { ...@@ -783,7 +789,7 @@ var creator = map[int] Creator {
FuncKind : &FuncCreator, FuncKind : &FuncCreator,
} }
var typecache = make(map[string] *Type); var typecache = make(map[string] Type);
func NewValueAddr(typ Type, addr Addr) Value { func NewValueAddr(typ Type, addr Addr) Value {
c, ok := creator[typ.Kind()]; c, ok := creator[typ.Kind()];
...@@ -870,17 +876,21 @@ export func CopyArray(dst ArrayValue, src ArrayValue, n int) { ...@@ -870,17 +876,21 @@ export func CopyArray(dst ArrayValue, src ArrayValue, n int) {
export func NewValue(e interface {}) Value { export func NewValue(e interface {}) Value {
value, typestring := sys.reflect(e); value, typestring, indir := sys.reflect(e);
p, ok := typecache[typestring]; typ, ok := typecache[typestring];
if !ok { if !ok {
typ := ParseTypeString("", typestring); typ = ParseTypeString("", typestring);
p = new(Type); typecache[typestring] = typ;
*p = typ;
typecache[typestring] = p;
} }
// Content of interface is a value; need a permanent copy to take its address
// so we can modify the contents. Values contain pointers to 'values'. if indir {
// Content of interface is a pointer.
return NewValueAddr(typ, value.(uintptr).(Addr));
}
// Content of interface is a value;
// need a permanent copy to take its address.
ap := new(uint64); ap := new(uint64);
*ap = value; *ap = value;
return NewValueAddr(*p, ap.(Addr)); return NewValueAddr(typ, ap.(Addr));
} }
...@@ -38,6 +38,7 @@ struct Itype ...@@ -38,6 +38,7 @@ struct Itype
void (*fun[])(void); void (*fun[])(void);
}; };
static Iface niliface;
static Itype* hash[1009]; static Itype* hash[1009];
Sigi sigi·empty[2] = { (byte*)"interface { }" }; Sigi sigi·empty[2] = { (byte*)"interface { }" };
...@@ -102,16 +103,10 @@ printsigt(Sigt *st) ...@@ -102,16 +103,10 @@ printsigt(Sigt *st)
static void static void
printiface(Iface i) printiface(Iface i)
{ {
int32 j;
prints("("); prints("(");
sys·printpointer(i.type); sys·printpointer(i.type);
prints(","); prints(",");
for(j=0; j<nelem(i.data); j++) { sys·printpointer(i.data);
if(j > 0)
prints(".");
sys·printpointer(i.data[0]);
}
prints(")"); prints(")");
} }
...@@ -217,12 +212,12 @@ sys·ifaceT2I(Sigi *si, Sigt *st, ...) ...@@ -217,12 +212,12 @@ sys·ifaceT2I(Sigi *si, Sigt *st, ...)
alg = st->hash; alg = st->hash;
wid = st->offset; wid = st->offset;
if(wid <= sizeof ret->data) if(wid <= sizeof ret->data)
algarray[alg].copy(wid, ret->data, elem); algarray[alg].copy(wid, &ret->data, elem);
else{ else{
ret->data[0] = mal(wid); ret->data = mal(wid);
if(iface_debug) if(iface_debug)
printf("T2I mal %d %p\n", wid, ret->data[0]); printf("T2I mal %d %p\n", wid, ret->data);
algarray[alg].copy(wid, ret->data[0], elem); algarray[alg].copy(wid, ret->data, elem);
} }
if(iface_debug) { if(iface_debug) {
...@@ -273,9 +268,9 @@ sys·ifaceI2T(Sigt *st, Iface i, ...) ...@@ -273,9 +268,9 @@ sys·ifaceI2T(Sigt *st, Iface i, ...)
alg = st->hash; alg = st->hash;
wid = st->offset; wid = st->offset;
if(wid <= sizeof i.data) if(wid <= sizeof i.data)
algarray[alg].copy(wid, ret, i.data); algarray[alg].copy(wid, ret, &i.data);
else else
algarray[alg].copy(wid, ret, i.data[0]); algarray[alg].copy(wid, ret, i.data);
if(iface_debug) { if(iface_debug) {
prints("I2T ret="); prints("I2T ret=");
...@@ -314,9 +309,9 @@ sys·ifaceI2T2(Sigt *st, Iface i, ...) ...@@ -314,9 +309,9 @@ sys·ifaceI2T2(Sigt *st, Iface i, ...)
} else { } else {
*ok = true; *ok = true;
if(wid <= sizeof i.data) if(wid <= sizeof i.data)
algarray[alg].copy(wid, ret, i.data); algarray[alg].copy(wid, ret, &i.data);
else else
algarray[alg].copy(wid, ret, i.data[0]); algarray[alg].copy(wid, ret, i.data);
} }
if(iface_debug) { if(iface_debug) {
prints("I2T2 ret="); prints("I2T2 ret=");
...@@ -331,7 +326,6 @@ void ...@@ -331,7 +326,6 @@ void
sys·ifaceI2I(Sigi *si, Iface i, Iface ret) sys·ifaceI2I(Sigi *si, Iface i, Iface ret)
{ {
Itype *im; Itype *im;
int32 j;
if(iface_debug) { if(iface_debug) {
prints("I2I sigi="); prints("I2I sigi=");
...@@ -345,9 +339,7 @@ sys·ifaceI2I(Sigi *si, Iface i, Iface ret) ...@@ -345,9 +339,7 @@ sys·ifaceI2I(Sigi *si, Iface i, Iface ret)
if(im == nil) { if(im == nil) {
// If incoming interface is uninitialized (zeroed) // If incoming interface is uninitialized (zeroed)
// make the outgoing interface zeroed as well. // make the outgoing interface zeroed as well.
ret.type = nil; ret = niliface;
for(j=0; j<nelem(ret.data); j++)
ret.data[j] = nil;
} else { } else {
ret = i; ret = i;
if(im->sigi != si) if(im->sigi != si)
...@@ -368,7 +360,6 @@ void ...@@ -368,7 +360,6 @@ void
sys·ifaceI2I2(Sigi *si, Iface i, Iface ret, bool ok) sys·ifaceI2I2(Sigi *si, Iface i, Iface ret, bool ok)
{ {
Itype *im; Itype *im;
int32 j;
if(iface_debug) { if(iface_debug) {
prints("I2I2 sigi="); prints("I2I2 sigi=");
...@@ -382,9 +373,7 @@ sys·ifaceI2I2(Sigi *si, Iface i, Iface ret, bool ok) ...@@ -382,9 +373,7 @@ sys·ifaceI2I2(Sigi *si, Iface i, Iface ret, bool ok)
if(im == nil) { if(im == nil) {
// If incoming interface is uninitialized (zeroed) // If incoming interface is uninitialized (zeroed)
// make the outgoing interface zeroed as well. // make the outgoing interface zeroed as well.
ret.type = nil; ret = niliface;
for(j=0; j<nelem(ret.data); j++)
ret.data[j] = nil;
ok = 1; ok = 1;
} else { } else {
ret = i; ret = i;
...@@ -392,8 +381,7 @@ sys·ifaceI2I2(Sigi *si, Iface i, Iface ret, bool ok) ...@@ -392,8 +381,7 @@ sys·ifaceI2I2(Sigi *si, Iface i, Iface ret, bool ok)
if(im->sigi != si) { if(im->sigi != si) {
ret.type = itype(si, im->sigt, 1); ret.type = itype(si, im->sigt, 1);
if(ret.type == nil) { if(ret.type == nil) {
for(j=0; j<nelem(ret.data); j++) ret = niliface;
ret.data[j] = nil;
ok = 0; ok = 0;
} }
} }
...@@ -444,10 +432,10 @@ sys·ifaceeq(Iface i1, Iface i2, bool ret) ...@@ -444,10 +432,10 @@ sys·ifaceeq(Iface i1, Iface i2, bool ret)
goto no; goto no;
if(wid <= sizeof i1.data) { if(wid <= sizeof i1.data) {
if(!algarray[alg].equal(wid, i1.data, i2.data)) if(!algarray[alg].equal(wid, &i1.data, &i2.data))
goto no; goto no;
} else { } else {
if(!algarray[alg].equal(wid, i1.data[0], i2.data[0])) if(!algarray[alg].equal(wid, i1.data, i2.data))
goto no; goto no;
} }
...@@ -469,24 +457,61 @@ sys·printinter(Iface i) ...@@ -469,24 +457,61 @@ sys·printinter(Iface i)
} }
void void
sys·reflect(Itype *im, void *it, uint64 retit, string rettype) sys·reflect(Iface i, uint64 retit, string rettype, bool retindir)
{ {
if(im == nil) { int32 wid;
if(i.type == nil) {
retit = 0; retit = 0;
rettype = nil; rettype = nil;
retindir = false;
} else { } else {
retit = (uint64)it; retit = (uint64)i.data;
rettype = gostring(im->sigt->name); rettype = gostring(i.type->sigt->name);
wid = i.type->sigt->offset;
retindir = wid > sizeof i.data;
} }
FLUSH(&retit); FLUSH(&retit);
FLUSH(&rettype); FLUSH(&rettype);
FLUSH(&retindir);
} }
extern Sigt *gotypesigs[]; extern Sigt *gotypesigs[];
extern int32 ngotypesigs; extern int32 ngotypesigs;
// The reflection library can ask to unreflect on a type
// that has never been used, so we don't have a signature for it.
// For concreteness, suppose a program does
//
// type T struct{ x []int }
// var t T;
// v := reflect.NewValue(v);
// vv := v.Field(0);
// if s, ok := vv.Interface().(string) {
// print("first field is string");
// }
//
// vv.Interface() returns the result of sys.unreflect with
// a typestring of "[]int". If []int is not used with interfaces
// in the rest of the program, there will be no signature in gotypesigs
// for "[]int", so we have to invent one. The only requirements
// on the fake signature are:
//
// (1) any interface conversion using the signature will fail
// (2) calling sys.reflect() returns the args to unreflect
//
// (1) is ensured by the fact that we allocate a new Sigt,
// so it will necessarily be != any Sigt in gotypesigs.
// (2) is ensured by storing the type string in the signature
// and setting the width to force the correct value of the bool indir.
//
// Note that (1) is correct behavior: if the program had tested
// for .([]int) instead of .(string) above, then there would be a
// signature with type string "[]int" in gotypesigs, and unreflect
// wouldn't call fakesigt.
static Sigt* static Sigt*
fakesigt(string type) fakesigt(string type, bool indir)
{ {
// TODO(rsc): Cache these by type string. // TODO(rsc): Cache these by type string.
Sigt *sigt; Sigt *sigt;
...@@ -495,7 +520,10 @@ fakesigt(string type) ...@@ -495,7 +520,10 @@ fakesigt(string type)
sigt[0].name = mal(type->len + 1); sigt[0].name = mal(type->len + 1);
mcpy(sigt[0].name, type->str, type->len); mcpy(sigt[0].name, type->str, type->len);
sigt[0].hash = ASIMP; // alg sigt[0].hash = ASIMP; // alg
sigt[0].offset = sizeof(void*); // width if(indir)
sigt[0].offset = 2*sizeof(niliface.data); // big width
else
sigt[0].offset = 1; // small width
return sigt; return sigt;
} }
...@@ -521,27 +549,37 @@ cmpstringchars(string a, uint8 *b) ...@@ -521,27 +549,37 @@ cmpstringchars(string a, uint8 *b)
} }
static Sigt* static Sigt*
findtype(string type) findtype(string type, bool indir)
{ {
int32 i; int32 i;
for(i=0; i<ngotypesigs; i++) for(i=0; i<ngotypesigs; i++)
if(cmpstringchars(type, gotypesigs[i]->name) == 0) if(cmpstringchars(type, gotypesigs[i]->name) == 0)
return gotypesigs[i]; return gotypesigs[i];
return fakesigt(type); return fakesigt(type, indir);
} }
void void
sys·unreflect(uint64 it, string type, Itype *retim, void *retit) sys·unreflect(uint64 it, string type, bool indir, Iface ret)
{ {
if(cmpstring(type, emptystring) == 0) { Sigt *sigt;
retim = 0;
retit = 0; ret = niliface;
} else {
retim = itype(sigi·empty, findtype(type), 0); if(cmpstring(type, emptystring) == 0)
retit = (void*)it; goto out;
}
FLUSH(&retim); // if we think the type should be indirect
FLUSH(&retit); // and caller does not, play it safe, return nil.
sigt = findtype(type, indir);
if(indir != (sigt[0].offset > sizeof ret.data))
goto out;
ret.type = itype(sigi·empty, sigt, 0);
ret.data = (void*)it;
out:
FLUSH(&ret);
} }
...@@ -110,7 +110,7 @@ struct String ...@@ -110,7 +110,7 @@ struct String
struct Iface struct Iface
{ {
Itype *type; Itype *type;
void *data[1]; // could make bigger later, but must be in sync with compilers void *data;
}; };
struct Array struct Array
......
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