Commit 11209825 authored by Russ Cox's avatar Russ Cox

reflect: add ArrayOf, ChanOf, MapOf, SliceOf

In order to add these, we need to be able to find references
to such types that already exist in the binary. To do that, introduce
a new linker section holding a list of the types corresponding to
arrays, chans, maps, and slices.

To offset the storage cost of this list, and to simplify the code,
remove the interface{} header from the representation of a
runtime type. It was used in early versions of the code but was
made obsolete by the kind field: a switch on kind is more efficient
than a type switch.

In the godoc binary, removing the interface{} header cuts two
words from each of about 10,000 types. Adding back the list of pointers
to array, chan, map, and slice types reintroduces one word for
each of about 500 types. On a 64-bit machine, then, this CL *removes*
a net 156 kB of read-only data from the binary.

This CL does not include the needed support for precise garbage
collection. I have created issue 4375 to track that.

This CL also does not set the 'algorithm' - specifically the equality
and copy functions - for a new array correctly, so I have unexported
ArrayOf for now. That is also part of issue 4375.

Fixes #2339.

R=r, remyoudompheng, mirtchovski, iant
CC=golang-dev
https://golang.org/cl/6572043
parent 0eb42fa6
...@@ -852,7 +852,8 @@ EXTERN Pkg* itabpkg; // fake pkg for itab cache ...@@ -852,7 +852,8 @@ EXTERN Pkg* itabpkg; // fake pkg for itab cache
EXTERN Pkg* runtimepkg; // package runtime EXTERN Pkg* runtimepkg; // package runtime
EXTERN Pkg* racepkg; // package runtime/race EXTERN Pkg* racepkg; // package runtime/race
EXTERN Pkg* stringpkg; // fake package for C strings EXTERN Pkg* stringpkg; // fake package for C strings
EXTERN Pkg* typepkg; // fake package for runtime type info EXTERN Pkg* typepkg; // fake package for runtime type info (headers)
EXTERN Pkg* typelinkpkg; // fake package for runtime type info (data)
EXTERN Pkg* weaktypepkg; // weak references to runtime type info EXTERN Pkg* weaktypepkg; // weak references to runtime type info
EXTERN Pkg* unsafepkg; // package unsafe EXTERN Pkg* unsafepkg; // package unsafe
EXTERN Pkg* trackpkg; // fake package for field tracking EXTERN Pkg* trackpkg; // fake package for field tracking
......
...@@ -224,6 +224,10 @@ main(int argc, char *argv[]) ...@@ -224,6 +224,10 @@ main(int argc, char *argv[])
weaktypepkg = mkpkg(strlit("go.weak.type")); weaktypepkg = mkpkg(strlit("go.weak.type"));
weaktypepkg->name = "go.weak.type"; weaktypepkg->name = "go.weak.type";
weaktypepkg->prefix = "go.weak.type"; // not go%2eweak%2etype weaktypepkg->prefix = "go.weak.type"; // not go%2eweak%2etype
typelinkpkg = mkpkg(strlit("go.typelink"));
typelinkpkg->name = "go.typelink";
typelinkpkg->prefix = "go.typelink"; // not go%2etypelink
trackpkg = mkpkg(strlit("go.track")); trackpkg = mkpkg(strlit("go.track"));
trackpkg->name = "go.track"; trackpkg->name = "go.track";
......
...@@ -467,20 +467,6 @@ kinds[] = ...@@ -467,20 +467,6 @@ kinds[] =
[TUNSAFEPTR] = KindUnsafePointer, [TUNSAFEPTR] = KindUnsafePointer,
}; };
static Sym*
typestruct(Type *t)
{
// We use a weak reference to the reflect type
// to avoid requiring package reflect in every binary.
// If package reflect is available, the interface{} holding
// a runtime type will contain a *reflect.commonType.
// Otherwise it will use a nil type word but still be usable
// by package runtime (because we always use the memory
// after the interface value, not the interface value itself).
USED(t);
return pkglookup("*reflect.commonType", weaktypepkg);
}
int int
haspointers(Type *t) haspointers(Type *t)
{ {
...@@ -535,6 +521,9 @@ dcommontype(Sym *s, int ot, Type *t) ...@@ -535,6 +521,9 @@ dcommontype(Sym *s, int ot, Type *t)
Sym *sptr, *algsym; Sym *sptr, *algsym;
static Sym *algarray; static Sym *algarray;
char *p; char *p;
if(ot != 0)
fatal("dcommontype %d", ot);
sizeofAlg = 4*widthptr; sizeofAlg = 4*widthptr;
if(algarray == nil) if(algarray == nil)
...@@ -550,13 +539,6 @@ dcommontype(Sym *s, int ot, Type *t) ...@@ -550,13 +539,6 @@ dcommontype(Sym *s, int ot, Type *t)
else else
sptr = weaktypesym(ptrto(t)); sptr = weaktypesym(ptrto(t));
// empty interface pointing at this type.
// all the references that we emit are *interface{};
// they point here.
ot = rnd(ot, widthptr);
ot = dsymptr(s, ot, typestruct(t), 0);
ot = dsymptr(s, ot, s, 2*widthptr);
// ../../pkg/reflect/type.go:/^type.commonType // ../../pkg/reflect/type.go:/^type.commonType
// actual type structure // actual type structure
// type commonType struct { // type commonType struct {
...@@ -636,6 +618,27 @@ tracksym(Type *t) ...@@ -636,6 +618,27 @@ tracksym(Type *t)
return s; return s;
} }
Sym*
typelinksym(Type *t)
{
char *p;
Sym *s;
// %-uT is what the generated Type's string field says.
// It uses (ambiguous) package names instead of import paths.
// %-T is the complete, unambiguous type name.
// We want the types to end up sorted by string field,
// so use that first in the name, and then add :%-T to
// disambiguate. The names are a little long but they are
// discarded by the linker and do not end up in the symbol
// table of the final binary.
p = smprint("%-uT/%-T", t, t);
s = pkglookup(p, typelinkpkg);
//print("typelinksym: %s -> %+S\n", p, s);
free(p);
return s;
}
Sym* Sym*
typesymprefix(char *prefix, Type *t) typesymprefix(char *prefix, Type *t)
{ {
...@@ -697,7 +700,7 @@ static Sym* ...@@ -697,7 +700,7 @@ static Sym*
dtypesym(Type *t) dtypesym(Type *t)
{ {
int ot, xt, n, isddd, dupok; int ot, xt, n, isddd, dupok;
Sym *s, *s1, *s2; Sym *s, *s1, *s2, *slink;
Sig *a, *m; Sig *a, *m;
Type *t1, *tbase, *t2; Type *t1, *tbase, *t2;
...@@ -893,6 +896,23 @@ ok: ...@@ -893,6 +896,23 @@ ok:
} }
ot = dextratype(s, ot, t, xt); ot = dextratype(s, ot, t, xt);
ggloblsym(s, ot, dupok, 1); ggloblsym(s, ot, dupok, 1);
// generate typelink.foo pointing at s = type.foo.
// The linker will leave a table of all the typelinks for
// types in the binary, so reflect can find them.
// We only need the link for unnamed composites that
// we want be able to find.
if(t->sym == S) {
switch(t->etype) {
case TARRAY:
case TCHAN:
case TMAP:
slink = typelinksym(t);
dsymptr(slink, 0, s, 0);
ggloblsym(slink, widthptr, dupok, 1);
}
}
return s; return s;
} }
......
...@@ -1079,7 +1079,7 @@ dodata(void) ...@@ -1079,7 +1079,7 @@ dodata(void)
sect->vaddr = 0; sect->vaddr = 0;
datsize = 0; datsize = 0;
s = datap; s = datap;
for(; s != nil && s->type < SGCDATA; s = s->next) { for(; s != nil && s->type < STYPELINK; s = s->next) {
if(s->align != 0) if(s->align != 0)
datsize = rnd(datsize, s->align); datsize = rnd(datsize, s->align);
s->type = SRODATA; s->type = SRODATA;
...@@ -1089,6 +1089,17 @@ dodata(void) ...@@ -1089,6 +1089,17 @@ dodata(void)
sect->len = datsize - sect->vaddr; sect->len = datsize - sect->vaddr;
datsize = rnd(datsize, PtrSize); datsize = rnd(datsize, PtrSize);
/* type */
sect = addsection(&segtext, ".typelink", 04);
sect->vaddr = datsize;
for(; s != nil && s->type == STYPELINK; s = s->next) {
s->type = SRODATA;
s->value = datsize;
datsize += s->size;
}
sect->len = datsize - sect->vaddr;
datsize = rnd(datsize, PtrSize);
/* gcdata */ /* gcdata */
sect = addsection(&segtext, ".gcdata", 04); sect = addsection(&segtext, ".gcdata", 04);
sect->vaddr = datsize; sect->vaddr = datsize;
...@@ -1194,7 +1205,7 @@ void ...@@ -1194,7 +1205,7 @@ void
address(void) address(void)
{ {
Section *s, *text, *data, *rodata, *symtab, *pclntab, *noptr, *bss, *noptrbss; Section *s, *text, *data, *rodata, *symtab, *pclntab, *noptr, *bss, *noptrbss;
Section *gcdata, *gcbss; Section *gcdata, *gcbss, *typelink;
Sym *sym, *sub; Sym *sym, *sub;
uvlong va; uvlong va;
...@@ -1241,7 +1252,8 @@ address(void) ...@@ -1241,7 +1252,8 @@ address(void)
text = segtext.sect; text = segtext.sect;
rodata = text->next; rodata = text->next;
gcdata = rodata->next; typelink = rodata->next;
gcdata = typelink->next;
gcbss = gcdata->next; gcbss = gcdata->next;
symtab = gcbss->next; symtab = gcbss->next;
pclntab = symtab->next; pclntab = symtab->next;
...@@ -1260,6 +1272,8 @@ address(void) ...@@ -1260,6 +1272,8 @@ address(void)
xdefine("etext", STEXT, text->vaddr + text->len); xdefine("etext", STEXT, text->vaddr + text->len);
xdefine("rodata", SRODATA, rodata->vaddr); xdefine("rodata", SRODATA, rodata->vaddr);
xdefine("erodata", SRODATA, rodata->vaddr + rodata->len); xdefine("erodata", SRODATA, rodata->vaddr + rodata->len);
xdefine("typelink", SRODATA, typelink->vaddr);
xdefine("etypelink", SRODATA, typelink->vaddr + typelink->len);
xdefine("gcdata", SGCDATA, gcdata->vaddr); xdefine("gcdata", SGCDATA, gcdata->vaddr);
xdefine("egcdata", SGCDATA, gcdata->vaddr + gcdata->len); xdefine("egcdata", SGCDATA, gcdata->vaddr + gcdata->len);
xdefine("gcbss", SGCBSS, gcbss->vaddr); xdefine("gcbss", SGCBSS, gcbss->vaddr);
......
...@@ -71,21 +71,21 @@ decode_inuxi(uchar* p, int sz) ...@@ -71,21 +71,21 @@ decode_inuxi(uchar* p, int sz)
uint8 uint8
decodetype_kind(Sym *s) decodetype_kind(Sym *s)
{ {
return s->p[3*PtrSize + 7] & ~KindNoPointers; // 0x13 / 0x1f return s->p[1*PtrSize + 7] & ~KindNoPointers; // 0x13 / 0x1f
} }
// Type.commonType.size // Type.commonType.size
vlong vlong
decodetype_size(Sym *s) decodetype_size(Sym *s)
{ {
return decode_inuxi(s->p + 2*PtrSize, PtrSize); // 0x8 / 0x10 return decode_inuxi(s->p, PtrSize); // 0x8 / 0x10
} }
// Type.commonType.gc // Type.commonType.gc
Sym* Sym*
decodetype_gc(Sym *s) decodetype_gc(Sym *s)
{ {
return decode_reloc_sym(s, 3*PtrSize + 8 + 1*PtrSize); return decode_reloc_sym(s, 1*PtrSize + 8 + 1*PtrSize);
} }
// Type.ArrayType.elem and Type.SliceType.Elem // Type.ArrayType.elem and Type.SliceType.Elem
......
...@@ -2082,7 +2082,7 @@ dwarfemitdebugsections(void) ...@@ -2082,7 +2082,7 @@ dwarfemitdebugsections(void)
newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, PtrSize, 0); newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, PtrSize, 0);
// Needed by the prettyprinter code for interface inspection. // Needed by the prettyprinter code for interface inspection.
defgotype(lookup_or_diag("type.runtime.commonType")); defgotype(lookup_or_diag("type.runtime.rtype"));
defgotype(lookup_or_diag("type.runtime.interfaceType")); defgotype(lookup_or_diag("type.runtime.interfaceType"));
defgotype(lookup_or_diag("type.runtime.itab")); defgotype(lookup_or_diag("type.runtime.itab"));
......
...@@ -740,6 +740,12 @@ deadcode(void) ...@@ -740,6 +740,12 @@ deadcode(void)
markflood(); markflood();
// keep each beginning with 'typelink.' if the symbol it points at is being kept.
for(s = allsym; s != S; s = s->allsym) {
if(strncmp(s->name, "go.typelink.", 12) == 0)
s->reachable = s->nr==1 && s->r[0].sym->reachable;
}
// remove dead text but keep file information (z symbols). // remove dead text but keep file information (z symbols).
last = nil; last = nil;
z = nil; z = nil;
...@@ -771,7 +777,7 @@ deadcode(void) ...@@ -771,7 +777,7 @@ deadcode(void)
s->reachable = 1; s->reachable = 1;
s->hide = 1; s->hide = 1;
} }
// record field tracking references // record field tracking references
fmtstrinit(&fmt); fmtstrinit(&fmt);
for(s = allsym; s != S; s = s->allsym) { for(s = allsym; s != S; s = s->allsym) {
......
...@@ -39,6 +39,7 @@ enum ...@@ -39,6 +39,7 @@ enum
SSTRING, SSTRING,
SGOSTRING, SGOSTRING,
SRODATA, SRODATA,
STYPELINK,
SGCDATA, SGCDATA,
SGCBSS, SGCBSS,
SSYMTAB, SSYMTAB,
......
...@@ -337,6 +337,8 @@ symtab(void) ...@@ -337,6 +337,8 @@ symtab(void)
// data.c:/^address will provide the actual values. // data.c:/^address will provide the actual values.
xdefine("text", STEXT, 0); xdefine("text", STEXT, 0);
xdefine("etext", STEXT, 0); xdefine("etext", STEXT, 0);
xdefine("typelink", SRODATA, 0);
xdefine("etypelink", SRODATA, 0);
xdefine("rodata", SRODATA, 0); xdefine("rodata", SRODATA, 0);
xdefine("erodata", SRODATA, 0); xdefine("erodata", SRODATA, 0);
xdefine("gcdata", SGCDATA, 0); xdefine("gcdata", SGCDATA, 0);
...@@ -382,6 +384,10 @@ symtab(void) ...@@ -382,6 +384,10 @@ symtab(void)
s->type = STYPE; s->type = STYPE;
s->hide = 1; s->hide = 1;
} }
if(strncmp(s->name, "go.typelink.", 12) == 0) {
s->type = STYPELINK;
s->hide = 1;
}
if(strncmp(s->name, "go.string.", 10) == 0) { if(strncmp(s->name, "go.string.", 10) == 0) {
s->type = SGOSTRING; s->type = SGOSTRING;
s->hide = 1; s->hide = 1;
......
...@@ -2703,6 +2703,88 @@ func TestOverflow(t *testing.T) { ...@@ -2703,6 +2703,88 @@ func TestOverflow(t *testing.T) {
} }
} }
func checkSameType(t *testing.T, x, y interface{}) {
if TypeOf(x) != TypeOf(y) {
t.Errorf("did not find preexisting type for %s (vs %s)", TypeOf(x), TypeOf(y))
}
}
func TestArrayOf(t *testing.T) {
// check construction and use of type not in binary
type T int
at := ArrayOf(10, TypeOf(T(1)))
v := New(at).Elem()
for i := 0; i < v.Len(); i++ {
v.Index(i).Set(ValueOf(T(i)))
}
s := fmt.Sprint(v.Interface())
want := "[0 1 2 3 4 5 6 7 8 9]"
if s != want {
t.Errorf("constructed array = %s, want %s", s, want)
}
// check that type already in binary is found
checkSameType(t, Zero(ArrayOf(5, TypeOf(T(1)))).Interface(), [5]T{})
}
func TestSliceOf(t *testing.T) {
// check construction and use of type not in binary
type T int
st := SliceOf(TypeOf(T(1)))
v := MakeSlice(st, 10, 10)
for i := 0; i < v.Len(); i++ {
v.Index(i).Set(ValueOf(T(i)))
}
s := fmt.Sprint(v.Interface())
want := "[0 1 2 3 4 5 6 7 8 9]"
if s != want {
t.Errorf("constructed slice = %s, want %s", s, want)
}
// check that type already in binary is found
type T1 int
checkSameType(t, Zero(SliceOf(TypeOf(T1(1)))).Interface(), []T1{})
}
func TestChanOf(t *testing.T) {
// check construction and use of type not in binary
type T string
ct := ChanOf(BothDir, TypeOf(T("")))
v := MakeChan(ct, 2)
v.Send(ValueOf(T("hello")))
v.Send(ValueOf(T("world")))
sv1, _ := v.Recv()
sv2, _ := v.Recv()
s1 := sv1.String()
s2 := sv2.String()
if s1 != "hello" || s2 != "world" {
t.Errorf("constructed chan: have %q, %q, want %q, %q", s1, s2, "hello", "world")
}
// check that type already in binary is found
type T1 int
checkSameType(t, Zero(ChanOf(BothDir, TypeOf(T1(1)))).Interface(), (chan T1)(nil))
}
func TestMapOf(t *testing.T) {
// check construction and use of type not in binary
type K string
type V float64
v := MakeMap(MapOf(TypeOf(K("")), TypeOf(V(0))))
v.SetMapIndex(ValueOf(K("a")), ValueOf(V(1)))
s := fmt.Sprint(v.Interface())
want := "map[a:1]"
if s != want {
t.Errorf("constructed map = %s, want %s", s, want)
}
// check that type already in binary is found
checkSameType(t, Zero(MapOf(TypeOf(V(0)), TypeOf(K("")))).Interface(), map[V]K(nil))
}
type B1 struct { type B1 struct {
X int X int
Y int Y int
......
...@@ -14,3 +14,5 @@ func MakeRO(v Value) Value { ...@@ -14,3 +14,5 @@ func MakeRO(v Value) Value {
func IsRO(v Value) bool { func IsRO(v Value) bool {
return v.flag&flagRO != 0 return v.flag&flagRO != 0
} }
var ArrayOf = arrayOf
...@@ -17,7 +17,7 @@ type makeFuncImpl struct { ...@@ -17,7 +17,7 @@ type makeFuncImpl struct {
// References visible to the garbage collector. // References visible to the garbage collector.
// The code array below contains the same references // The code array below contains the same references
// embedded in the machine code. // embedded in the machine code.
typ *commonType typ *rtype
fn func([]Value) []Value fn func([]Value) []Value
// code is the actual machine code invoked for the closure. // code is the actual machine code invoked for the closure.
......
...@@ -184,8 +184,7 @@ type Type interface { ...@@ -184,8 +184,7 @@ type Type interface {
// It panics if i is not in the range [0, NumOut()). // It panics if i is not in the range [0, NumOut()).
Out(i int) Type Out(i int) Type
runtimeType() *runtimeType common() *rtype
common() *commonType
uncommon() *uncommonType uncommon() *uncommonType
} }
...@@ -229,37 +228,30 @@ const ( ...@@ -229,37 +228,30 @@ const (
UnsafePointer UnsafePointer
) )
// The compiler can only construct empty interface values at // rtype is the common implementation of most values.
// compile time; non-empty interface values get created
// during initialization. Type is an empty interface
// so that the compiler can lay out references as data.
// The underlying type is *reflect.ArrayType and so on.
type runtimeType interface{}
// commonType is the common implementation of most values.
// It is embedded in other, public struct types, but always // It is embedded in other, public struct types, but always
// with a unique tag like `reflect:"array"` or `reflect:"ptr"` // with a unique tag like `reflect:"array"` or `reflect:"ptr"`
// so that code cannot convert from, say, *arrayType to *ptrType. // so that code cannot convert from, say, *arrayType to *ptrType.
type commonType struct { type rtype struct {
size uintptr // size in bytes size uintptr // size in bytes
hash uint32 // hash of type; avoids computation in hash tables hash uint32 // hash of type; avoids computation in hash tables
_ uint8 // unused/padding _ uint8 // unused/padding
align uint8 // alignment of variable with this type align uint8 // alignment of variable with this type
fieldAlign uint8 // alignment of struct field with this type fieldAlign uint8 // alignment of struct field with this type
kind uint8 // enumeration for C kind uint8 // enumeration for C
alg *uintptr // algorithm table (../runtime/runtime.h:/Alg) alg *uintptr // algorithm table (../runtime/runtime.h:/Alg)
gc uintptr // garbage collection data gc uintptr // garbage collection data
string *string // string form; unnecessary but undeniably useful string *string // string form; unnecessary but undeniably useful
*uncommonType // (relatively) uncommon fields *uncommonType // (relatively) uncommon fields
ptrToThis *runtimeType // pointer to this type, if used in binary or has methods ptrToThis *rtype // type for pointer to this type, if used in binary or has methods
} }
// Method on non-interface type // Method on non-interface type
type method struct { type method struct {
name *string // name of method name *string // name of method
pkgPath *string // nil for exported Names; otherwise import path pkgPath *string // nil for exported Names; otherwise import path
mtyp *runtimeType // method type (without receiver) mtyp *rtype // method type (without receiver)
typ *runtimeType // .(*FuncType) underneath (with receiver) typ *rtype // .(*FuncType) underneath (with receiver)
ifn unsafe.Pointer // fn used in interface call (one-word receiver) ifn unsafe.Pointer // fn used in interface call (one-word receiver)
tfn unsafe.Pointer // fn used for normal method call tfn unsafe.Pointer // fn used for normal method call
} }
...@@ -285,72 +277,72 @@ const ( ...@@ -285,72 +277,72 @@ const (
// arrayType represents a fixed array type. // arrayType represents a fixed array type.
type arrayType struct { type arrayType struct {
commonType `reflect:"array"` rtype `reflect:"array"`
elem *runtimeType // array element type elem *rtype // array element type
slice *runtimeType // slice type slice *rtype // slice type
len uintptr len uintptr
} }
// chanType represents a channel type. // chanType represents a channel type.
type chanType struct { type chanType struct {
commonType `reflect:"chan"` rtype `reflect:"chan"`
elem *runtimeType // channel element type elem *rtype // channel element type
dir uintptr // channel direction (ChanDir) dir uintptr // channel direction (ChanDir)
} }
// funcType represents a function type. // funcType represents a function type.
type funcType struct { type funcType struct {
commonType `reflect:"func"` rtype `reflect:"func"`
dotdotdot bool // last input parameter is ... dotdotdot bool // last input parameter is ...
in []*runtimeType // input parameter types in []*rtype // input parameter types
out []*runtimeType // output parameter types out []*rtype // output parameter types
} }
// imethod represents a method on an interface type // imethod represents a method on an interface type
type imethod struct { type imethod struct {
name *string // name of method name *string // name of method
pkgPath *string // nil for exported Names; otherwise import path pkgPath *string // nil for exported Names; otherwise import path
typ *runtimeType // .(*FuncType) underneath typ *rtype // .(*FuncType) underneath
} }
// interfaceType represents an interface type. // interfaceType represents an interface type.
type interfaceType struct { type interfaceType struct {
commonType `reflect:"interface"` rtype `reflect:"interface"`
methods []imethod // sorted by hash methods []imethod // sorted by hash
} }
// mapType represents a map type. // mapType represents a map type.
type mapType struct { type mapType struct {
commonType `reflect:"map"` rtype `reflect:"map"`
key *runtimeType // map key type key *rtype // map key type
elem *runtimeType // map element (value) type elem *rtype // map element (value) type
} }
// ptrType represents a pointer type. // ptrType represents a pointer type.
type ptrType struct { type ptrType struct {
commonType `reflect:"ptr"` rtype `reflect:"ptr"`
elem *runtimeType // pointer element (pointed at) type elem *rtype // pointer element (pointed at) type
} }
// sliceType represents a slice type. // sliceType represents a slice type.
type sliceType struct { type sliceType struct {
commonType `reflect:"slice"` rtype `reflect:"slice"`
elem *runtimeType // slice element type elem *rtype // slice element type
} }
// Struct field // Struct field
type structField struct { type structField struct {
name *string // nil for embedded fields name *string // nil for embedded fields
pkgPath *string // nil for exported Names; otherwise import path pkgPath *string // nil for exported Names; otherwise import path
typ *runtimeType // type of field typ *rtype // type of field
tag *string // nil if no tag tag *string // nil if no tag
offset uintptr // byte offset of field within struct offset uintptr // byte offset of field within struct
} }
// structType represents a struct type. // structType represents a struct type.
type structType struct { type structType struct {
commonType `reflect:"struct"` rtype `reflect:"struct"`
fields []structField // sorted by offset fields []structField // sorted by offset
} }
/* /*
...@@ -433,18 +425,11 @@ func (t *uncommonType) Name() string { ...@@ -433,18 +425,11 @@ func (t *uncommonType) Name() string {
return *t.name return *t.name
} }
func (t *commonType) toType() Type { func (t *rtype) String() string { return *t.string }
if t == nil {
return nil
}
return t
}
func (t *commonType) String() string { return *t.string } func (t *rtype) Size() uintptr { return t.size }
func (t *commonType) Size() uintptr { return t.size } func (t *rtype) Bits() int {
func (t *commonType) Bits() int {
if t == nil { if t == nil {
panic("reflect: Bits of nil Type") panic("reflect: Bits of nil Type")
} }
...@@ -455,13 +440,13 @@ func (t *commonType) Bits() int { ...@@ -455,13 +440,13 @@ func (t *commonType) Bits() int {
return int(t.size) * 8 return int(t.size) * 8
} }
func (t *commonType) Align() int { return int(t.align) } func (t *rtype) Align() int { return int(t.align) }
func (t *commonType) FieldAlign() int { return int(t.fieldAlign) } func (t *rtype) FieldAlign() int { return int(t.fieldAlign) }
func (t *commonType) Kind() Kind { return Kind(t.kind & kindMask) } func (t *rtype) Kind() Kind { return Kind(t.kind & kindMask) }
func (t *commonType) common() *commonType { return t } func (t *rtype) common() *rtype { return t }
func (t *uncommonType) Method(i int) (m Method) { func (t *uncommonType) Method(i int) (m Method) {
if t == nil || i < 0 || i >= len(t.methods) { if t == nil || i < 0 || i >= len(t.methods) {
...@@ -476,7 +461,7 @@ func (t *uncommonType) Method(i int) (m Method) { ...@@ -476,7 +461,7 @@ func (t *uncommonType) Method(i int) (m Method) {
m.PkgPath = *p.pkgPath m.PkgPath = *p.pkgPath
fl |= flagRO fl |= flagRO
} }
mt := toCommonType(p.typ) mt := p.typ
m.Type = mt m.Type = mt
fn := p.tfn fn := p.tfn
m.Func = Value{mt, fn, fl} m.Func = Value{mt, fn, fl}
...@@ -507,8 +492,8 @@ func (t *uncommonType) MethodByName(name string) (m Method, ok bool) { ...@@ -507,8 +492,8 @@ func (t *uncommonType) MethodByName(name string) (m Method, ok bool) {
// TODO(rsc): 6g supplies these, but they are not // TODO(rsc): 6g supplies these, but they are not
// as efficient as they could be: they have commonType // as efficient as they could be: they have commonType
// as the receiver instead of *commonType. // as the receiver instead of *rtype.
func (t *commonType) NumMethod() int { func (t *rtype) NumMethod() int {
if t.Kind() == Interface { if t.Kind() == Interface {
tt := (*interfaceType)(unsafe.Pointer(t)) tt := (*interfaceType)(unsafe.Pointer(t))
return tt.NumMethod() return tt.NumMethod()
...@@ -516,7 +501,7 @@ func (t *commonType) NumMethod() int { ...@@ -516,7 +501,7 @@ func (t *commonType) NumMethod() int {
return t.uncommonType.NumMethod() return t.uncommonType.NumMethod()
} }
func (t *commonType) Method(i int) (m Method) { func (t *rtype) Method(i int) (m Method) {
if t.Kind() == Interface { if t.Kind() == Interface {
tt := (*interfaceType)(unsafe.Pointer(t)) tt := (*interfaceType)(unsafe.Pointer(t))
return tt.Method(i) return tt.Method(i)
...@@ -524,7 +509,7 @@ func (t *commonType) Method(i int) (m Method) { ...@@ -524,7 +509,7 @@ func (t *commonType) Method(i int) (m Method) {
return t.uncommonType.Method(i) return t.uncommonType.Method(i)
} }
func (t *commonType) MethodByName(name string) (m Method, ok bool) { func (t *rtype) MethodByName(name string) (m Method, ok bool) {
if t.Kind() == Interface { if t.Kind() == Interface {
tt := (*interfaceType)(unsafe.Pointer(t)) tt := (*interfaceType)(unsafe.Pointer(t))
return tt.MethodByName(name) return tt.MethodByName(name)
...@@ -532,15 +517,15 @@ func (t *commonType) MethodByName(name string) (m Method, ok bool) { ...@@ -532,15 +517,15 @@ func (t *commonType) MethodByName(name string) (m Method, ok bool) {
return t.uncommonType.MethodByName(name) return t.uncommonType.MethodByName(name)
} }
func (t *commonType) PkgPath() string { func (t *rtype) PkgPath() string {
return t.uncommonType.PkgPath() return t.uncommonType.PkgPath()
} }
func (t *commonType) Name() string { func (t *rtype) Name() string {
return t.uncommonType.Name() return t.uncommonType.Name()
} }
func (t *commonType) ChanDir() ChanDir { func (t *rtype) ChanDir() ChanDir {
if t.Kind() != Chan { if t.Kind() != Chan {
panic("reflect: ChanDir of non-chan type") panic("reflect: ChanDir of non-chan type")
} }
...@@ -548,7 +533,7 @@ func (t *commonType) ChanDir() ChanDir { ...@@ -548,7 +533,7 @@ func (t *commonType) ChanDir() ChanDir {
return ChanDir(tt.dir) return ChanDir(tt.dir)
} }
func (t *commonType) IsVariadic() bool { func (t *rtype) IsVariadic() bool {
if t.Kind() != Func { if t.Kind() != Func {
panic("reflect: IsVariadic of non-func type") panic("reflect: IsVariadic of non-func type")
} }
...@@ -556,7 +541,7 @@ func (t *commonType) IsVariadic() bool { ...@@ -556,7 +541,7 @@ func (t *commonType) IsVariadic() bool {
return tt.dotdotdot return tt.dotdotdot
} }
func (t *commonType) Elem() Type { func (t *rtype) Elem() Type {
switch t.Kind() { switch t.Kind() {
case Array: case Array:
tt := (*arrayType)(unsafe.Pointer(t)) tt := (*arrayType)(unsafe.Pointer(t))
...@@ -577,7 +562,7 @@ func (t *commonType) Elem() Type { ...@@ -577,7 +562,7 @@ func (t *commonType) Elem() Type {
panic("reflect: Elem of invalid type") panic("reflect: Elem of invalid type")
} }
func (t *commonType) Field(i int) StructField { func (t *rtype) Field(i int) StructField {
if t.Kind() != Struct { if t.Kind() != Struct {
panic("reflect: Field of non-struct type") panic("reflect: Field of non-struct type")
} }
...@@ -585,7 +570,7 @@ func (t *commonType) Field(i int) StructField { ...@@ -585,7 +570,7 @@ func (t *commonType) Field(i int) StructField {
return tt.Field(i) return tt.Field(i)
} }
func (t *commonType) FieldByIndex(index []int) StructField { func (t *rtype) FieldByIndex(index []int) StructField {
if t.Kind() != Struct { if t.Kind() != Struct {
panic("reflect: FieldByIndex of non-struct type") panic("reflect: FieldByIndex of non-struct type")
} }
...@@ -593,7 +578,7 @@ func (t *commonType) FieldByIndex(index []int) StructField { ...@@ -593,7 +578,7 @@ func (t *commonType) FieldByIndex(index []int) StructField {
return tt.FieldByIndex(index) return tt.FieldByIndex(index)
} }
func (t *commonType) FieldByName(name string) (StructField, bool) { func (t *rtype) FieldByName(name string) (StructField, bool) {
if t.Kind() != Struct { if t.Kind() != Struct {
panic("reflect: FieldByName of non-struct type") panic("reflect: FieldByName of non-struct type")
} }
...@@ -601,7 +586,7 @@ func (t *commonType) FieldByName(name string) (StructField, bool) { ...@@ -601,7 +586,7 @@ func (t *commonType) FieldByName(name string) (StructField, bool) {
return tt.FieldByName(name) return tt.FieldByName(name)
} }
func (t *commonType) FieldByNameFunc(match func(string) bool) (StructField, bool) { func (t *rtype) FieldByNameFunc(match func(string) bool) (StructField, bool) {
if t.Kind() != Struct { if t.Kind() != Struct {
panic("reflect: FieldByNameFunc of non-struct type") panic("reflect: FieldByNameFunc of non-struct type")
} }
...@@ -609,7 +594,7 @@ func (t *commonType) FieldByNameFunc(match func(string) bool) (StructField, bool ...@@ -609,7 +594,7 @@ func (t *commonType) FieldByNameFunc(match func(string) bool) (StructField, bool
return tt.FieldByNameFunc(match) return tt.FieldByNameFunc(match)
} }
func (t *commonType) In(i int) Type { func (t *rtype) In(i int) Type {
if t.Kind() != Func { if t.Kind() != Func {
panic("reflect: In of non-func type") panic("reflect: In of non-func type")
} }
...@@ -617,7 +602,7 @@ func (t *commonType) In(i int) Type { ...@@ -617,7 +602,7 @@ func (t *commonType) In(i int) Type {
return toType(tt.in[i]) return toType(tt.in[i])
} }
func (t *commonType) Key() Type { func (t *rtype) Key() Type {
if t.Kind() != Map { if t.Kind() != Map {
panic("reflect: Key of non-map type") panic("reflect: Key of non-map type")
} }
...@@ -625,7 +610,7 @@ func (t *commonType) Key() Type { ...@@ -625,7 +610,7 @@ func (t *commonType) Key() Type {
return toType(tt.key) return toType(tt.key)
} }
func (t *commonType) Len() int { func (t *rtype) Len() int {
if t.Kind() != Array { if t.Kind() != Array {
panic("reflect: Len of non-array type") panic("reflect: Len of non-array type")
} }
...@@ -633,7 +618,7 @@ func (t *commonType) Len() int { ...@@ -633,7 +618,7 @@ func (t *commonType) Len() int {
return int(tt.len) return int(tt.len)
} }
func (t *commonType) NumField() int { func (t *rtype) NumField() int {
if t.Kind() != Struct { if t.Kind() != Struct {
panic("reflect: NumField of non-struct type") panic("reflect: NumField of non-struct type")
} }
...@@ -641,7 +626,7 @@ func (t *commonType) NumField() int { ...@@ -641,7 +626,7 @@ func (t *commonType) NumField() int {
return len(tt.fields) return len(tt.fields)
} }
func (t *commonType) NumIn() int { func (t *rtype) NumIn() int {
if t.Kind() != Func { if t.Kind() != Func {
panic("reflect: NumIn of non-func type") panic("reflect: NumIn of non-func type")
} }
...@@ -649,7 +634,7 @@ func (t *commonType) NumIn() int { ...@@ -649,7 +634,7 @@ func (t *commonType) NumIn() int {
return len(tt.in) return len(tt.in)
} }
func (t *commonType) NumOut() int { func (t *rtype) NumOut() int {
if t.Kind() != Func { if t.Kind() != Func {
panic("reflect: NumOut of non-func type") panic("reflect: NumOut of non-func type")
} }
...@@ -657,7 +642,7 @@ func (t *commonType) NumOut() int { ...@@ -657,7 +642,7 @@ func (t *commonType) NumOut() int {
return len(tt.out) return len(tt.out)
} }
func (t *commonType) Out(i int) Type { func (t *rtype) Out(i int) Type {
if t.Kind() != Func { if t.Kind() != Func {
panic("reflect: Out of non-func type") panic("reflect: Out of non-func type")
} }
...@@ -827,7 +812,7 @@ func (t *structType) Field(i int) (f StructField) { ...@@ -827,7 +812,7 @@ func (t *structType) Field(i int) (f StructField) {
// FieldByIndex returns the nested field corresponding to index. // FieldByIndex returns the nested field corresponding to index.
func (t *structType) FieldByIndex(index []int) (f StructField) { func (t *structType) FieldByIndex(index []int) (f StructField) {
f.Type = Type(t.toType()) f.Type = toType(&t.rtype)
for i, x := range index { for i, x := range index {
if i > 0 { if i > 0 {
ft := f.Type ft := f.Type
...@@ -898,13 +883,13 @@ func (t *structType) FieldByNameFunc(match func(string) bool) (result StructFiel ...@@ -898,13 +883,13 @@ func (t *structType) FieldByNameFunc(match func(string) bool) (result StructFiel
f := &t.fields[i] f := &t.fields[i]
// Find name and type for field f. // Find name and type for field f.
var fname string var fname string
var ntyp *commonType var ntyp *rtype
if f.name != nil { if f.name != nil {
fname = *f.name fname = *f.name
} else { } else {
// Anonymous field of type T or *T. // Anonymous field of type T or *T.
// Name taken from type. // Name taken from type.
ntyp = toCommonType(f.typ) ntyp = f.typ
if ntyp.Kind() == Ptr { if ntyp.Kind() == Ptr {
ntyp = ntyp.Elem().common() ntyp = ntyp.Elem().common()
} }
...@@ -977,21 +962,6 @@ func (t *structType) FieldByName(name string) (f StructField, present bool) { ...@@ -977,21 +962,6 @@ func (t *structType) FieldByName(name string) (f StructField, present bool) {
return t.FieldByNameFunc(func(s string) bool { return s == name }) return t.FieldByNameFunc(func(s string) bool { return s == name })
} }
// Convert runtime type to reflect type.
func toCommonType(p *runtimeType) *commonType {
if p == nil {
return nil
}
return (*p).(*commonType)
}
func toType(p *runtimeType) Type {
if p == nil {
return nil
}
return (*p).(*commonType)
}
// TypeOf returns the reflection Type of the value in the interface{}. // TypeOf returns the reflection Type of the value in the interface{}.
// TypeOf(nil) returns nil. // TypeOf(nil) returns nil.
func TypeOf(i interface{}) Type { func TypeOf(i interface{}) Type {
...@@ -1002,28 +972,18 @@ func TypeOf(i interface{}) Type { ...@@ -1002,28 +972,18 @@ func TypeOf(i interface{}) Type {
// ptrMap is the cache for PtrTo. // ptrMap is the cache for PtrTo.
var ptrMap struct { var ptrMap struct {
sync.RWMutex sync.RWMutex
m map[*commonType]*ptrType m map[*rtype]*ptrType
}
func (t *commonType) runtimeType() *runtimeType {
// The runtimeType always precedes the commonType in memory.
// Adjust pointer to find it.
var rt struct {
i runtimeType
ct commonType
}
return (*runtimeType)(unsafe.Pointer(uintptr(unsafe.Pointer(t)) - unsafe.Offsetof(rt.ct)))
} }
// PtrTo returns the pointer type with element t. // PtrTo returns the pointer type with element t.
// For example, if t represents type Foo, PtrTo(t) represents *Foo. // For example, if t represents type Foo, PtrTo(t) represents *Foo.
func PtrTo(t Type) Type { func PtrTo(t Type) Type {
return t.(*commonType).ptrTo() return t.(*rtype).ptrTo()
} }
func (ct *commonType) ptrTo() *commonType { func (t *rtype) ptrTo() *rtype {
if p := ct.ptrToThis; p != nil { if p := t.ptrToThis; p != nil {
return toCommonType(p) return p
} }
// Otherwise, synthesize one. // Otherwise, synthesize one.
...@@ -1033,36 +993,31 @@ func (ct *commonType) ptrTo() *commonType { ...@@ -1033,36 +993,31 @@ func (ct *commonType) ptrTo() *commonType {
// the type structures in read-only memory. // the type structures in read-only memory.
ptrMap.RLock() ptrMap.RLock()
if m := ptrMap.m; m != nil { if m := ptrMap.m; m != nil {
if p := m[ct]; p != nil { if p := m[t]; p != nil {
ptrMap.RUnlock() ptrMap.RUnlock()
return &p.commonType return &p.rtype
} }
} }
ptrMap.RUnlock() ptrMap.RUnlock()
ptrMap.Lock() ptrMap.Lock()
if ptrMap.m == nil { if ptrMap.m == nil {
ptrMap.m = make(map[*commonType]*ptrType) ptrMap.m = make(map[*rtype]*ptrType)
} }
p := ptrMap.m[ct] p := ptrMap.m[t]
if p != nil { if p != nil {
// some other goroutine won the race and created it // some other goroutine won the race and created it
ptrMap.Unlock() ptrMap.Unlock()
return &p.commonType return &p.rtype
} }
var rt struct { // Create a new ptrType starting with the description
i runtimeType // of an *unsafe.Pointer.
ptrType p = new(ptrType)
} var iptr interface{} = (*unsafe.Pointer)(nil)
rt.i = &rt.commonType prototype := *(**ptrType)(unsafe.Pointer(&iptr))
*p = *prototype
// initialize p using *byte's ptrType as a prototype. s := "*" + *t.string
p = &rt.ptrType
var ibyte interface{} = (*byte)(nil)
bp := (*ptrType)(unsafe.Pointer((**(**runtimeType)(unsafe.Pointer(&ibyte))).(*commonType)))
*p = *bp
s := "*" + *ct.string
p.string = &s p.string = &s
// For the type structures linked into the binary, the // For the type structures linked into the binary, the
...@@ -1070,45 +1025,53 @@ func (ct *commonType) ptrTo() *commonType { ...@@ -1070,45 +1025,53 @@ func (ct *commonType) ptrTo() *commonType {
// Create a good hash for the new string by using // Create a good hash for the new string by using
// the FNV-1 hash's mixing function to combine the // the FNV-1 hash's mixing function to combine the
// old hash and the new "*". // old hash and the new "*".
p.hash = ct.hash*16777619 ^ '*' p.hash = fnv1(t.hash, '*')
p.uncommonType = nil p.uncommonType = nil
p.ptrToThis = nil p.ptrToThis = nil
p.elem = (*runtimeType)(unsafe.Pointer(uintptr(unsafe.Pointer(ct)) - unsafe.Offsetof(rt.ptrType))) p.elem = t
ptrMap.m[ct] = p ptrMap.m[t] = p
ptrMap.Unlock() ptrMap.Unlock()
return &p.commonType return &p.rtype
}
// fnv1 incorporates the list of bytes into the hash x using the FNV-1 hash function.
func fnv1(x uint32, list ...byte) uint32 {
for _, b := range list {
x = x*16777619 ^ uint32(b)
}
return x
} }
func (t *commonType) Implements(u Type) bool { func (t *rtype) Implements(u Type) bool {
if u == nil { if u == nil {
panic("reflect: nil type passed to Type.Implements") panic("reflect: nil type passed to Type.Implements")
} }
if u.Kind() != Interface { if u.Kind() != Interface {
panic("reflect: non-interface type passed to Type.Implements") panic("reflect: non-interface type passed to Type.Implements")
} }
return implements(u.(*commonType), t) return implements(u.(*rtype), t)
} }
func (t *commonType) AssignableTo(u Type) bool { func (t *rtype) AssignableTo(u Type) bool {
if u == nil { if u == nil {
panic("reflect: nil type passed to Type.AssignableTo") panic("reflect: nil type passed to Type.AssignableTo")
} }
uu := u.(*commonType) uu := u.(*rtype)
return directlyAssignable(uu, t) || implements(uu, t) return directlyAssignable(uu, t) || implements(uu, t)
} }
func (t *commonType) ConvertibleTo(u Type) bool { func (t *rtype) ConvertibleTo(u Type) bool {
if u == nil { if u == nil {
panic("reflect: nil type passed to Type.ConvertibleTo") panic("reflect: nil type passed to Type.ConvertibleTo")
} }
uu := u.(*commonType) uu := u.(*rtype)
return convertOp(uu, t) != nil return convertOp(uu, t) != nil
} }
// implements returns true if the type V implements the interface type T. // implements returns true if the type V implements the interface type T.
func implements(T, V *commonType) bool { func implements(T, V *rtype) bool {
if T.Kind() != Interface { if T.Kind() != Interface {
return false return false
} }
...@@ -1166,7 +1129,7 @@ func implements(T, V *commonType) bool { ...@@ -1166,7 +1129,7 @@ func implements(T, V *commonType) bool {
// http://golang.org/doc/go_spec.html#Assignability // http://golang.org/doc/go_spec.html#Assignability
// Ignoring the interface rules (implemented elsewhere) // Ignoring the interface rules (implemented elsewhere)
// and the ideal constant rules (no ideal constants at run time). // and the ideal constant rules (no ideal constants at run time).
func directlyAssignable(T, V *commonType) bool { func directlyAssignable(T, V *rtype) bool {
// x's type V is identical to T? // x's type V is identical to T?
if T == V { if T == V {
return true return true
...@@ -1182,7 +1145,7 @@ func directlyAssignable(T, V *commonType) bool { ...@@ -1182,7 +1145,7 @@ func directlyAssignable(T, V *commonType) bool {
return haveIdenticalUnderlyingType(T, V) return haveIdenticalUnderlyingType(T, V)
} }
func haveIdenticalUnderlyingType(T, V *commonType) bool { func haveIdenticalUnderlyingType(T, V *rtype) bool {
if T == V { if T == V {
return true return true
} }
...@@ -1278,3 +1241,295 @@ func haveIdenticalUnderlyingType(T, V *commonType) bool { ...@@ -1278,3 +1241,295 @@ func haveIdenticalUnderlyingType(T, V *commonType) bool {
return false return false
} }
// typelinks is implemented in package runtime.
// It retuns a slice of all the 'typelink' information in the binary,
// which is to say a slice of known types, sorted by string.
// Note that strings are not unique identifiers for types:
// there can be more than one with a given string.
// Only types we might want to look up are included:
// channels, maps, slices, and arrays.
func typelinks() []*rtype
// typesByString returns the subslice of typelinks() whose elements have
// the given string representation.
// It may be empty (no known types with that string) or may have
// multiple elements (multiple types with that string).
func typesByString(s string) []*rtype {
typ := typelinks()
// We are looking for the first index i where the string becomes >= s.
// This is a copy of sort.Search, with f(h) replaced by (*typ[h].string >= s).
i, j := 0, len(typ)
for i < j {
h := i + (j-i)/2 // avoid overflow when computing h
// i ≤ h < j
if !(*typ[h].string >= s) {
i = h + 1 // preserves f(i-1) == false
} else {
j = h // preserves f(j) == true
}
}
// i == j, f(i-1) == false, and f(j) (= f(i)) == true => answer is i.
// Having found the first, linear scan forward to find the last.
// We could do a second binary search, but the caller is going
// to do a linear scan anyway.
j = i
for j < len(typ) && *typ[j].string == s {
j++
}
// This slice will be empty if the string is not found.
return typ[i:j]
}
// The lookupCache caches ChanOf, MapOf, and SliceOf lookups.
var lookupCache struct {
sync.RWMutex
m map[cacheKey]*rtype
}
// A cacheKey is the key for use in the lookupCache.
// Four values describe any of the types we are looking for:
// type kind, one or two subtypes, and an extra integer.
type cacheKey struct {
kind Kind
t1 *rtype
t2 *rtype
extra uintptr
}
// cacheGet looks for a type under the key k in the lookupCache.
// If it finds one, it returns that type.
// If not, it returns nil with the cache locked.
// The caller is expected to use cachePut to unlock the cache.
func cacheGet(k cacheKey) Type {
lookupCache.RLock()
t := lookupCache.m[k]
lookupCache.RUnlock()
if t != nil {
return t
}
lookupCache.Lock()
t = lookupCache.m[k]
if t != nil {
lookupCache.Unlock()
return t
}
if lookupCache.m == nil {
lookupCache.m = make(map[cacheKey]*rtype)
}
return nil
}
// cachePut stores the given type in the cache, unlocks the cache,
// and returns the type. It is expected that the cache is locked
// because cacheGet returned nil.
func cachePut(k cacheKey, t *rtype) Type {
lookupCache.m[k] = t
lookupCache.Unlock()
return t
}
// ChanOf returns the channel type with the given direction and and element type.
// For example, if t represents int, ChanOf(RecvDir, t) represents <-chan int.
//
// The gc runtime imposes a limit of 64 kB on channel element types.
// If t's size is equal to or exceeds this limit, ChanOf panics.
func ChanOf(dir ChanDir, t Type) Type {
typ := t.(*rtype)
// Look in cache.
ckey := cacheKey{Chan, typ, nil, uintptr(dir)}
if ch := cacheGet(ckey); ch != nil {
return ch
}
// This restriction is imposed by the gc compiler and the runtime.
if typ.size >= 1<<16 {
lookupCache.Unlock()
panic("reflect.ChanOf: element size too large")
}
// Look in known types.
// TODO: Precedence when constructing string.
var s string
switch dir {
default:
lookupCache.Unlock()
panic("reflect.ChanOf: invalid dir")
case SendDir:
s = "chan<- " + *typ.string
case RecvDir:
s = "<-chan " + *typ.string
case BothDir:
s = "chan " + *typ.string
}
for _, tt := range typesByString(s) {
ch := (*chanType)(unsafe.Pointer(tt))
if ch.elem == typ && ch.dir == uintptr(dir) {
return cachePut(ckey, tt)
}
}
// Make a channel type.
var ichan interface{} = (chan unsafe.Pointer)(nil)
prototype := *(**chanType)(unsafe.Pointer(&ichan))
ch := new(chanType)
*ch = *prototype
ch.string = &s
ch.hash = fnv1(typ.hash, 'c', byte(dir))
ch.elem = typ
ch.uncommonType = nil
ch.ptrToThis = nil
return cachePut(ckey, &ch.rtype)
}
// MapOf returns the map type with the given key and element types.
// For example, if k represents int and e represents string,
// MapOf(k, e) represents map[int]string.
//
// If the key type is not a valid map key type (that is, if it does
// not implement Go's == operator), MapOf panics. TODO(rsc).
func MapOf(key, elem Type) Type {
ktyp := key.(*rtype)
etyp := elem.(*rtype)
// TODO: Check for invalid key types.
// Look in cache.
ckey := cacheKey{Map, ktyp, etyp, 0}
if mt := cacheGet(ckey); mt != nil {
return mt
}
// Look in known types.
s := "map[" + *ktyp.string + "]" + *etyp.string
for _, tt := range typesByString(s) {
mt := (*mapType)(unsafe.Pointer(tt))
if mt.key == ktyp && mt.elem == etyp {
return cachePut(ckey, tt)
}
}
// Make a map type.
var imap interface{} = (map[unsafe.Pointer]unsafe.Pointer)(nil)
prototype := *(**mapType)(unsafe.Pointer(&imap))
mt := new(mapType)
*mt = *prototype
mt.string = &s
mt.hash = fnv1(etyp.hash, 'm', byte(ktyp.hash>>24), byte(ktyp.hash>>16), byte(ktyp.hash>>8), byte(ktyp.hash))
mt.key = ktyp
mt.elem = etyp
mt.uncommonType = nil
mt.ptrToThis = nil
return cachePut(ckey, &mt.rtype)
}
// SliceOf returns the slice type with element type t.
// For example, if t represents int, SliceOf(t) represents []int.
func SliceOf(t Type) Type {
typ := t.(*rtype)
// Look in cache.
ckey := cacheKey{Slice, typ, nil, 0}
if slice := cacheGet(ckey); slice != nil {
return slice
}
// Look in known types.
s := "[]" + *typ.string
for _, tt := range typesByString(s) {
slice := (*sliceType)(unsafe.Pointer(tt))
if slice.elem == typ {
return cachePut(ckey, tt)
}
}
// Make a slice type.
var islice interface{} = ([]unsafe.Pointer)(nil)
prototype := *(**sliceType)(unsafe.Pointer(&islice))
slice := new(sliceType)
*slice = *prototype
slice.string = &s
slice.hash = fnv1(typ.hash, '[')
slice.elem = typ
slice.uncommonType = nil
slice.ptrToThis = nil
return cachePut(ckey, &slice.rtype)
}
// ArrayOf returns the array type with the given count and element type.
// For example, if t represents int, ArrayOf(5, t) represents [5]int.
//
// If the resulting type would be larger than the available address space,
// ArrayOf panics.
//
// TODO(rsc): Unexported for now. Export once the alg field is set correctly
// for the type. This may require significant work.
func arrayOf(count int, elem Type) Type {
typ := elem.(*rtype)
slice := SliceOf(elem)
// Look in cache.
ckey := cacheKey{Array, typ, nil, uintptr(count)}
if slice := cacheGet(ckey); slice != nil {
return slice
}
// Look in known types.
s := "[" + strconv.Itoa(count) + "]" + *typ.string
for _, tt := range typesByString(s) {
slice := (*sliceType)(unsafe.Pointer(tt))
if slice.elem == typ {
return cachePut(ckey, tt)
}
}
// Make an array type.
var iarray interface{} = [1]unsafe.Pointer{}
prototype := *(**arrayType)(unsafe.Pointer(&iarray))
array := new(arrayType)
*array = *prototype
array.string = &s
array.hash = fnv1(typ.hash, '[')
for n := uint32(count); n > 0; n >>= 8 {
array.hash = fnv1(array.hash, byte(n))
}
array.hash = fnv1(array.hash, ']')
array.elem = typ
max := ^uintptr(0) / typ.size
if uintptr(count) > max {
panic("reflect.ArrayOf: array size would exceed virtual address space")
}
array.size = typ.size * uintptr(count)
array.align = typ.align
array.fieldAlign = typ.fieldAlign
// TODO: array.alg
// TODO: array.gc
array.uncommonType = nil
array.ptrToThis = nil
array.len = uintptr(count)
array.slice = slice.(*rtype)
return cachePut(ckey, &array.rtype)
}
// toType converts from a *rtype to a Type that can be returned
// to the client of package reflect. In gc, the only concern is that
// a nil *rtype must be replaced by a nil Type, but in gccgo this
// function takes care of ensuring that multiple *rtype for the same
// type are coalesced into a single Type.
func toType(t *rtype) Type {
if t == nil {
return nil
}
return t
}
...@@ -60,7 +60,7 @@ func memmove(adst, asrc unsafe.Pointer, n uintptr) { ...@@ -60,7 +60,7 @@ func memmove(adst, asrc unsafe.Pointer, n uintptr) {
// direct operations. // direct operations.
type Value struct { type Value struct {
// typ holds the type of the value represented by a Value. // typ holds the type of the value represented by a Value.
typ *commonType typ *rtype
// val holds the 1-word representation of the value. // val holds the 1-word representation of the value.
// If flag's flagIndir bit is set, then val is a pointer to the data. // If flag's flagIndir bit is set, then val is a pointer to the data.
...@@ -211,7 +211,7 @@ func storeIword(p unsafe.Pointer, w iword, n uintptr) { ...@@ -211,7 +211,7 @@ func storeIword(p unsafe.Pointer, w iword, n uintptr) {
// emptyInterface is the header for an interface{} value. // emptyInterface is the header for an interface{} value.
type emptyInterface struct { type emptyInterface struct {
typ *runtimeType typ *rtype
word iword word iword
} }
...@@ -219,8 +219,8 @@ type emptyInterface struct { ...@@ -219,8 +219,8 @@ type emptyInterface struct {
type nonEmptyInterface struct { type nonEmptyInterface struct {
// see ../runtime/iface.c:/Itab // see ../runtime/iface.c:/Itab
itab *struct { itab *struct {
ityp *runtimeType // static interface type ityp *rtype // static interface type
typ *runtimeType // dynamic concrete type typ *rtype // dynamic concrete type
link unsafe.Pointer link unsafe.Pointer
bad int32 bad int32
unused int32 unused int32
...@@ -376,7 +376,7 @@ func (v Value) call(method string, in []Value) []Value { ...@@ -376,7 +376,7 @@ func (v Value) call(method string, in []Value) []Value {
if m.pkgPath != nil { if m.pkgPath != nil {
panic(method + " of unexported method") panic(method + " of unexported method")
} }
t = toCommonType(m.typ) t = m.typ
iface := (*nonEmptyInterface)(v.val) iface := (*nonEmptyInterface)(v.val)
if iface.itab == nil { if iface.itab == nil {
panic(method + " of method on nil interface value") panic(method + " of method on nil interface value")
...@@ -393,7 +393,7 @@ func (v Value) call(method string, in []Value) []Value { ...@@ -393,7 +393,7 @@ func (v Value) call(method string, in []Value) []Value {
panic(method + " of unexported method") panic(method + " of unexported method")
} }
fn = m.ifn fn = m.ifn
t = toCommonType(m.mtyp) t = m.mtyp
rcvr = v.iword() rcvr = v.iword()
} }
} else if v.flag&flagIndir != 0 { } else if v.flag&flagIndir != 0 {
...@@ -513,7 +513,7 @@ func (v Value) call(method string, in []Value) []Value { ...@@ -513,7 +513,7 @@ func (v Value) call(method string, in []Value) []Value {
} }
for i, v := range in { for i, v := range in {
v.mustBeExported() v.mustBeExported()
targ := t.In(i).(*commonType) targ := t.In(i).(*rtype)
a := uintptr(targ.align) a := uintptr(targ.align)
off = (off + a - 1) &^ (a - 1) off = (off + a - 1) &^ (a - 1)
n := targ.size n := targ.size
...@@ -561,7 +561,7 @@ func callReflect(ftyp *funcType, f func([]Value) []Value, frame unsafe.Pointer) ...@@ -561,7 +561,7 @@ func callReflect(ftyp *funcType, f func([]Value) []Value, frame unsafe.Pointer)
off := uintptr(0) off := uintptr(0)
in := make([]Value, 0, len(ftyp.in)) in := make([]Value, 0, len(ftyp.in))
for _, arg := range ftyp.in { for _, arg := range ftyp.in {
typ := toCommonType(arg) typ := arg
off += -off & uintptr(typ.align-1) off += -off & uintptr(typ.align-1)
v := Value{typ, nil, flag(typ.Kind()) << flagKindShift} v := Value{typ, nil, flag(typ.Kind()) << flagKindShift}
if typ.size <= ptrSize { if typ.size <= ptrSize {
...@@ -590,7 +590,7 @@ func callReflect(ftyp *funcType, f func([]Value) []Value, frame unsafe.Pointer) ...@@ -590,7 +590,7 @@ func callReflect(ftyp *funcType, f func([]Value) []Value, frame unsafe.Pointer)
if len(ftyp.out) > 0 { if len(ftyp.out) > 0 {
off += -off & (ptrSize - 1) off += -off & (ptrSize - 1)
for i, arg := range ftyp.out { for i, arg := range ftyp.out {
typ := toCommonType(arg) typ := arg
v := out[i] v := out[i]
if v.typ != typ { if v.typ != typ {
panic("reflect: function created by MakeFunc using " + funcName(f) + panic("reflect: function created by MakeFunc using " + funcName(f) +
...@@ -673,7 +673,7 @@ func (v Value) Elem() Value { ...@@ -673,7 +673,7 @@ func (v Value) Elem() Value {
switch k { switch k {
case Interface: case Interface:
var ( var (
typ *commonType typ *rtype
val unsafe.Pointer val unsafe.Pointer
) )
if v.typ.NumMethod() == 0 { if v.typ.NumMethod() == 0 {
...@@ -682,7 +682,7 @@ func (v Value) Elem() Value { ...@@ -682,7 +682,7 @@ func (v Value) Elem() Value {
// nil interface value // nil interface value
return Value{} return Value{}
} }
typ = toCommonType(eface.typ) typ = eface.typ
val = unsafe.Pointer(eface.word) val = unsafe.Pointer(eface.word)
} else { } else {
iface := (*nonEmptyInterface)(v.val) iface := (*nonEmptyInterface)(v.val)
...@@ -690,7 +690,7 @@ func (v Value) Elem() Value { ...@@ -690,7 +690,7 @@ func (v Value) Elem() Value {
// nil interface value // nil interface value
return Value{} return Value{}
} }
typ = toCommonType(iface.itab.typ) typ = iface.itab.typ
val = unsafe.Pointer(iface.word) val = unsafe.Pointer(iface.word)
} }
fl := v.flag & flagRO fl := v.flag & flagRO
...@@ -710,7 +710,7 @@ func (v Value) Elem() Value { ...@@ -710,7 +710,7 @@ func (v Value) Elem() Value {
return Value{} return Value{}
} }
tt := (*ptrType)(unsafe.Pointer(v.typ)) tt := (*ptrType)(unsafe.Pointer(v.typ))
typ := toCommonType(tt.elem) typ := tt.elem
fl := v.flag&flagRO | flagIndir | flagAddr fl := v.flag&flagRO | flagIndir | flagAddr
fl |= flag(typ.Kind() << flagKindShift) fl |= flag(typ.Kind() << flagKindShift)
return Value{typ, val, fl} return Value{typ, val, fl}
...@@ -727,7 +727,7 @@ func (v Value) Field(i int) Value { ...@@ -727,7 +727,7 @@ func (v Value) Field(i int) Value {
panic("reflect: Field index out of range") panic("reflect: Field index out of range")
} }
field := &tt.fields[i] field := &tt.fields[i]
typ := toCommonType(field.typ) typ := field.typ
// Inherit permission bits from v. // Inherit permission bits from v.
fl := v.flag & (flagRO | flagIndir | flagAddr) fl := v.flag & (flagRO | flagIndir | flagAddr)
...@@ -810,7 +810,7 @@ func (v Value) Float() float64 { ...@@ -810,7 +810,7 @@ func (v Value) Float() float64 {
panic(&ValueError{"reflect.Value.Float", k}) panic(&ValueError{"reflect.Value.Float", k})
} }
var uint8Type = TypeOf(uint8(0)).(*commonType) var uint8Type = TypeOf(uint8(0)).(*rtype)
// Index returns v's i'th element. // Index returns v's i'th element.
// It panics if v's Kind is not Array, Slice, or String or i is out of range. // It panics if v's Kind is not Array, Slice, or String or i is out of range.
...@@ -822,7 +822,7 @@ func (v Value) Index(i int) Value { ...@@ -822,7 +822,7 @@ func (v Value) Index(i int) Value {
if i < 0 || i > int(tt.len) { if i < 0 || i > int(tt.len) {
panic("reflect: array index out of range") panic("reflect: array index out of range")
} }
typ := toCommonType(tt.elem) typ := tt.elem
fl := v.flag & (flagRO | flagIndir | flagAddr) // bits same as overall array fl := v.flag & (flagRO | flagIndir | flagAddr) // bits same as overall array
fl |= flag(typ.Kind()) << flagKindShift fl |= flag(typ.Kind()) << flagKindShift
offset := uintptr(i) * typ.size offset := uintptr(i) * typ.size
...@@ -850,7 +850,7 @@ func (v Value) Index(i int) Value { ...@@ -850,7 +850,7 @@ func (v Value) Index(i int) Value {
panic("reflect: slice index out of range") panic("reflect: slice index out of range")
} }
tt := (*sliceType)(unsafe.Pointer(v.typ)) tt := (*sliceType)(unsafe.Pointer(v.typ))
typ := toCommonType(tt.elem) typ := tt.elem
fl |= flag(typ.Kind()) << flagKindShift fl |= flag(typ.Kind()) << flagKindShift
val := unsafe.Pointer(s.Data + uintptr(i)*typ.size) val := unsafe.Pointer(s.Data + uintptr(i)*typ.size)
return Value{typ, val, fl} return Value{typ, val, fl}
...@@ -944,7 +944,7 @@ func valueInterface(v Value, safe bool) interface{} { ...@@ -944,7 +944,7 @@ func valueInterface(v Value, safe bool) interface{} {
// Non-interface value. // Non-interface value.
var eface emptyInterface var eface emptyInterface
eface.typ = v.typ.runtimeType() eface.typ = v.typ
eface.word = v.iword() eface.word = v.iword()
if v.flag&flagIndir != 0 && v.typ.size > ptrSize { if v.flag&flagIndir != 0 && v.typ.size > ptrSize {
...@@ -1045,13 +1045,13 @@ func (v Value) MapIndex(key Value) Value { ...@@ -1045,13 +1045,13 @@ func (v Value) MapIndex(key Value) Value {
// considered unexported. This is consistent with the // considered unexported. This is consistent with the
// behavior for structs, which allow read but not write // behavior for structs, which allow read but not write
// of unexported fields. // of unexported fields.
key = key.assignTo("reflect.Value.MapIndex", toCommonType(tt.key), nil) key = key.assignTo("reflect.Value.MapIndex", tt.key, nil)
word, ok := mapaccess(v.typ.runtimeType(), v.iword(), key.iword()) word, ok := mapaccess(v.typ, v.iword(), key.iword())
if !ok { if !ok {
return Value{} return Value{}
} }
typ := toCommonType(tt.elem) typ := tt.elem
fl := (v.flag | key.flag) & flagRO fl := (v.flag | key.flag) & flagRO
if typ.size > ptrSize { if typ.size > ptrSize {
fl |= flagIndir fl |= flagIndir
...@@ -1067,7 +1067,7 @@ func (v Value) MapIndex(key Value) Value { ...@@ -1067,7 +1067,7 @@ func (v Value) MapIndex(key Value) Value {
func (v Value) MapKeys() []Value { func (v Value) MapKeys() []Value {
v.mustBe(Map) v.mustBe(Map)
tt := (*mapType)(unsafe.Pointer(v.typ)) tt := (*mapType)(unsafe.Pointer(v.typ))
keyType := toCommonType(tt.key) keyType := tt.key
fl := v.flag & flagRO fl := v.flag & flagRO
fl |= flag(keyType.Kind()) << flagKindShift fl |= flag(keyType.Kind()) << flagKindShift
...@@ -1080,7 +1080,7 @@ func (v Value) MapKeys() []Value { ...@@ -1080,7 +1080,7 @@ func (v Value) MapKeys() []Value {
if m != nil { if m != nil {
mlen = maplen(m) mlen = maplen(m)
} }
it := mapiterinit(v.typ.runtimeType(), m) it := mapiterinit(v.typ, m)
a := make([]Value, mlen) a := make([]Value, mlen)
var i int var i int
for i = 0; i < len(a); i++ { for i = 0; i < len(a); i++ {
...@@ -1249,9 +1249,9 @@ func (v Value) recv(nb bool) (val Value, ok bool) { ...@@ -1249,9 +1249,9 @@ func (v Value) recv(nb bool) (val Value, ok bool) {
if ChanDir(tt.dir)&RecvDir == 0 { if ChanDir(tt.dir)&RecvDir == 0 {
panic("recv on send-only channel") panic("recv on send-only channel")
} }
word, selected, ok := chanrecv(v.typ.runtimeType(), v.iword(), nb) word, selected, ok := chanrecv(v.typ, v.iword(), nb)
if selected { if selected {
typ := toCommonType(tt.elem) typ := tt.elem
fl := flag(typ.Kind()) << flagKindShift fl := flag(typ.Kind()) << flagKindShift
if typ.size > ptrSize { if typ.size > ptrSize {
fl |= flagIndir fl |= flagIndir
...@@ -1278,8 +1278,8 @@ func (v Value) send(x Value, nb bool) (selected bool) { ...@@ -1278,8 +1278,8 @@ func (v Value) send(x Value, nb bool) (selected bool) {
panic("send on recv-only channel") panic("send on recv-only channel")
} }
x.mustBeExported() x.mustBeExported()
x = x.assignTo("reflect.Value.Send", toCommonType(tt.elem), nil) x = x.assignTo("reflect.Value.Send", tt.elem, nil)
return chansend(v.typ.runtimeType(), v.iword(), x.iword(), nb) return chansend(v.typ, v.iword(), x.iword(), nb)
} }
// Set assigns x to the value v. // Set assigns x to the value v.
...@@ -1401,12 +1401,12 @@ func (v Value) SetMapIndex(key, val Value) { ...@@ -1401,12 +1401,12 @@ func (v Value) SetMapIndex(key, val Value) {
v.mustBeExported() v.mustBeExported()
key.mustBeExported() key.mustBeExported()
tt := (*mapType)(unsafe.Pointer(v.typ)) tt := (*mapType)(unsafe.Pointer(v.typ))
key = key.assignTo("reflect.Value.SetMapIndex", toCommonType(tt.key), nil) key = key.assignTo("reflect.Value.SetMapIndex", tt.key, nil)
if val.typ != nil { if val.typ != nil {
val.mustBeExported() val.mustBeExported()
val = val.assignTo("reflect.Value.SetMapIndex", toCommonType(tt.elem), nil) val = val.assignTo("reflect.Value.SetMapIndex", tt.elem, nil)
} }
mapassign(v.typ.runtimeType(), v.iword(), key.iword(), val.iword(), val.typ != nil) mapassign(v.typ, v.iword(), key.iword(), val.iword(), val.typ != nil)
} }
// SetUint sets v's underlying value to x. // SetUint sets v's underlying value to x.
...@@ -1465,7 +1465,7 @@ func (v Value) Slice(beg, end int) Value { ...@@ -1465,7 +1465,7 @@ func (v Value) Slice(beg, end int) Value {
} }
tt := (*arrayType)(unsafe.Pointer(v.typ)) tt := (*arrayType)(unsafe.Pointer(v.typ))
cap = int(tt.len) cap = int(tt.len)
typ = (*sliceType)(unsafe.Pointer(toCommonType(tt.slice))) typ = (*sliceType)(unsafe.Pointer(tt.slice))
base = v.val base = v.val
case Slice: case Slice:
...@@ -1495,7 +1495,7 @@ func (v Value) Slice(beg, end int) Value { ...@@ -1495,7 +1495,7 @@ func (v Value) Slice(beg, end int) Value {
// Reinterpret as *SliceHeader to edit. // Reinterpret as *SliceHeader to edit.
s := (*SliceHeader)(unsafe.Pointer(&x)) s := (*SliceHeader)(unsafe.Pointer(&x))
s.Data = uintptr(base) + uintptr(beg)*toCommonType(typ.elem).Size() s.Data = uintptr(base) + uintptr(beg)*typ.elem.Size()
s.Len = end - beg s.Len = end - beg
s.Cap = cap - beg s.Cap = cap - beg
...@@ -1561,7 +1561,7 @@ func (v Value) Type() Type { ...@@ -1561,7 +1561,7 @@ func (v Value) Type() Type {
panic("reflect: broken Value") panic("reflect: broken Value")
} }
m := &tt.methods[i] m := &tt.methods[i]
return toCommonType(m.typ) return m.typ
} }
// Method on concrete type. // Method on concrete type.
ut := v.typ.uncommon() ut := v.typ.uncommon()
...@@ -1569,7 +1569,7 @@ func (v Value) Type() Type { ...@@ -1569,7 +1569,7 @@ func (v Value) Type() Type {
panic("reflect: broken Value") panic("reflect: broken Value")
} }
m := &ut.methods[i] m := &ut.methods[i]
return toCommonType(m.mtyp) return m.mtyp
} }
// Uint returns v's underlying value, as a uint64. // Uint returns v's underlying value, as a uint64.
...@@ -1743,10 +1743,10 @@ func Copy(dst, src Value) int { ...@@ -1743,10 +1743,10 @@ func Copy(dst, src Value) int {
// A runtimeSelect is a single case passed to rselect. // A runtimeSelect is a single case passed to rselect.
// This must match ../runtime/chan.c:/runtimeSelect // This must match ../runtime/chan.c:/runtimeSelect
type runtimeSelect struct { type runtimeSelect struct {
dir uintptr // 0, SendDir, or RecvDir dir uintptr // 0, SendDir, or RecvDir
typ *runtimeType // channel type typ *rtype // channel type
ch iword // interface word for channel ch iword // interface word for channel
val iword // interface word for value (for SendDir) val iword // interface word for value (for SendDir)
} }
// rselect runs a select. It returns the index of the chosen case, // rselect runs a select. It returns the index of the chosen case,
...@@ -1833,13 +1833,13 @@ func Select(cases []SelectCase) (chosen int, recv Value, recvOK bool) { ...@@ -1833,13 +1833,13 @@ func Select(cases []SelectCase) (chosen int, recv Value, recvOK bool) {
panic("reflect.Select: SendDir case using recv-only channel") panic("reflect.Select: SendDir case using recv-only channel")
} }
rc.ch = ch.iword() rc.ch = ch.iword()
rc.typ = tt.runtimeType() rc.typ = &tt.rtype
v := c.Send v := c.Send
if !v.IsValid() { if !v.IsValid() {
panic("reflect.Select: SendDir case missing Send value") panic("reflect.Select: SendDir case missing Send value")
} }
v.mustBeExported() v.mustBeExported()
v = v.assignTo("reflect.Select", toCommonType(tt.elem), nil) v = v.assignTo("reflect.Select", tt.elem, nil)
rc.val = v.iword() rc.val = v.iword()
case SelectRecv: case SelectRecv:
...@@ -1853,7 +1853,7 @@ func Select(cases []SelectCase) (chosen int, recv Value, recvOK bool) { ...@@ -1853,7 +1853,7 @@ func Select(cases []SelectCase) (chosen int, recv Value, recvOK bool) {
ch.mustBe(Chan) ch.mustBe(Chan)
ch.mustBeExported() ch.mustBeExported()
tt := (*chanType)(unsafe.Pointer(ch.typ)) tt := (*chanType)(unsafe.Pointer(ch.typ))
rc.typ = tt.runtimeType() rc.typ = &tt.rtype
if ChanDir(tt.dir)&RecvDir == 0 { if ChanDir(tt.dir)&RecvDir == 0 {
panic("reflect.Select: RecvDir case using send-only channel") panic("reflect.Select: RecvDir case using send-only channel")
} }
...@@ -1863,8 +1863,8 @@ func Select(cases []SelectCase) (chosen int, recv Value, recvOK bool) { ...@@ -1863,8 +1863,8 @@ func Select(cases []SelectCase) (chosen int, recv Value, recvOK bool) {
chosen, word, recvOK := rselect(runcases) chosen, word, recvOK := rselect(runcases)
if runcases[chosen].dir == uintptr(SelectRecv) { if runcases[chosen].dir == uintptr(SelectRecv) {
tt := (*chanType)(unsafe.Pointer(toCommonType(runcases[chosen].typ))) tt := (*chanType)(unsafe.Pointer(runcases[chosen].typ))
typ := toCommonType(tt.elem) typ := tt.elem
fl := flag(typ.Kind()) << flagKindShift fl := flag(typ.Kind()) << flagKindShift
if typ.size > ptrSize { if typ.size > ptrSize {
fl |= flagIndir fl |= flagIndir
...@@ -1879,8 +1879,8 @@ func Select(cases []SelectCase) (chosen int, recv Value, recvOK bool) { ...@@ -1879,8 +1879,8 @@ func Select(cases []SelectCase) (chosen int, recv Value, recvOK bool) {
*/ */
// implemented in package runtime // implemented in package runtime
func unsafe_New(Type) unsafe.Pointer func unsafe_New(*rtype) unsafe.Pointer
func unsafe_NewArray(Type, int) unsafe.Pointer func unsafe_NewArray(*rtype, int) unsafe.Pointer
// MakeSlice creates a new zero-initialized slice value // MakeSlice creates a new zero-initialized slice value
// for the specified slice type, length, and capacity. // for the specified slice type, length, and capacity.
...@@ -1903,7 +1903,7 @@ func MakeSlice(typ Type, len, cap int) Value { ...@@ -1903,7 +1903,7 @@ func MakeSlice(typ Type, len, cap int) Value {
// Reinterpret as *SliceHeader to edit. // Reinterpret as *SliceHeader to edit.
s := (*SliceHeader)(unsafe.Pointer(&x)) s := (*SliceHeader)(unsafe.Pointer(&x))
s.Data = uintptr(unsafe_NewArray(typ.Elem(), cap)) s.Data = uintptr(unsafe_NewArray(typ.Elem().(*rtype), cap))
s.Len = len s.Len = len
s.Cap = cap s.Cap = cap
...@@ -1921,7 +1921,7 @@ func MakeChan(typ Type, buffer int) Value { ...@@ -1921,7 +1921,7 @@ func MakeChan(typ Type, buffer int) Value {
if typ.ChanDir() != BothDir { if typ.ChanDir() != BothDir {
panic("reflect.MakeChan: unidirectional channel type") panic("reflect.MakeChan: unidirectional channel type")
} }
ch := makechan(typ.runtimeType(), uint64(buffer)) ch := makechan(typ.(*rtype), uint64(buffer))
return Value{typ.common(), unsafe.Pointer(ch), flag(Chan) << flagKindShift} return Value{typ.common(), unsafe.Pointer(ch), flag(Chan) << flagKindShift}
} }
...@@ -1930,7 +1930,7 @@ func MakeMap(typ Type) Value { ...@@ -1930,7 +1930,7 @@ func MakeMap(typ Type) Value {
if typ.Kind() != Map { if typ.Kind() != Map {
panic("reflect.MakeMap of non-map type") panic("reflect.MakeMap of non-map type")
} }
m := makemap(typ.runtimeType()) m := makemap(typ.(*rtype))
return Value{typ.common(), unsafe.Pointer(m), flag(Map) << flagKindShift} return Value{typ.common(), unsafe.Pointer(m), flag(Map) << flagKindShift}
} }
...@@ -1961,7 +1961,7 @@ func ValueOf(i interface{}) Value { ...@@ -1961,7 +1961,7 @@ func ValueOf(i interface{}) Value {
// For an interface value with the noAddr bit set, // For an interface value with the noAddr bit set,
// the representation is identical to an empty interface. // the representation is identical to an empty interface.
eface := *(*emptyInterface)(unsafe.Pointer(&i)) eface := *(*emptyInterface)(unsafe.Pointer(&i))
typ := toCommonType(eface.typ) typ := eface.typ
fl := flag(typ.Kind()) << flagKindShift fl := flag(typ.Kind()) << flagKindShift
if typ.size > ptrSize { if typ.size > ptrSize {
fl |= flagIndir fl |= flagIndir
...@@ -1983,7 +1983,7 @@ func Zero(typ Type) Value { ...@@ -1983,7 +1983,7 @@ func Zero(typ Type) Value {
if t.size <= ptrSize { if t.size <= ptrSize {
return Value{t, nil, fl} return Value{t, nil, fl}
} }
return Value{t, unsafe_New(typ), fl | flagIndir} return Value{t, unsafe_New(typ.(*rtype)), fl | flagIndir}
} }
// New returns a Value representing a pointer to a new zero value // New returns a Value representing a pointer to a new zero value
...@@ -1992,7 +1992,7 @@ func New(typ Type) Value { ...@@ -1992,7 +1992,7 @@ func New(typ Type) Value {
if typ == nil { if typ == nil {
panic("reflect: New(nil)") panic("reflect: New(nil)")
} }
ptr := unsafe_New(typ) ptr := unsafe_New(typ.(*rtype))
fl := flag(Ptr) << flagKindShift fl := flag(Ptr) << flagKindShift
return Value{typ.common().ptrTo(), ptr, fl} return Value{typ.common().ptrTo(), ptr, fl}
} }
...@@ -2007,7 +2007,7 @@ func NewAt(typ Type, p unsafe.Pointer) Value { ...@@ -2007,7 +2007,7 @@ func NewAt(typ Type, p unsafe.Pointer) Value {
// assignTo returns a value v that can be assigned directly to typ. // assignTo returns a value v that can be assigned directly to typ.
// It panics if v is not assignable to typ. // It panics if v is not assignable to typ.
// For a conversion to an interface type, target is a suggested scratch space to use. // For a conversion to an interface type, target is a suggested scratch space to use.
func (v Value) assignTo(context string, dst *commonType, target *interface{}) Value { func (v Value) assignTo(context string, dst *rtype, target *interface{}) Value {
if v.flag&flagMethod != 0 { if v.flag&flagMethod != 0 {
panic(context + ": cannot assign method value to type " + dst.String()) panic(context + ": cannot assign method value to type " + dst.String())
} }
...@@ -2029,7 +2029,7 @@ func (v Value) assignTo(context string, dst *commonType, target *interface{}) Va ...@@ -2029,7 +2029,7 @@ func (v Value) assignTo(context string, dst *commonType, target *interface{}) Va
if dst.NumMethod() == 0 { if dst.NumMethod() == 0 {
*target = x *target = x
} else { } else {
ifaceE2I(dst.runtimeType(), x, unsafe.Pointer(target)) ifaceE2I(dst, x, unsafe.Pointer(target))
} }
return Value{dst, unsafe.Pointer(target), flagIndir | flag(Interface)<<flagKindShift} return Value{dst, unsafe.Pointer(target), flagIndir | flag(Interface)<<flagKindShift}
} }
...@@ -2054,7 +2054,7 @@ func (v Value) Convert(t Type) Value { ...@@ -2054,7 +2054,7 @@ func (v Value) Convert(t Type) Value {
// convertOp returns the function to convert a value of type src // convertOp returns the function to convert a value of type src
// to a value of type dst. If the conversion is illegal, convertOp returns nil. // to a value of type dst. If the conversion is illegal, convertOp returns nil.
func convertOp(dst, src *commonType) func(Value, Type) Value { func convertOp(dst, src *rtype) func(Value, Type) Value {
switch src.Kind() { switch src.Kind() {
case Int, Int8, Int16, Int32, Int64: case Int, Int8, Int16, Int32, Int64:
switch dst.Kind() { switch dst.Kind() {
...@@ -2141,7 +2141,7 @@ func makeInt(f flag, bits uint64, t Type) Value { ...@@ -2141,7 +2141,7 @@ func makeInt(f flag, bits uint64, t Type) Value {
typ := t.common() typ := t.common()
if typ.size > ptrSize { if typ.size > ptrSize {
// Assume ptrSize >= 4, so this must be uint64. // Assume ptrSize >= 4, so this must be uint64.
ptr := unsafe_New(t) ptr := unsafe_New(typ)
*(*uint64)(unsafe.Pointer(ptr)) = bits *(*uint64)(unsafe.Pointer(ptr)) = bits
return Value{typ, ptr, f | flag(typ.Kind())<<flagKindShift} return Value{typ, ptr, f | flag(typ.Kind())<<flagKindShift}
} }
...@@ -2165,7 +2165,7 @@ func makeFloat(f flag, v float64, t Type) Value { ...@@ -2165,7 +2165,7 @@ func makeFloat(f flag, v float64, t Type) Value {
typ := t.common() typ := t.common()
if typ.size > ptrSize { if typ.size > ptrSize {
// Assume ptrSize >= 4, so this must be float64. // Assume ptrSize >= 4, so this must be float64.
ptr := unsafe_New(t) ptr := unsafe_New(typ)
*(*float64)(unsafe.Pointer(ptr)) = v *(*float64)(unsafe.Pointer(ptr)) = v
return Value{typ, ptr, f | flag(typ.Kind())<<flagKindShift} return Value{typ, ptr, f | flag(typ.Kind())<<flagKindShift}
} }
...@@ -2185,7 +2185,7 @@ func makeFloat(f flag, v float64, t Type) Value { ...@@ -2185,7 +2185,7 @@ func makeFloat(f flag, v float64, t Type) Value {
func makeComplex(f flag, v complex128, t Type) Value { func makeComplex(f flag, v complex128, t Type) Value {
typ := t.common() typ := t.common()
if typ.size > ptrSize { if typ.size > ptrSize {
ptr := unsafe_New(t) ptr := unsafe_New(typ)
switch typ.size { switch typ.size {
case 8: case 8:
*(*complex64)(unsafe.Pointer(ptr)) = complex64(v) *(*complex64)(unsafe.Pointer(ptr)) = complex64(v)
...@@ -2319,7 +2319,7 @@ func cvtT2I(v Value, typ Type) Value { ...@@ -2319,7 +2319,7 @@ func cvtT2I(v Value, typ Type) Value {
if typ.NumMethod() == 0 { if typ.NumMethod() == 0 {
*target = x *target = x
} else { } else {
ifaceE2I(typ.runtimeType(), x, unsafe.Pointer(target)) ifaceE2I(typ.(*rtype), x, unsafe.Pointer(target))
} }
return Value{typ.common(), unsafe.Pointer(target), v.flag&flagRO | flagIndir | flag(Interface)<<flagKindShift} return Value{typ.common(), unsafe.Pointer(target), v.flag&flagRO | flagIndir | flag(Interface)<<flagKindShift}
} }
...@@ -2338,20 +2338,20 @@ func cvtI2I(v Value, typ Type) Value { ...@@ -2338,20 +2338,20 @@ func cvtI2I(v Value, typ Type) Value {
func chancap(ch iword) int func chancap(ch iword) int
func chanclose(ch iword) func chanclose(ch iword)
func chanlen(ch iword) int func chanlen(ch iword) int
func chanrecv(t *runtimeType, ch iword, nb bool) (val iword, selected, received bool) func chanrecv(t *rtype, ch iword, nb bool) (val iword, selected, received bool)
func chansend(t *runtimeType, ch iword, val iword, nb bool) bool func chansend(t *rtype, ch iword, val iword, nb bool) bool
func makechan(typ *runtimeType, size uint64) (ch iword) func makechan(typ *rtype, size uint64) (ch iword)
func makemap(t *runtimeType) (m iword) func makemap(t *rtype) (m iword)
func mapaccess(t *runtimeType, m iword, key iword) (val iword, ok bool) func mapaccess(t *rtype, m iword, key iword) (val iword, ok bool)
func mapassign(t *runtimeType, m iword, key, val iword, ok bool) func mapassign(t *rtype, m iword, key, val iword, ok bool)
func mapiterinit(t *runtimeType, m iword) *byte func mapiterinit(t *rtype, m iword) *byte
func mapiterkey(it *byte) (key iword, ok bool) func mapiterkey(it *byte) (key iword, ok bool)
func mapiternext(it *byte) func mapiternext(it *byte)
func maplen(m iword) int func maplen(m iword) int
func call(fn, arg unsafe.Pointer, n uint32) func call(fn, arg unsafe.Pointer, n uint32)
func ifaceE2I(t *runtimeType, src interface{}, dst unsafe.Pointer) func ifaceE2I(t *rtype, src interface{}, dst unsafe.Pointer)
// Dummy annotation marking that the value x escapes, // Dummy annotation marking that the value x escapes,
// for use in cases where the reflect code is so clever that // for use in cases where the reflect code is so clever that
......
...@@ -686,17 +686,10 @@ reflect·unsafe_Typeof(Eface e, Eface ret) ...@@ -686,17 +686,10 @@ reflect·unsafe_Typeof(Eface e, Eface ret)
} }
void void
reflect·unsafe_New(Eface typ, void *ret) reflect·unsafe_New(Type *t, void *ret)
{ {
Type *t;
uint32 flag; uint32 flag;
// Reflect library has reinterpreted typ
// as its own kind of type structure.
// We know that the pointer to the original
// type structure sits before the data pointer.
t = (Type*)((Eface*)typ.data-1);
flag = t->kind&KindNoPointers ? FlagNoPointers : 0; flag = t->kind&KindNoPointers ? FlagNoPointers : 0;
ret = runtime·mallocgc(t->size, flag, 1, 1); ret = runtime·mallocgc(t->size, flag, 1, 1);
...@@ -711,16 +704,9 @@ reflect·unsafe_New(Eface typ, void *ret) ...@@ -711,16 +704,9 @@ reflect·unsafe_New(Eface typ, void *ret)
} }
void void
reflect·unsafe_NewArray(Eface typ, intgo n, void *ret) reflect·unsafe_NewArray(Type *t, intgo n, void *ret)
{ {
uint64 size; uint64 size;
Type *t;
// Reflect library has reinterpreted typ
// as its own kind of type structure.
// We know that the pointer to the original
// type structure sits before the data pointer.
t = (Type*)((Eface*)typ.data-1);
size = n*t->size; size = n*t->size;
if(size == 0) if(size == 0)
...@@ -740,3 +726,14 @@ reflect·unsafe_NewArray(Eface typ, intgo n, void *ret) ...@@ -740,3 +726,14 @@ reflect·unsafe_NewArray(Eface typ, intgo n, void *ret)
FLUSH(&ret); FLUSH(&ret);
} }
void
reflect·typelinks(Slice ret)
{
extern Type *typelink[], *etypelink[];
static int32 first = 1;
ret.array = (byte*)typelink;
ret.len = etypelink - typelink;
ret.cap = ret.len;
FLUSH(&ret);
}
...@@ -149,8 +149,8 @@ goobjfile.pretty_printers.extend([makematcher(k) for k in vars().values() if has ...@@ -149,8 +149,8 @@ goobjfile.pretty_printers.extend([makematcher(k) for k in vars().values() if has
# #
# For reference, this is what we're trying to do: # For reference, this is what we're trying to do:
# eface: p *(*(struct 'runtime.commonType'*)'main.e'->type_->data)->string # eface: p *(*(struct 'runtime.rtype'*)'main.e'->type_->data)->string
# iface: p *(*(struct 'runtime.commonType'*)'main.s'->tab->Type->data)->string # iface: p *(*(struct 'runtime.rtype'*)'main.s'->tab->Type->data)->string
# #
# interface types can't be recognized by their name, instead we check # interface types can't be recognized by their name, instead we check
# if they have the expected fields. Unfortunately the mapping of # if they have the expected fields. Unfortunately the mapping of
...@@ -186,8 +186,7 @@ def lookup_type(name): ...@@ -186,8 +186,7 @@ def lookup_type(name):
except: except:
pass pass
_rctp_type = gdb.lookup_type("struct runtime.commonType").pointer() _rctp_type = gdb.lookup_type("struct runtime.rtype").pointer()
_rtp_type = gdb.lookup_type("struct runtime._type").pointer()
def iface_commontype(obj): def iface_commontype(obj):
if is_iface(obj): if is_iface(obj):
...@@ -196,18 +195,13 @@ def iface_commontype(obj): ...@@ -196,18 +195,13 @@ def iface_commontype(obj):
go_type_ptr = obj['_type'] go_type_ptr = obj['_type']
else: else:
return return
# sanity check: reflection type description ends in a loop.
tt = go_type_ptr['_type'].cast(_rtp_type).dereference()['_type']
if tt != tt.cast(_rtp_type).dereference()['_type']:
return
return go_type_ptr['ptr'].cast(_rctp_type).dereference() return go_type_ptr.cast(_rctp_type).dereference()
def iface_dtype(obj): def iface_dtype(obj):
"Decode type of the data field of an eface or iface struct." "Decode type of the data field of an eface or iface struct."
# known issue: dtype_name decoded from runtime.commonType is "nested.Foo" # known issue: dtype_name decoded from runtime.rtype is "nested.Foo"
# but the dwarf table lists it as "full/path/to/nested.Foo" # but the dwarf table lists it as "full/path/to/nested.Foo"
dynamic_go_type = iface_commontype(obj) dynamic_go_type = iface_commontype(obj)
......
...@@ -14,7 +14,7 @@ package runtime ...@@ -14,7 +14,7 @@ package runtime
import "unsafe" import "unsafe"
type commonType struct { type rtype struct {
size uintptr size uintptr
hash uint32 hash uint32
_ uint8 _ uint8
...@@ -25,14 +25,14 @@ type commonType struct { ...@@ -25,14 +25,14 @@ type commonType struct {
gc unsafe.Pointer gc unsafe.Pointer
string *string string *string
*uncommonType *uncommonType
ptrToThis *interface{} ptrToThis *rtype
} }
type _method struct { type _method struct {
name *string name *string
pkgPath *string pkgPath *string
mtyp *interface{} mtyp *rtype
typ *interface{} typ *rtype
ifn unsafe.Pointer ifn unsafe.Pointer
tfn unsafe.Pointer tfn unsafe.Pointer
} }
...@@ -46,10 +46,10 @@ type uncommonType struct { ...@@ -46,10 +46,10 @@ type uncommonType struct {
type _imethod struct { type _imethod struct {
name *string name *string
pkgPath *string pkgPath *string
typ *interface{} typ *rtype
} }
type interfaceType struct { type interfaceType struct {
commonType rtype
methods []_imethod methods []_imethod
} }
...@@ -5,13 +5,10 @@ ...@@ -5,13 +5,10 @@
/* /*
* Runtime type representation; master is type.go * Runtime type representation; master is type.go
* *
* The *Types here correspond 1-1 to type.go's *Type's, but are * The Type*s here correspond 1-1 to type.go's *rtype.
* prefixed with an extra header of 2 pointers, corresponding to the
* interface{} structure, which itself is called type Type again on
* the Go side.
*/ */
typedef struct CommonType CommonType; typedef struct Type Type;
typedef struct UncommonType UncommonType; typedef struct UncommonType UncommonType;
typedef struct InterfaceType InterfaceType; typedef struct InterfaceType InterfaceType;
typedef struct Method Method; typedef struct Method Method;
...@@ -21,7 +18,7 @@ typedef struct FuncType FuncType; ...@@ -21,7 +18,7 @@ typedef struct FuncType FuncType;
typedef struct PtrType PtrType; typedef struct PtrType PtrType;
// Needs to be in sync with typekind.h/CommonSize // Needs to be in sync with typekind.h/CommonSize
struct CommonType struct Type
{ {
uintptr size; uintptr size;
uint32 hash; uint32 hash;
...@@ -54,13 +51,6 @@ struct UncommonType ...@@ -54,13 +51,6 @@ struct UncommonType
Method m[]; Method m[];
}; };
struct Type
{
void *type; // interface{} value
void *ptr;
CommonType;
};
struct IMethod struct IMethod
{ {
String *name; String *name;
......
...@@ -35,7 +35,7 @@ enum { ...@@ -35,7 +35,7 @@ enum {
KindNoPointers = 1<<7, KindNoPointers = 1<<7,
// size of Type interface header + CommonType structure. // size of Type structure.
CommonSize = 2*PtrSize + 6*PtrSize + 8, CommonSize = 6*PtrSize + 8,
}; };
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