}
}
-// tflag is documented in ../../../../reflect/type.go.
-const tflagUncommon = 1
-
-// commonType
-// ../../../../runtime/type.go:/commonType
+// tflag is documented in reflect/type.go.
+//
+// tflag values must be kept in sync with copies in:
+// cmd/compile/internal/gc/reflect.go
+// cmd/link/internal/ld/decodesym.go
+// reflect/type.go
+// runtime/type.go
+const (
+ tflagUncommon = 1 << 0
+ tflagExtraStar = 1 << 1
+)
var dcommontype_algarray *Sym
+// dcommontype dumps the contents of a reflect.rtype (runtime._type).
func dcommontype(s *Sym, ot int, t *Type) int {
if ot != 0 {
Fatalf("dcommontype %d", ot)
// kind uint8
// alg *typeAlg
// gcdata *byte
- // string *string
+ // str nameOff
+ // _ int32
// }
ot = duintptr(s, ot, uint64(t.Width))
ot = duintptr(s, ot, uint64(ptrdata))
if uncommonSize(t) != 0 {
tflag |= tflagUncommon
}
+
+ exported := false
+ p := Tconv(t, FmtLeft|FmtUnsigned)
+ // If we're writing out type T,
+ // we are very likely to write out type *T as well.
+ // Use the string "*T"[1:] for "T", so that the two
+ // share storage. This is a cheap way to reduce the
+ // amount of space taken up by reflect strings.
+ if !strings.HasPrefix(p, "*") {
+ p = "*" + p
+ tflag |= tflagExtraStar
+ if t.Sym != nil {
+ exported = exportname(t.Sym.Name)
+ }
+ } else {
+ if t.Elem() != nil && t.Elem().Sym != nil {
+ exported = exportname(t.Elem().Sym.Name)
+ }
+ }
+
ot = duint8(s, ot, tflag)
// runtime (and common sense) expects alignment to be a power of two.
}
ot = dsymptr(s, ot, gcsym, 0) // gcdata
- p := Tconv(t, FmtLeft|FmtUnsigned)
-
- // If we're writing out type T,
- // we are very likely to write out type *T as well.
- // Use the string "*T"[1:] for "T", so that the two
- // share storage. This is a cheap way to reduce the
- // amount of space taken up by reflect strings.
- prefix := 0
- if !strings.HasPrefix(p, "*") {
- p = "*" + p
- prefix = 1
- }
- _, symdata := stringsym(p) // string
- ot = dsymptrLSym(Linksym(s), ot, symdata, prefix)
- ot = duintxx(s, ot, uint64(len(p)-prefix), Widthint)
+ nsym := dname(p, "", nil, exported)
+ ot = dsymptrOffLSym(Linksym(s), ot, nsym, 0)
+ ot = duint32(s, ot, 0)
return ot
}
case obj.STYPELINK:
// Sort typelinks by the rtype.string field so the reflect
// package can binary search type links.
- symsSort[i].name = string(decodetype_string(s.R[0].Sym))
+ symsSort[i].name = string(decodetype_str(s.R[0].Sym))
}
}
// ../../runtime/type.go, or more specifically, with what
// ../gc/reflect.c stuffs in these.
+// tflag is documented in reflect/type.go.
+//
+// tflag values must be kept in sync with copies in:
+// cmd/compile/internal/gc/reflect.go
+// cmd/link/internal/ld/decodesym.go
+// reflect/type.go
+// runtime/type.go
+const (
+ tflagUncommon = 1 << 0
+ tflagExtraStar = 1 << 1
+)
+
func decode_reloc(s *LSym, off int32) *Reloc {
for i := range s.R {
if s.R[i].Off == off {
}
}
-func commonsize() int { return 6*SysArch.PtrSize + 8 } // runtime._type
-func structfieldSize() int { return 3 * SysArch.PtrSize } // runtime.structfield
-func uncommonSize() int { return 2 * SysArch.PtrSize } // runtime.uncommontype
+func commonsize() int { return 4*SysArch.PtrSize + 8 + 8 } // runtime._type
+func structfieldSize() int { return 3 * SysArch.PtrSize } // runtime.structfield
+func uncommonSize() int { return 2 * SysArch.PtrSize } // runtime.uncommontype
// Type.commonType.kind
func decodetype_kind(s *LSym) uint8 {
// Type.commonType.tflag
func decodetype_hasUncommon(s *LSym) bool {
- const tflagUncommon = 1 // see ../../../../reflect/type.go:/^type.tflag
return s.P[2*SysArch.PtrSize+4]&tflagUncommon != 0
}
return off
}
-// decodetype_string returns the contents of an rtype's string field.
-func decodetype_string(s *LSym) []byte {
- off := 4*SysArch.PtrSize + 8
- strlen := int64(decode_inuxi(s.P[off+SysArch.PtrSize:], SysArch.IntSize))
-
- r := decode_reloc(s, int32(off))
- if r == nil {
- return nil
+// decodetype_str returns the contents of an rtype's str field (a nameOff).
+func decodetype_str(s *LSym) string {
+ str := decodetype_name(s, 4*SysArch.PtrSize+8)
+ if s.P[2*SysArch.PtrSize+4]&tflagExtraStar != 0 {
+ return str[1:]
}
- return r.Sym.P[r.Add : r.Add+strlen]
+ return str
}
// decodetype_name decodes the name from a reflect.name.
data := r.Sym.P
namelen := int(uint16(data[1]<<8) | uint16(data[2]))
return string(data[3 : 3+namelen])
-
}
func decodetype_structfieldname(s *LSym, i int) string {
},
{
field: StructField{Name: "", Type: TypeOf(ΦType{})},
- mustPanic: true, // TODO(sbinet): creating a struct with UTF-8 fields not supported
+ mustPanic: false,
exported: true,
},
{
field: StructField{Name: "", Type: TypeOf(φType{})},
- mustPanic: true, // TODO(sbinet): creating a struct with UTF-8 fields not supported
+ mustPanic: false,
exported: false,
},
{
}
}
+func TestExported(t *testing.T) {
+ type ΦExported struct{}
+ type φUnexported struct{}
+ type BigP *big
+ type P int
+ type p *P
+ type P2 p
+ type p3 p
+
+ type exportTest struct {
+ v interface{}
+ want bool
+ }
+ exportTests := []exportTest{
+ {D1{}, true},
+ {(*D1)(nil), true},
+ {big{}, false},
+ {(*big)(nil), false},
+ {(BigP)(nil), true},
+ {(*BigP)(nil), true},
+ {ΦExported{}, true},
+ {φUnexported{}, false},
+ {P(0), true},
+ {(p)(nil), false},
+ {(P2)(nil), true},
+ {(p3)(nil), false},
+ }
+
+ for i, test := range exportTests {
+ typ := TypeOf(test.v)
+ if got := IsExported(typ); got != test.want {
+ t.Errorf("%d: %s exported=%v, want %v", i, typ.Name(), got, test.want)
+ }
+ }
+}
+
type embed struct {
EmbedWithUnexpMeth
}
rodata := sections[i]
for _, off := range offs {
typ := (*rtype)(resolveTypeOff(unsafe.Pointer(rodata), off))
- r = append(r, typ.string)
+ r = append(r, typ.String())
}
}
return r
OtherExported int
otherUnexported int
}
+
+func IsExported(t Type) bool {
+ typ := t.(*rtype)
+ n := typ.nameOff(typ.str)
+ return n.isExported()
+}
// tflag is used by an rtype to signal what extra type information is
// available in the memory directly following the rtype value.
+//
+// tflag values must be kept in sync with copies in:
+// cmd/compile/internal/gc/reflect.go
+// cmd/link/internal/ld/decodesym.go
+// runtime/type.go
type tflag uint8
const (
// u uncommonType
// }
// u := &(*tUncommon)(unsafe.Pointer(t)).u
- tflagUncommon tflag = 1
+ tflagUncommon tflag = 1 << 0
+
+ // tflagExtraStar means the name in the str field has an
+ // extraneous '*' prefix. This is because for most types T in
+ // a program, the type *T also exists and reusing the str data
+ // saves binary size.
+ tflagExtraStar tflag = 1 << 1
)
// rtype is the common implementation of most values.
kind uint8 // enumeration for C
alg *typeAlg // algorithm table
gcdata *byte // garbage collection data
- string string // string form; unnecessary but undeniably useful
+ str nameOff // string form
+ _ int32 // unused; keeps rtype always a multiple of ptrSize
}
// a copy of runtime.typeAlg
// If the import path follows, then 4 bytes at the end of
// the data form a nameOff. The import path is only set for concrete
// methods that are defined in a different package than their type.
+//
+// If a name starts with "*", then the exported bit represents
+// whether the pointed to type is exported.
type name struct {
bytes *byte
}
}
}
-func (t *rtype) String() string { return t.string }
+func (t *rtype) String() string {
+ s := t.nameOff(t.str).name()
+ if t.tflag&tflagExtraStar != 0 {
+ return s[1:]
+ }
+ return s
+}
func (t *rtype) Size() uintptr { return t.size }
}
func (t *rtype) Name() string {
- if hasPrefix(t.string, "map[") {
+ s := t.String()
+ if hasPrefix(s, "map[") {
return ""
}
- if hasPrefix(t.string, "struct {") {
+ if hasPrefix(s, "struct {") {
return ""
}
- if hasPrefix(t.string, "chan ") {
+ if hasPrefix(s, "chan ") {
return ""
}
- if hasPrefix(t.string, "chan<-") {
+ if hasPrefix(s, "chan<-") {
return ""
}
- if hasPrefix(t.string, "func(") {
+ if hasPrefix(s, "func(") {
return ""
}
- switch t.string[0] {
+ switch s[0] {
case '[', '*', '<':
return ""
}
- i := len(t.string) - 1
+ i := len(s) - 1
for i >= 0 {
- if t.string[i] == '.' {
+ if s[i] == '.' {
break
}
i--
}
- return t.string[i+1:]
+ return s[i+1:]
}
func (t *rtype) ChanDir() ChanDir {
}
// Look in known types.
- s := "*" + t.string
+ s := "*" + t.String()
for _, tt := range typesByString(s) {
p = (*ptrType)(unsafe.Pointer(tt))
if p.elem == t {
prototype := *(**ptrType)(unsafe.Pointer(&iptr))
*p = *prototype
- p.string = s
+ p.str = resolveReflectName(newName(s, "", "", false))
// For the type structures linked into the binary, the
// compiler provides a good hash of the string.
//
// and
//
-// t1.string < t2.string
+// t1.String() < t2.String()
//
// Note that strings are not unique identifiers for types:
// there can be more than one with a given string.
section := sections[offsI]
// 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).
+ // This is a copy of sort.Search, with f(h) replaced by (*typ[h].String() >= s).
i, j := 0, len(offs)
for i < j {
h := i + (j-i)/2 // avoid overflow when computing h
// i ≤ h < j
- if !(rtypeOff(section, offs[h]).string >= s) {
+ if !(rtypeOff(section, offs[h]).String() >= s) {
i = h + 1 // preserves f(i-1) == false
} else {
j = h // preserves f(j) == true
// to do a linear scan anyway.
for j := i; j < len(offs); j++ {
typ := rtypeOff(section, offs[j])
- if typ.string != s {
+ if typ.String() != s {
break
}
ret = append(ret, typ)
lookupCache.Unlock()
panic("reflect.ChanOf: invalid dir")
case SendDir:
- s = "chan<- " + typ.string
+ s = "chan<- " + typ.String()
case RecvDir:
- s = "<-chan " + typ.string
+ s = "<-chan " + typ.String()
case BothDir:
- s = "chan " + typ.string
+ s = "chan " + typ.String()
}
for _, tt := range typesByString(s) {
ch := (*chanType)(unsafe.Pointer(tt))
ch := new(chanType)
*ch = *prototype
ch.dir = uintptr(dir)
- ch.string = s
+ ch.str = resolveReflectName(newName(s, "", "", false))
ch.hash = fnv1(typ.hash, 'c', byte(dir))
ch.elem = typ
}
// Look in known types.
- s := "map[" + ktyp.string + "]" + etyp.string
+ s := "map[" + ktyp.String() + "]" + etyp.String()
for _, tt := range typesByString(s) {
mt := (*mapType)(unsafe.Pointer(tt))
if mt.key == ktyp && mt.elem == etyp {
var imap interface{} = (map[unsafe.Pointer]unsafe.Pointer)(nil)
mt := new(mapType)
*mt = **(**mapType)(unsafe.Pointer(&imap))
- mt.string = s
+ mt.str = resolveReflectName(newName(s, "", "", false))
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
}
// Populate the remaining fields of ft and store in cache.
- ft.string = str
+ ft.str = resolveReflectName(newName(str, "", "", false))
funcLookupCache.m[hash] = append(funcLookupCache.m[hash], &ft.rtype)
return &ft.rtype
}
if ft.IsVariadic() && i == int(ft.inCount)-1 {
repr = append(repr, "..."...)
- repr = append(repr, (*sliceType)(unsafe.Pointer(t)).elem.string...)
+ repr = append(repr, (*sliceType)(unsafe.Pointer(t)).elem.String()...)
} else {
- repr = append(repr, t.string...)
+ repr = append(repr, t.String()...)
}
}
repr = append(repr, ')')
if i > 0 {
repr = append(repr, ", "...)
}
- repr = append(repr, t.string...)
+ repr = append(repr, t.String()...)
}
if len(out) > 1 {
repr = append(repr, ')')
b.ptrdata = ptrdata
b.kind = kind
b.gcdata = gcdata
- s := "bucket(" + ktyp.string + "," + etyp.string + ")"
- b.string = s
+ s := "bucket(" + ktyp.String() + "," + etyp.String() + ")"
+ b.str = resolveReflectName(newName(s, "", "", false))
return b
}
}
// Look in known types.
- s := "[]" + typ.string
+ s := "[]" + typ.String()
for _, tt := range typesByString(s) {
slice := (*sliceType)(unsafe.Pointer(tt))
if slice.elem == typ {
prototype := *(**sliceType)(unsafe.Pointer(&islice))
slice := new(sliceType)
*slice = *prototype
- slice.string = s
+ slice.str = resolveReflectName(newName(s, "", "", false))
slice.hash = fnv1(typ.hash, '[')
slice.elem = typ
// Embedded ** and *interface{} are illegal
elem := ft.Elem()
if k := elem.Kind(); k == Ptr || k == Interface {
- panic("reflect.StructOf: illegal anonymous field type " + ft.string)
+ panic("reflect.StructOf: illegal anonymous field type " + ft.String())
}
name = elem.String()
} else {
- name = ft.string
+ name = ft.String()
}
// TODO(sbinet) check for syntactically impossible type names?
hash = fnv1(hash, byte(ft.hash>>24), byte(ft.hash>>16), byte(ft.hash>>8), byte(ft.hash))
- repr = append(repr, (" " + ft.string)...)
+ repr = append(repr, (" " + ft.String())...)
if f.name.tagLen() > 0 {
hash = fnv1(hash, []byte(f.name.tag())...)
repr = append(repr, (" " + strconv.Quote(f.name.tag()))...)
}
}
- typ.string = str
+ typ.str = resolveReflectName(newName(str, "", "", false))
typ.hash = hash
typ.size = size
typ.align = typalign
func runtimeStructField(field StructField) structField {
exported := field.PkgPath == ""
if field.Name == "" {
- t := field.Type
+ t := field.Type.(*rtype)
if t.Kind() == Ptr {
- t = t.Elem()
+ t = t.Elem().(*rtype)
}
- exported = isExported(t.Name())
+ exported = t.nameOff(t.str).isExported()
} else if exported {
b0 := field.Name[0]
if ('a' <= b0 && b0 <= 'z') || b0 == '_' {
}
}
-func isExported(s string) bool {
- if s == "" {
- return false
- }
- // FIXME(sbinet): handle utf8/runes (see https://golang.org/issue/15064)
- // TODO: turn rtype.string into a reflect.name type, and put the exported
- // bit on there which can be checked here with field.Type.(*rtype).string.isExported()
- // When done, remove the documented limitation of StructOf.
- r := s[0]
- switch {
- case 'A' <= r && r <= 'Z':
- return true
- case r == '_' || 'a' <= r && r <= 'z':
- return false
- default:
- panic("reflect.StructOf: creating a struct with UTF-8 fields is not supported yet")
- }
-}
-
// typeptrdata returns the length in bytes of the prefix of t
// containing pointer data. Anything after this offset is scalar data.
// keep in sync with ../cmd/compile/internal/gc/reflect.go
}
// Look in known types.
- s := "[" + strconv.Itoa(count) + "]" + typ.string
+ s := "[" + strconv.Itoa(count) + "]" + typ.String()
for _, tt := range typesByString(s) {
array := (*arrayType)(unsafe.Pointer(tt))
if array.elem == typ {
prototype := *(**arrayType)(unsafe.Pointer(&iarray))
array := new(arrayType)
*array = *prototype
- array.string = s
+ array.str = resolveReflectName(newName(s, "", "", false))
array.hash = fnv1(typ.hash, '[')
for n := uint32(count); n > 0; n >>= 8 {
array.hash = fnv1(array.hash, byte(n))
var s string
if rcvr != nil {
- s = "methodargs(" + rcvr.string + ")(" + t.string + ")"
+ s = "methodargs(" + rcvr.String() + ")(" + t.String() + ")"
} else {
- s = "funcargs(" + t.string + ")"
+ s = "funcargs(" + t.String() + ")"
}
- x.string = s
+ x.str = resolveReflectName(newName(s, "", "", false))
// cache result for future callers
if layoutCache.m == nil {
t := tab._type
fn := t.alg.hash
if fn == nil {
- panic(errorString("hash of unhashable type " + t._string))
+ panic(errorString("hash of unhashable type " + t.string()))
}
if isDirectIface(t) {
return c1 * fn(unsafe.Pointer(&a.data), h^c0)
}
fn := t.alg.hash
if fn == nil {
- panic(errorString("hash of unhashable type " + t._string))
+ panic(errorString("hash of unhashable type " + t.string()))
}
if isDirectIface(t) {
return c1 * fn(unsafe.Pointer(&a.data), h^c0)
}
eq := t.alg.equal
if eq == nil {
- panic(errorString("comparing uncomparable type " + t._string))
+ panic(errorString("comparing uncomparable type " + t.string()))
}
if isDirectIface(t) {
return eq(noescape(unsafe.Pointer(&x.data)), noescape(unsafe.Pointer(&y.data)))
t := xtab._type
eq := t.alg.equal
if eq == nil {
- panic(errorString("comparing uncomparable type " + t._string))
+ panic(errorString("comparing uncomparable type " + t.string()))
}
if isDirectIface(t) {
return eq(noescape(unsafe.Pointer(&x.data)), noescape(unsafe.Pointer(&y.data)))
func typestring(x interface{}) string {
e := efaceOf(&x)
- return e._type._string
+ return e._type.string()
}
// For calling from C.
dumpint(uint64(uintptr(unsafe.Pointer(t))))
dumpint(uint64(t.size))
if x := t.uncommon(); x == nil || x.pkgpath.name() == "" {
- dumpstr(t._string)
+ dumpstr(t.string())
} else {
pkgpathstr := x.pkgpath.name()
pkgpath := stringStructOf(&pkgpathstr)
return nil
}
name := inter.typ.nameOff(inter.mhdr[0].name)
- panic(&TypeAssertionError{"", typ._string, inter.typ._string, name.name()})
+ panic(&TypeAssertionError{"", typ.string(), inter.typ.string(), name.name()})
}
h := itabhash(inter, typ)
if locked {
unlock(&ifaceLock)
}
- panic(&TypeAssertionError{"", typ._string, inter.typ._string, iname})
+ panic(&TypeAssertionError{"", typ.string(), inter.typ.string(), iname})
}
m.bad = 1
break
func panicdottype(have, want, iface *_type) {
haveString := ""
if have != nil {
- haveString = have._string
+ haveString = have.string()
}
- panic(&TypeAssertionError{iface._string, haveString, want._string, ""})
+ panic(&TypeAssertionError{iface.string(), haveString, want.string(), ""})
}
func assertI2T(t *_type, i iface, r unsafe.Pointer) {
tab := i.tab
if tab == nil {
- panic(&TypeAssertionError{"", "", t._string, ""})
+ panic(&TypeAssertionError{"", "", t.string(), ""})
}
if tab._type != t {
- panic(&TypeAssertionError{tab.inter.typ._string, tab._type._string, t._string, ""})
+ panic(&TypeAssertionError{tab.inter.typ.string(), tab._type.string(), t.string(), ""})
}
if r != nil {
if isDirectIface(t) {
func assertE2T(t *_type, e eface, r unsafe.Pointer) {
if e._type == nil {
- panic(&TypeAssertionError{"", "", t._string, ""})
+ panic(&TypeAssertionError{"", "", t.string(), ""})
}
if e._type != t {
- panic(&TypeAssertionError{"", e._type._string, t._string, ""})
+ panic(&TypeAssertionError{"", e._type.string(), t.string(), ""})
}
if r != nil {
if isDirectIface(t) {
tab := i.tab
if tab == nil {
// explicit conversions require non-nil interface value.
- panic(&TypeAssertionError{"", "", inter.typ._string, ""})
+ panic(&TypeAssertionError{"", "", inter.typ.string(), ""})
}
r._type = tab._type
r.data = i.data
tab := i.tab
if tab == nil {
// explicit conversions require non-nil interface value.
- panic(&TypeAssertionError{"", "", inter.typ._string, ""})
+ panic(&TypeAssertionError{"", "", inter.typ.string(), ""})
}
if tab.inter == inter {
r.tab = tab
t := e._type
if t == nil {
// explicit conversions require non-nil interface value.
- panic(&TypeAssertionError{"", "", inter.typ._string, ""})
+ panic(&TypeAssertionError{"", "", inter.typ.string(), ""})
}
r.tab = getitab(inter, t, false)
r.data = e.data
func assertE2E(inter *interfacetype, e eface, r *eface) {
if e._type == nil {
// explicit conversions require non-nil interface value.
- panic(&TypeAssertionError{"", "", inter.typ._string, ""})
+ panic(&TypeAssertionError{"", "", inter.typ.string(), ""})
}
*r = e
}
throw("runtime: typeBitsBulkBarrier without type")
}
if typ.size != size {
- println("runtime: typeBitsBulkBarrier with type ", typ._string, " of size ", typ.size, " but memory size", size)
+ println("runtime: typeBitsBulkBarrier with type ", typ.string(), " of size ", typ.size, " but memory size", size)
throw("runtime: invalid typeBitsBulkBarrier")
}
if typ.kind&kindGCProg != 0 {
- println("runtime: typeBitsBulkBarrier with type ", typ._string, " with GC prog")
+ println("runtime: typeBitsBulkBarrier with type ", typ.string(), " with GC prog")
throw("runtime: invalid typeBitsBulkBarrier")
}
if !writeBarrier.needed {
}
if nw == 0 {
// No pointers! Caller was supposed to check.
- println("runtime: invalid type ", typ._string)
+ println("runtime: invalid type ", typ.string())
throw("heapBitsSetType: called with non-pointer type")
return
}
if doubleCheck {
end := heapBitsForAddr(x + size)
if typ.kind&kindGCProg == 0 && (hbitp != end.bitp || (w == nw+2) != (end.shift == 2)) {
- println("ended at wrong bitmap byte for", typ._string, "x", dataSize/typ.size)
+ println("ended at wrong bitmap byte for", typ.string(), "x", dataSize/typ.size)
print("typ.size=", typ.size, " typ.ptrdata=", typ.ptrdata, " dataSize=", dataSize, " size=", size, "\n")
print("w=", w, " nw=", nw, " b=", hex(b), " nb=", nb, " hb=", hex(hb), "\n")
h0 := heapBitsForAddr(x)
}
}
if have != want {
- println("mismatch writing bits for", typ._string, "x", dataSize/typ.size)
+ println("mismatch writing bits for", typ.string(), "x", dataSize/typ.size)
print("typ.size=", typ.size, " typ.ptrdata=", typ.ptrdata, " dataSize=", dataSize, " size=", size, "\n")
print("kindGCProg=", typ.kind&kindGCProg != 0, "\n")
print("w=", w, " nw=", nw, " b=", hex(b), " nb=", nb, " hb=", hex(hb), "\n")
throw("runtime.SetFinalizer: first argument is nil")
}
if etyp.kind&kindMask != kindPtr {
- throw("runtime.SetFinalizer: first argument is " + etyp._string + ", not pointer")
+ throw("runtime.SetFinalizer: first argument is " + etyp.string() + ", not pointer")
}
ot := (*ptrtype)(unsafe.Pointer(etyp))
if ot.elem == nil {
}
if ftyp.kind&kindMask != kindFunc {
- throw("runtime.SetFinalizer: second argument is " + ftyp._string + ", not a function")
+ throw("runtime.SetFinalizer: second argument is " + ftyp.string() + ", not a function")
}
ft := (*functype)(unsafe.Pointer(ftyp))
if ft.dotdotdot() {
- throw("runtime.SetFinalizer: cannot pass " + etyp._string + " to finalizer " + ftyp._string + " because dotdotdot")
+ throw("runtime.SetFinalizer: cannot pass " + etyp.string() + " to finalizer " + ftyp.string() + " because dotdotdot")
}
if ft.dotdotdot() || ft.inCount != 1 {
- throw("runtime.SetFinalizer: cannot pass " + etyp._string + " to finalizer " + ftyp._string)
+ throw("runtime.SetFinalizer: cannot pass " + etyp.string() + " to finalizer " + ftyp.string())
}
fint := ft.in()[0]
switch {
goto okarg
}
}
- throw("runtime.SetFinalizer: cannot pass " + etyp._string + " to finalizer " + ftyp._string)
+ throw("runtime.SetFinalizer: cannot pass " + etyp.string() + " to finalizer " + ftyp.string())
okarg:
// compute size needed for return parameters
nret := uintptr(0)
if typ == nil {
print("tracealloc(", p, ", ", hex(size), ")\n")
} else {
- print("tracealloc(", p, ", ", hex(size), ", ", typ._string, ")\n")
+ print("tracealloc(", p, ", ", hex(size), ", ", typ.string(), ")\n")
}
if gp.m.curg == nil || gp == gp.m.curg {
goroutineheader(gp)
import "unsafe"
-// tflag is documented in ../reflect/type.go.
+// tflag is documented in reflect/type.go.
+//
+// tflag values must be kept in sync with copies in:
+// cmd/compile/internal/gc/reflect.go
+// cmd/link/internal/ld/decodesym.go
+// reflect/type.go
type tflag uint8
-const tflagUncommon tflag = 1
+const (
+ tflagUncommon tflag = 1 << 0
+ tflagExtraStar tflag = 1 << 1
+)
// Needs to be in sync with ../cmd/compile/internal/ld/decodesym.go:/^func.commonsize,
// ../cmd/compile/internal/gc/reflect.go:/^func.dcommontype and
// gcdata stores the GC type data for the garbage collector.
// If the KindGCProg bit is set in kind, gcdata is a GC program.
// Otherwise it is a ptrmask bitmap. See mbitmap.go for details.
- gcdata *byte
- _string string
+ gcdata *byte
+ str nameOff
+ _ int32
+}
+
+func (t *_type) string() string {
+ s := t.nameOff(t.str).name()
+ if t.tflag&tflagExtraStar != 0 {
+ return s[1:]
+ }
+ return s
}
func (t *_type) uncommon() *uncommontype {
}
func (t *_type) name() string {
- if hasPrefix(t._string, "map[") {
+ s := t.string()
+ if hasPrefix(s, "map[") {
return ""
}
- if hasPrefix(t._string, "struct {") {
+ if hasPrefix(s, "struct {") {
return ""
}
- if hasPrefix(t._string, "chan ") {
+ if hasPrefix(s, "chan ") {
return ""
}
- if hasPrefix(t._string, "chan<-") {
+ if hasPrefix(s, "chan<-") {
return ""
}
- if hasPrefix(t._string, "func(") {
+ if hasPrefix(s, "func(") {
return ""
}
- switch t._string[0] {
+ switch s[0] {
case '[', '*', '<':
return ""
}
- i := len(t._string) - 1
+ i := len(s) - 1
for i >= 0 {
- if t._string[i] == '.' {
+ if s[i] == '.' {
break
}
i--
}
- return t._string[i+1:]
+ return s[i+1:]
}
// reflectOffs holds type offsets defined at run time by the reflect package.
if kind != v.kind&kindMask {
return false
}
- if t._string != v._string {
+ if t.string() != v.string() {
return false
}
ut := t.uncommon()