Commit 1492e7db authored by David Crawshaw's avatar David Crawshaw

cmd/compile, etc: use nameOff for rtype string

linux/amd64:
	cmd/go:   -8KB (basically nothing)

linux/amd64 PIE:
	cmd/go: -191KB (1.6%)
	jujud:  -1.5MB (1.9%)

Updates #6853
Fixes #15064

Change-Id: I0adbb95685e28be92e8548741df0e11daa0a9b5f
Reviewed-on: https://go-review.googlesource.com/21777Reviewed-by: 's avatarIan Lance Taylor <iant@golang.org>
parent bb52ceaf
......@@ -788,14 +788,21 @@ func typeptrdata(t *Type) int64 {
}
}
// 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)
......@@ -836,7 +843,8 @@ func dcommontype(s *Sym, ot int, t *Type) int {
// kind uint8
// alg *typeAlg
// gcdata *byte
// string *string
// str nameOff
// _ int32
// }
ot = duintptr(s, ot, uint64(t.Width))
ot = duintptr(s, ot, uint64(ptrdata))
......@@ -847,6 +855,26 @@ func dcommontype(s *Sym, ot int, t *Type) int {
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.
......@@ -882,21 +910,9 @@ func dcommontype(s *Sym, ot int, t *Type) int {
}
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
}
......
......@@ -1832,7 +1832,7 @@ func dodataSect(symn int, syms []*LSym) (result []*LSym, maxAlign int32) {
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))
}
}
......
......@@ -16,6 +16,18 @@ import (
// ../../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 {
......@@ -47,9 +59,9 @@ func decode_inuxi(p []byte, sz int) uint64 {
}
}
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 {
......@@ -73,7 +85,6 @@ func decodetype_ptrdata(s *LSym) int64 {
// 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
}
......@@ -211,16 +222,13 @@ func decodetype_structfieldarrayoff(s *LSym, i int) int {
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.
......@@ -233,7 +241,6 @@ func decodetype_name(s *LSym, off int) string {
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 {
......
......@@ -4175,12 +4175,12 @@ func TestStructOfExportRules(t *testing.T) {
},
{
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,
},
{
......@@ -5674,6 +5674,42 @@ func TestNames(t *testing.T) {
}
}
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
}
......
......@@ -51,7 +51,7 @@ func TypeLinks() []string {
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
......@@ -103,3 +103,9 @@ type OtherPkgFields struct {
OtherExported int
otherUnexported int
}
func IsExported(t Type) bool {
typ := t.(*rtype)
n := typ.nameOff(typ.str)
return n.isExported()
}
This diff is collapsed.
......@@ -146,7 +146,7 @@ func interhash(p unsafe.Pointer, h uintptr) uintptr {
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)
......@@ -163,7 +163,7 @@ func nilinterhash(p unsafe.Pointer, h uintptr) uintptr {
}
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)
......@@ -221,7 +221,7 @@ func efaceeq(x, y eface) bool {
}
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)))
......@@ -239,7 +239,7 @@ func ifaceeq(x, y iface) bool {
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)))
......
......@@ -67,7 +67,7 @@ type stringer interface {
func typestring(x interface{}) string {
e := efaceOf(&x)
return e._type._string
return e._type.string()
}
// For calling from C.
......
......@@ -184,7 +184,7 @@ func dumptype(t *_type) {
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)
......
......@@ -38,7 +38,7 @@ func getitab(inter *interfacetype, typ *_type, canfail bool) *itab {
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)
......@@ -128,7 +128,7 @@ func additab(m *itab, locked, canfail bool) {
if locked {
unlock(&ifaceLock)
}
panic(&TypeAssertionError{"", typ._string, inter.typ._string, iname})
panic(&TypeAssertionError{"", typ.string(), inter.typ.string(), iname})
}
m.bad = 1
break
......@@ -196,18 +196,18 @@ func convT2I(tab *itab, elem unsafe.Pointer, x unsafe.Pointer) (i iface) {
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) {
......@@ -238,10 +238,10 @@ func assertI2T2(t *_type, i iface, r unsafe.Pointer) bool {
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) {
......@@ -285,7 +285,7 @@ func assertI2E(inter *interfacetype, i iface, r *eface) {
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
......@@ -322,7 +322,7 @@ func assertI2I(inter *interfacetype, i iface, r *iface) {
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
......@@ -361,7 +361,7 @@ func assertE2I(inter *interfacetype, e eface, r *iface) {
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
......@@ -402,7 +402,7 @@ func reflect_ifaceE2I(inter *interfacetype, e eface, dst *iface) {
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
}
......
......@@ -461,11 +461,11 @@ func typeBitsBulkBarrier(typ *_type, p, size uintptr) {
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 {
......@@ -916,7 +916,7 @@ func heapBitsSetType(x, size, dataSize uintptr, typ *_type) {
}
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
}
......@@ -1100,7 +1100,7 @@ Phase4:
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)
......@@ -1136,7 +1136,7 @@ Phase4:
}
}
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")
......
......@@ -274,7 +274,7 @@ func SetFinalizer(obj interface{}, finalizer interface{}) {
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 {
......@@ -328,14 +328,14 @@ func SetFinalizer(obj interface{}, finalizer interface{}) {
}
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 {
......@@ -358,7 +358,7 @@ func SetFinalizer(obj interface{}, finalizer interface{}) {
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)
......
......@@ -624,7 +624,7 @@ func tracealloc(p unsafe.Pointer, size uintptr, typ *_type) {
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)
......
......@@ -8,10 +8,18 @@ package runtime
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
......@@ -28,8 +36,17 @@ type _type struct {
// 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 {
......@@ -99,33 +116,34 @@ func hasPrefix(s, prefix string) bool {
}
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.
......@@ -497,7 +515,7 @@ func typesEqual(t, v *_type) bool {
if kind != v.kind&kindMask {
return false
}
if t._string != v._string {
if t.string() != v.string() {
return false
}
ut := t.uncommon()
......
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