EXTERN Pkg* runtimepkg; // package runtime
EXTERN Pkg* racepkg; // package runtime/race
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* unsafepkg; // package unsafe
EXTERN Pkg* trackpkg; // fake package for field tracking
weaktypepkg = mkpkg(strlit("go.weak.type"));
weaktypepkg->name = "go.weak.type";
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->name = "go.track";
[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
haspointers(Type *t)
{
Sym *sptr, *algsym;
static Sym *algarray;
char *p;
+
+ if(ot != 0)
+ fatal("dcommontype %d", ot);
sizeofAlg = 4*widthptr;
if(algarray == nil)
else
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
// actual type structure
// type commonType struct {
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*
typesymprefix(char *prefix, Type *t)
{
dtypesym(Type *t)
{
int ot, xt, n, isddd, dupok;
- Sym *s, *s1, *s2;
+ Sym *s, *s1, *s2, *slink;
Sig *a, *m;
Type *t1, *tbase, *t2;
}
ot = dextratype(s, ot, t, xt);
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;
}
sect->vaddr = 0;
datsize = 0;
s = datap;
- for(; s != nil && s->type < SGCDATA; s = s->next) {
+ for(; s != nil && s->type < STYPELINK; s = s->next) {
if(s->align != 0)
datsize = rnd(datsize, s->align);
s->type = SRODATA;
sect->len = datsize - sect->vaddr;
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 */
sect = addsection(&segtext, ".gcdata", 04);
sect->vaddr = datsize;
address(void)
{
Section *s, *text, *data, *rodata, *symtab, *pclntab, *noptr, *bss, *noptrbss;
- Section *gcdata, *gcbss;
+ Section *gcdata, *gcbss, *typelink;
Sym *sym, *sub;
uvlong va;
text = segtext.sect;
rodata = text->next;
- gcdata = rodata->next;
+ typelink = rodata->next;
+ gcdata = typelink->next;
gcbss = gcdata->next;
symtab = gcbss->next;
pclntab = symtab->next;
xdefine("etext", STEXT, text->vaddr + text->len);
xdefine("rodata", SRODATA, rodata->vaddr);
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("egcdata", SGCDATA, gcdata->vaddr + gcdata->len);
xdefine("gcbss", SGCBSS, gcbss->vaddr);
uint8
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
vlong
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
Sym*
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
newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, PtrSize, 0);
// 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.itab"));
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).
last = nil;
z = nil;
s->reachable = 1;
s->hide = 1;
}
-
+
// record field tracking references
fmtstrinit(&fmt);
for(s = allsym; s != S; s = s->allsym) {
SSTRING,
SGOSTRING,
SRODATA,
+ STYPELINK,
SGCDATA,
SGCBSS,
SSYMTAB,
// data.c:/^address will provide the actual values.
xdefine("text", STEXT, 0);
xdefine("etext", STEXT, 0);
+ xdefine("typelink", SRODATA, 0);
+ xdefine("etypelink", SRODATA, 0);
xdefine("rodata", SRODATA, 0);
xdefine("erodata", SRODATA, 0);
xdefine("gcdata", SGCDATA, 0);
s->type = STYPE;
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) {
s->type = SGOSTRING;
s->hide = 1;
}
}
+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 {
X int
Y int
func IsRO(v Value) bool {
return v.flag&flagRO != 0
}
+
+var ArrayOf = arrayOf
// References visible to the garbage collector.
// The code array below contains the same references
// embedded in the machine code.
- typ *commonType
+ typ *rtype
fn func([]Value) []Value
// code is the actual machine code invoked for the closure.
// It panics if i is not in the range [0, NumOut()).
Out(i int) Type
- runtimeType() *runtimeType
- common() *commonType
+ common() *rtype
uncommon() *uncommonType
}
UnsafePointer
)
-// The compiler can only construct empty interface values at
-// 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.
+// rtype is the common implementation of most values.
// It is embedded in other, public struct types, but always
// with a unique tag like `reflect:"array"` or `reflect:"ptr"`
// so that code cannot convert from, say, *arrayType to *ptrType.
-type commonType struct {
- size uintptr // size in bytes
- hash uint32 // hash of type; avoids computation in hash tables
- _ uint8 // unused/padding
- align uint8 // alignment of variable with this type
- fieldAlign uint8 // alignment of struct field with this type
- kind uint8 // enumeration for C
- alg *uintptr // algorithm table (../runtime/runtime.h:/Alg)
- gc uintptr // garbage collection data
- string *string // string form; unnecessary but undeniably useful
- *uncommonType // (relatively) uncommon fields
- ptrToThis *runtimeType // pointer to this type, if used in binary or has methods
+type rtype struct {
+ size uintptr // size in bytes
+ hash uint32 // hash of type; avoids computation in hash tables
+ _ uint8 // unused/padding
+ align uint8 // alignment of variable with this type
+ fieldAlign uint8 // alignment of struct field with this type
+ kind uint8 // enumeration for C
+ alg *uintptr // algorithm table (../runtime/runtime.h:/Alg)
+ gc uintptr // garbage collection data
+ string *string // string form; unnecessary but undeniably useful
+ *uncommonType // (relatively) uncommon fields
+ ptrToThis *rtype // type for pointer to this type, if used in binary or has methods
}
// Method on non-interface type
type method struct {
name *string // name of method
pkgPath *string // nil for exported Names; otherwise import path
- mtyp *runtimeType // method type (without receiver)
- typ *runtimeType // .(*FuncType) underneath (with receiver)
+ mtyp *rtype // method type (without receiver)
+ typ *rtype // .(*FuncType) underneath (with receiver)
ifn unsafe.Pointer // fn used in interface call (one-word receiver)
tfn unsafe.Pointer // fn used for normal method call
}
// arrayType represents a fixed array type.
type arrayType struct {
- commonType `reflect:"array"`
- elem *runtimeType // array element type
- slice *runtimeType // slice type
- len uintptr
+ rtype `reflect:"array"`
+ elem *rtype // array element type
+ slice *rtype // slice type
+ len uintptr
}
// chanType represents a channel type.
type chanType struct {
- commonType `reflect:"chan"`
- elem *runtimeType // channel element type
- dir uintptr // channel direction (ChanDir)
+ rtype `reflect:"chan"`
+ elem *rtype // channel element type
+ dir uintptr // channel direction (ChanDir)
}
// funcType represents a function type.
type funcType struct {
- commonType `reflect:"func"`
- dotdotdot bool // last input parameter is ...
- in []*runtimeType // input parameter types
- out []*runtimeType // output parameter types
+ rtype `reflect:"func"`
+ dotdotdot bool // last input parameter is ...
+ in []*rtype // input parameter types
+ out []*rtype // output parameter types
}
// imethod represents a method on an interface type
type imethod struct {
- name *string // name of method
- pkgPath *string // nil for exported Names; otherwise import path
- typ *runtimeType // .(*FuncType) underneath
+ name *string // name of method
+ pkgPath *string // nil for exported Names; otherwise import path
+ typ *rtype // .(*FuncType) underneath
}
// interfaceType represents an interface type.
type interfaceType struct {
- commonType `reflect:"interface"`
- methods []imethod // sorted by hash
+ rtype `reflect:"interface"`
+ methods []imethod // sorted by hash
}
// mapType represents a map type.
type mapType struct {
- commonType `reflect:"map"`
- key *runtimeType // map key type
- elem *runtimeType // map element (value) type
+ rtype `reflect:"map"`
+ key *rtype // map key type
+ elem *rtype // map element (value) type
}
// ptrType represents a pointer type.
type ptrType struct {
- commonType `reflect:"ptr"`
- elem *runtimeType // pointer element (pointed at) type
+ rtype `reflect:"ptr"`
+ elem *rtype // pointer element (pointed at) type
}
// sliceType represents a slice type.
type sliceType struct {
- commonType `reflect:"slice"`
- elem *runtimeType // slice element type
+ rtype `reflect:"slice"`
+ elem *rtype // slice element type
}
// Struct field
type structField struct {
- name *string // nil for embedded fields
- pkgPath *string // nil for exported Names; otherwise import path
- typ *runtimeType // type of field
- tag *string // nil if no tag
- offset uintptr // byte offset of field within struct
+ name *string // nil for embedded fields
+ pkgPath *string // nil for exported Names; otherwise import path
+ typ *rtype // type of field
+ tag *string // nil if no tag
+ offset uintptr // byte offset of field within struct
}
// structType represents a struct type.
type structType struct {
- commonType `reflect:"struct"`
- fields []structField // sorted by offset
+ rtype `reflect:"struct"`
+ fields []structField // sorted by offset
}
/*
return *t.name
}
-func (t *commonType) toType() Type {
- if t == nil {
- return nil
- }
- return t
-}
+func (t *rtype) String() string { return *t.string }
-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 *commonType) Bits() int {
+func (t *rtype) Bits() int {
if t == nil {
panic("reflect: Bits of nil Type")
}
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) {
if t == nil || i < 0 || i >= len(t.methods) {
m.PkgPath = *p.pkgPath
fl |= flagRO
}
- mt := toCommonType(p.typ)
+ mt := p.typ
m.Type = mt
fn := p.tfn
m.Func = Value{mt, fn, fl}
// TODO(rsc): 6g supplies these, but they are not
// as efficient as they could be: they have commonType
-// as the receiver instead of *commonType.
-func (t *commonType) NumMethod() int {
+// as the receiver instead of *rtype.
+func (t *rtype) NumMethod() int {
if t.Kind() == Interface {
tt := (*interfaceType)(unsafe.Pointer(t))
return tt.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 {
tt := (*interfaceType)(unsafe.Pointer(t))
return tt.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 {
tt := (*interfaceType)(unsafe.Pointer(t))
return tt.MethodByName(name)
return t.uncommonType.MethodByName(name)
}
-func (t *commonType) PkgPath() string {
+func (t *rtype) PkgPath() string {
return t.uncommonType.PkgPath()
}
-func (t *commonType) Name() string {
+func (t *rtype) Name() string {
return t.uncommonType.Name()
}
-func (t *commonType) ChanDir() ChanDir {
+func (t *rtype) ChanDir() ChanDir {
if t.Kind() != Chan {
panic("reflect: ChanDir of non-chan type")
}
return ChanDir(tt.dir)
}
-func (t *commonType) IsVariadic() bool {
+func (t *rtype) IsVariadic() bool {
if t.Kind() != Func {
panic("reflect: IsVariadic of non-func type")
}
return tt.dotdotdot
}
-func (t *commonType) Elem() Type {
+func (t *rtype) Elem() Type {
switch t.Kind() {
case Array:
tt := (*arrayType)(unsafe.Pointer(t))
panic("reflect: Elem of invalid type")
}
-func (t *commonType) Field(i int) StructField {
+func (t *rtype) Field(i int) StructField {
if t.Kind() != Struct {
panic("reflect: Field of non-struct type")
}
return tt.Field(i)
}
-func (t *commonType) FieldByIndex(index []int) StructField {
+func (t *rtype) FieldByIndex(index []int) StructField {
if t.Kind() != Struct {
panic("reflect: FieldByIndex of non-struct type")
}
return tt.FieldByIndex(index)
}
-func (t *commonType) FieldByName(name string) (StructField, bool) {
+func (t *rtype) FieldByName(name string) (StructField, bool) {
if t.Kind() != Struct {
panic("reflect: FieldByName of non-struct type")
}
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 {
panic("reflect: FieldByNameFunc of non-struct type")
}
return tt.FieldByNameFunc(match)
}
-func (t *commonType) In(i int) Type {
+func (t *rtype) In(i int) Type {
if t.Kind() != Func {
panic("reflect: In of non-func type")
}
return toType(tt.in[i])
}
-func (t *commonType) Key() Type {
+func (t *rtype) Key() Type {
if t.Kind() != Map {
panic("reflect: Key of non-map type")
}
return toType(tt.key)
}
-func (t *commonType) Len() int {
+func (t *rtype) Len() int {
if t.Kind() != Array {
panic("reflect: Len of non-array type")
}
return int(tt.len)
}
-func (t *commonType) NumField() int {
+func (t *rtype) NumField() int {
if t.Kind() != Struct {
panic("reflect: NumField of non-struct type")
}
return len(tt.fields)
}
-func (t *commonType) NumIn() int {
+func (t *rtype) NumIn() int {
if t.Kind() != Func {
panic("reflect: NumIn of non-func type")
}
return len(tt.in)
}
-func (t *commonType) NumOut() int {
+func (t *rtype) NumOut() int {
if t.Kind() != Func {
panic("reflect: NumOut of non-func type")
}
return len(tt.out)
}
-func (t *commonType) Out(i int) Type {
+func (t *rtype) Out(i int) Type {
if t.Kind() != Func {
panic("reflect: Out of non-func type")
}
// FieldByIndex returns the nested field corresponding to index.
func (t *structType) FieldByIndex(index []int) (f StructField) {
- f.Type = Type(t.toType())
+ f.Type = toType(&t.rtype)
for i, x := range index {
if i > 0 {
ft := f.Type
f := &t.fields[i]
// Find name and type for field f.
var fname string
- var ntyp *commonType
+ var ntyp *rtype
if f.name != nil {
fname = *f.name
} else {
// Anonymous field of type T or *T.
// Name taken from type.
- ntyp = toCommonType(f.typ)
+ ntyp = f.typ
if ntyp.Kind() == Ptr {
ntyp = ntyp.Elem().common()
}
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(nil) returns nil.
func TypeOf(i interface{}) Type {
// ptrMap is the cache for PtrTo.
var ptrMap struct {
sync.RWMutex
- m map[*commonType]*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)))
+ m map[*rtype]*ptrType
}
// PtrTo returns the pointer type with element t.
// For example, if t represents type Foo, PtrTo(t) represents *Foo.
func PtrTo(t Type) Type {
- return t.(*commonType).ptrTo()
+ return t.(*rtype).ptrTo()
}
-func (ct *commonType) ptrTo() *commonType {
- if p := ct.ptrToThis; p != nil {
- return toCommonType(p)
+func (t *rtype) ptrTo() *rtype {
+ if p := t.ptrToThis; p != nil {
+ return p
}
// Otherwise, synthesize one.
// the type structures in read-only memory.
ptrMap.RLock()
if m := ptrMap.m; m != nil {
- if p := m[ct]; p != nil {
+ if p := m[t]; p != nil {
ptrMap.RUnlock()
- return &p.commonType
+ return &p.rtype
}
}
ptrMap.RUnlock()
ptrMap.Lock()
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 {
// some other goroutine won the race and created it
ptrMap.Unlock()
- return &p.commonType
+ return &p.rtype
}
- var rt struct {
- i runtimeType
- ptrType
- }
- rt.i = &rt.commonType
+ // Create a new ptrType starting with the description
+ // of an *unsafe.Pointer.
+ p = new(ptrType)
+ var iptr interface{} = (*unsafe.Pointer)(nil)
+ prototype := *(**ptrType)(unsafe.Pointer(&iptr))
+ *p = *prototype
- // initialize p using *byte's ptrType as a prototype.
- p = &rt.ptrType
- var ibyte interface{} = (*byte)(nil)
- bp := (*ptrType)(unsafe.Pointer((**(**runtimeType)(unsafe.Pointer(&ibyte))).(*commonType)))
- *p = *bp
-
- s := "*" + *ct.string
+ s := "*" + *t.string
p.string = &s
// For the type structures linked into the binary, the
// Create a good hash for the new string by using
// the FNV-1 hash's mixing function to combine the
// old hash and the new "*".
- p.hash = ct.hash*16777619 ^ '*'
+ p.hash = fnv1(t.hash, '*')
p.uncommonType = 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()
- 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 {
panic("reflect: nil type passed to Type.Implements")
}
if u.Kind() != Interface {
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 {
panic("reflect: nil type passed to Type.AssignableTo")
}
- uu := u.(*commonType)
+ uu := u.(*rtype)
return directlyAssignable(uu, t) || implements(uu, t)
}
-func (t *commonType) ConvertibleTo(u Type) bool {
+func (t *rtype) ConvertibleTo(u Type) bool {
if u == nil {
panic("reflect: nil type passed to Type.ConvertibleTo")
}
- uu := u.(*commonType)
+ uu := u.(*rtype)
return convertOp(uu, t) != nil
}
// 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 {
return false
}
// http://golang.org/doc/go_spec.html#Assignability
// Ignoring the interface rules (implemented elsewhere)
// 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?
if T == V {
return true
return haveIdenticalUnderlyingType(T, V)
}
-func haveIdenticalUnderlyingType(T, V *commonType) bool {
+func haveIdenticalUnderlyingType(T, V *rtype) bool {
if T == V {
return true
}
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
+}
// direct operations.
type Value struct {
// typ holds the type of the value represented by a Value.
- typ *commonType
+ typ *rtype
// val holds the 1-word representation of the value.
// If flag's flagIndir bit is set, then val is a pointer to the data.
// emptyInterface is the header for an interface{} value.
type emptyInterface struct {
- typ *runtimeType
+ typ *rtype
word iword
}
type nonEmptyInterface struct {
// see ../runtime/iface.c:/Itab
itab *struct {
- ityp *runtimeType // static interface type
- typ *runtimeType // dynamic concrete type
+ ityp *rtype // static interface type
+ typ *rtype // dynamic concrete type
link unsafe.Pointer
bad int32
unused int32
if m.pkgPath != nil {
panic(method + " of unexported method")
}
- t = toCommonType(m.typ)
+ t = m.typ
iface := (*nonEmptyInterface)(v.val)
if iface.itab == nil {
panic(method + " of method on nil interface value")
panic(method + " of unexported method")
}
fn = m.ifn
- t = toCommonType(m.mtyp)
+ t = m.mtyp
rcvr = v.iword()
}
} else if v.flag&flagIndir != 0 {
}
for i, v := range in {
v.mustBeExported()
- targ := t.In(i).(*commonType)
+ targ := t.In(i).(*rtype)
a := uintptr(targ.align)
off = (off + a - 1) &^ (a - 1)
n := targ.size
off := uintptr(0)
in := make([]Value, 0, len(ftyp.in))
for _, arg := range ftyp.in {
- typ := toCommonType(arg)
+ typ := arg
off += -off & uintptr(typ.align-1)
v := Value{typ, nil, flag(typ.Kind()) << flagKindShift}
if typ.size <= ptrSize {
if len(ftyp.out) > 0 {
off += -off & (ptrSize - 1)
for i, arg := range ftyp.out {
- typ := toCommonType(arg)
+ typ := arg
v := out[i]
if v.typ != typ {
panic("reflect: function created by MakeFunc using " + funcName(f) +
switch k {
case Interface:
var (
- typ *commonType
+ typ *rtype
val unsafe.Pointer
)
if v.typ.NumMethod() == 0 {
// nil interface value
return Value{}
}
- typ = toCommonType(eface.typ)
+ typ = eface.typ
val = unsafe.Pointer(eface.word)
} else {
iface := (*nonEmptyInterface)(v.val)
// nil interface value
return Value{}
}
- typ = toCommonType(iface.itab.typ)
+ typ = iface.itab.typ
val = unsafe.Pointer(iface.word)
}
fl := v.flag & flagRO
return Value{}
}
tt := (*ptrType)(unsafe.Pointer(v.typ))
- typ := toCommonType(tt.elem)
+ typ := tt.elem
fl := v.flag&flagRO | flagIndir | flagAddr
fl |= flag(typ.Kind() << flagKindShift)
return Value{typ, val, fl}
panic("reflect: Field index out of range")
}
field := &tt.fields[i]
- typ := toCommonType(field.typ)
+ typ := field.typ
// Inherit permission bits from v.
fl := v.flag & (flagRO | flagIndir | flagAddr)
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.
// It panics if v's Kind is not Array, Slice, or String or i is out of range.
if i < 0 || i > int(tt.len) {
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 |= flag(typ.Kind()) << flagKindShift
offset := uintptr(i) * typ.size
panic("reflect: slice index out of range")
}
tt := (*sliceType)(unsafe.Pointer(v.typ))
- typ := toCommonType(tt.elem)
+ typ := tt.elem
fl |= flag(typ.Kind()) << flagKindShift
val := unsafe.Pointer(s.Data + uintptr(i)*typ.size)
return Value{typ, val, fl}
// Non-interface value.
var eface emptyInterface
- eface.typ = v.typ.runtimeType()
+ eface.typ = v.typ
eface.word = v.iword()
if v.flag&flagIndir != 0 && v.typ.size > ptrSize {
// considered unexported. This is consistent with the
// behavior for structs, which allow read but not write
// 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 {
return Value{}
}
- typ := toCommonType(tt.elem)
+ typ := tt.elem
fl := (v.flag | key.flag) & flagRO
if typ.size > ptrSize {
fl |= flagIndir
func (v Value) MapKeys() []Value {
v.mustBe(Map)
tt := (*mapType)(unsafe.Pointer(v.typ))
- keyType := toCommonType(tt.key)
+ keyType := tt.key
fl := v.flag & flagRO
fl |= flag(keyType.Kind()) << flagKindShift
if m != nil {
mlen = maplen(m)
}
- it := mapiterinit(v.typ.runtimeType(), m)
+ it := mapiterinit(v.typ, m)
a := make([]Value, mlen)
var i int
for i = 0; i < len(a); i++ {
if ChanDir(tt.dir)&RecvDir == 0 {
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 {
- typ := toCommonType(tt.elem)
+ typ := tt.elem
fl := flag(typ.Kind()) << flagKindShift
if typ.size > ptrSize {
fl |= flagIndir
panic("send on recv-only channel")
}
x.mustBeExported()
- x = x.assignTo("reflect.Value.Send", toCommonType(tt.elem), nil)
- return chansend(v.typ.runtimeType(), v.iword(), x.iword(), nb)
+ x = x.assignTo("reflect.Value.Send", tt.elem, nil)
+ return chansend(v.typ, v.iword(), x.iword(), nb)
}
// Set assigns x to the value v.
v.mustBeExported()
key.mustBeExported()
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 {
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.
}
tt := (*arrayType)(unsafe.Pointer(v.typ))
cap = int(tt.len)
- typ = (*sliceType)(unsafe.Pointer(toCommonType(tt.slice)))
+ typ = (*sliceType)(unsafe.Pointer(tt.slice))
base = v.val
case Slice:
// Reinterpret as *SliceHeader to edit.
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.Cap = cap - beg
panic("reflect: broken Value")
}
m := &tt.methods[i]
- return toCommonType(m.typ)
+ return m.typ
}
// Method on concrete type.
ut := v.typ.uncommon()
panic("reflect: broken Value")
}
m := &ut.methods[i]
- return toCommonType(m.mtyp)
+ return m.mtyp
}
// Uint returns v's underlying value, as a uint64.
// A runtimeSelect is a single case passed to rselect.
// This must match ../runtime/chan.c:/runtimeSelect
type runtimeSelect struct {
- dir uintptr // 0, SendDir, or RecvDir
- typ *runtimeType // channel type
- ch iword // interface word for channel
- val iword // interface word for value (for SendDir)
+ dir uintptr // 0, SendDir, or RecvDir
+ typ *rtype // channel type
+ ch iword // interface word for channel
+ val iword // interface word for value (for SendDir)
}
// rselect runs a select. It returns the index of the chosen case,
panic("reflect.Select: SendDir case using recv-only channel")
}
rc.ch = ch.iword()
- rc.typ = tt.runtimeType()
+ rc.typ = &tt.rtype
v := c.Send
if !v.IsValid() {
panic("reflect.Select: SendDir case missing Send value")
}
v.mustBeExported()
- v = v.assignTo("reflect.Select", toCommonType(tt.elem), nil)
+ v = v.assignTo("reflect.Select", tt.elem, nil)
rc.val = v.iword()
case SelectRecv:
ch.mustBe(Chan)
ch.mustBeExported()
tt := (*chanType)(unsafe.Pointer(ch.typ))
- rc.typ = tt.runtimeType()
+ rc.typ = &tt.rtype
if ChanDir(tt.dir)&RecvDir == 0 {
panic("reflect.Select: RecvDir case using send-only channel")
}
chosen, word, recvOK := rselect(runcases)
if runcases[chosen].dir == uintptr(SelectRecv) {
- tt := (*chanType)(unsafe.Pointer(toCommonType(runcases[chosen].typ)))
- typ := toCommonType(tt.elem)
+ tt := (*chanType)(unsafe.Pointer(runcases[chosen].typ))
+ typ := tt.elem
fl := flag(typ.Kind()) << flagKindShift
if typ.size > ptrSize {
fl |= flagIndir
*/
// implemented in package runtime
-func unsafe_New(Type) unsafe.Pointer
-func unsafe_NewArray(Type, int) unsafe.Pointer
+func unsafe_New(*rtype) unsafe.Pointer
+func unsafe_NewArray(*rtype, int) unsafe.Pointer
// MakeSlice creates a new zero-initialized slice value
// for the specified slice type, length, and capacity.
// Reinterpret as *SliceHeader to edit.
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.Cap = cap
if typ.ChanDir() != BothDir {
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}
}
if typ.Kind() != Map {
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}
}
// For an interface value with the noAddr bit set,
// the representation is identical to an empty interface.
eface := *(*emptyInterface)(unsafe.Pointer(&i))
- typ := toCommonType(eface.typ)
+ typ := eface.typ
fl := flag(typ.Kind()) << flagKindShift
if typ.size > ptrSize {
fl |= flagIndir
if t.size <= ptrSize {
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
if typ == nil {
panic("reflect: New(nil)")
}
- ptr := unsafe_New(typ)
+ ptr := unsafe_New(typ.(*rtype))
fl := flag(Ptr) << flagKindShift
return Value{typ.common().ptrTo(), ptr, fl}
}
// assignTo returns a value v that can be assigned directly 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.
-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 {
panic(context + ": cannot assign method value to type " + dst.String())
}
if dst.NumMethod() == 0 {
*target = x
} else {
- ifaceE2I(dst.runtimeType(), x, unsafe.Pointer(target))
+ ifaceE2I(dst, x, unsafe.Pointer(target))
}
return Value{dst, unsafe.Pointer(target), flagIndir | flag(Interface)<<flagKindShift}
}
// 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.
-func convertOp(dst, src *commonType) func(Value, Type) Value {
+func convertOp(dst, src *rtype) func(Value, Type) Value {
switch src.Kind() {
case Int, Int8, Int16, Int32, Int64:
switch dst.Kind() {
typ := t.common()
if typ.size > ptrSize {
// Assume ptrSize >= 4, so this must be uint64.
- ptr := unsafe_New(t)
+ ptr := unsafe_New(typ)
*(*uint64)(unsafe.Pointer(ptr)) = bits
return Value{typ, ptr, f | flag(typ.Kind())<<flagKindShift}
}
typ := t.common()
if typ.size > ptrSize {
// Assume ptrSize >= 4, so this must be float64.
- ptr := unsafe_New(t)
+ ptr := unsafe_New(typ)
*(*float64)(unsafe.Pointer(ptr)) = v
return Value{typ, ptr, f | flag(typ.Kind())<<flagKindShift}
}
func makeComplex(f flag, v complex128, t Type) Value {
typ := t.common()
if typ.size > ptrSize {
- ptr := unsafe_New(t)
+ ptr := unsafe_New(typ)
switch typ.size {
case 8:
*(*complex64)(unsafe.Pointer(ptr)) = complex64(v)
if typ.NumMethod() == 0 {
*target = x
} 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}
}
func chancap(ch iword) int
func chanclose(ch iword)
func chanlen(ch iword) int
-func chanrecv(t *runtimeType, ch iword, nb bool) (val iword, selected, received bool)
-func chansend(t *runtimeType, ch iword, val iword, nb bool) bool
-
-func makechan(typ *runtimeType, size uint64) (ch iword)
-func makemap(t *runtimeType) (m iword)
-func mapaccess(t *runtimeType, m iword, key iword) (val iword, ok bool)
-func mapassign(t *runtimeType, m iword, key, val iword, ok bool)
-func mapiterinit(t *runtimeType, m iword) *byte
+func chanrecv(t *rtype, ch iword, nb bool) (val iword, selected, received bool)
+func chansend(t *rtype, ch iword, val iword, nb bool) bool
+
+func makechan(typ *rtype, size uint64) (ch iword)
+func makemap(t *rtype) (m iword)
+func mapaccess(t *rtype, m iword, key iword) (val iword, ok bool)
+func mapassign(t *rtype, m iword, key, val iword, ok bool)
+func mapiterinit(t *rtype, m iword) *byte
func mapiterkey(it *byte) (key iword, ok bool)
func mapiternext(it *byte)
func maplen(m iword) int
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,
// for use in cases where the reflect code is so clever that
}
void
-reflect·unsafe_New(Eface typ, void *ret)
+reflect·unsafe_New(Type *t, void *ret)
{
- Type *t;
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;
ret = runtime·mallocgc(t->size, flag, 1, 1);
}
void
-reflect·unsafe_NewArray(Eface typ, intgo n, void *ret)
+reflect·unsafe_NewArray(Type *t, intgo n, void *ret)
{
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;
if(size == 0)
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);
+}
#
# For reference, this is what we're trying to do:
-# eface: p *(*(struct 'runtime.commonType'*)'main.e'->type_->data)->string
-# iface: p *(*(struct 'runtime.commonType'*)'main.s'->tab->Type->data)->string
+# eface: p *(*(struct 'runtime.rtype'*)'main.e'->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
# if they have the expected fields. Unfortunately the mapping of
except:
pass
-_rctp_type = gdb.lookup_type("struct runtime.commonType").pointer()
-_rtp_type = gdb.lookup_type("struct runtime._type").pointer()
+_rctp_type = gdb.lookup_type("struct runtime.rtype").pointer()
def iface_commontype(obj):
if is_iface(obj):
go_type_ptr = obj['_type']
else:
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):
"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"
dynamic_go_type = iface_commontype(obj)
import "unsafe"
-type commonType struct {
+type rtype struct {
size uintptr
hash uint32
_ uint8
gc unsafe.Pointer
string *string
*uncommonType
- ptrToThis *interface{}
+ ptrToThis *rtype
}
type _method struct {
name *string
pkgPath *string
- mtyp *interface{}
- typ *interface{}
+ mtyp *rtype
+ typ *rtype
ifn unsafe.Pointer
tfn unsafe.Pointer
}
type _imethod struct {
name *string
pkgPath *string
- typ *interface{}
+ typ *rtype
}
type interfaceType struct {
- commonType
+ rtype
methods []_imethod
}
/*
* Runtime type representation; master is type.go
*
- * The *Types here correspond 1-1 to type.go's *Type's, but are
- * prefixed with an extra header of 2 pointers, corresponding to the
- * interface{} structure, which itself is called type Type again on
- * the Go side.
+ * The Type*s here correspond 1-1 to type.go's *rtype.
*/
-typedef struct CommonType CommonType;
+typedef struct Type Type;
typedef struct UncommonType UncommonType;
typedef struct InterfaceType InterfaceType;
typedef struct Method Method;
typedef struct PtrType PtrType;
// Needs to be in sync with typekind.h/CommonSize
-struct CommonType
+struct Type
{
uintptr size;
uint32 hash;
Method m[];
};
-struct Type
-{
- void *type; // interface{} value
- void *ptr;
- CommonType;
-};
-
struct IMethod
{
String *name;
KindNoPointers = 1<<7,
- // size of Type interface header + CommonType structure.
- CommonSize = 2*PtrSize + 6*PtrSize + 8,
+ // size of Type structure.
+ CommonSize = 6*PtrSize + 8,
};