aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/link/internal/ld/deadcode.go
diff options
context:
space:
mode:
authorCherry Zhang <cherryyz@google.com>2020-06-08 18:38:59 -0400
committerCherry Zhang <cherryyz@google.com>2020-06-11 22:32:49 +0000
commit95848fc5c64cde2e0fc95348a861e3cab98feaa7 (patch)
treee8007638bbd2a336045c338c326e596f9f29ed9a /src/cmd/link/internal/ld/deadcode.go
parent3187b05b87e39231202bf2a9bf89905649472b6c (diff)
downloadgo-95848fc5c64cde2e0fc95348a861e3cab98feaa7.tar.gz
go-95848fc5c64cde2e0fc95348a861e3cab98feaa7.zip
[dev.link] cmd/compile, cmd/link: remove dead methods if type is not used in interface
Currently, a method of a reachable type is live if it matches a method of a reachable interface. In fact, we only need to retain the method if the type is actually converted to an interface. If the type is never converted to an interface, there is no way to call the method through an interface method call (but the type descriptor could still be used, e.g. in calling runtime.newobject). A type can be used in an interface in two ways: - directly converted to interface. (Any interface counts, as it is possible to convert one interface to another.) - obtained by reflection from a related type (e.g. obtaining an interface of T from []T). For the former, we let the compiler emit a marker on the type descriptor symbol when it is converted to an interface. In the linker, we only need to check methods of marked types. For the latter, when the linker visits a marked type, it needs to visit all its "child" types as marked (i.e. potentially could be converted to interface). This reduces binary size: cmd/compile 18792016 18706096 (-0.5%) cmd/go 14120572 13398948 (-5.1%) Change-Id: I4465c7eeabf575f4dc84017214c610fa05ae31fd Reviewed-on: https://go-review.googlesource.com/c/go/+/237298 Run-TryBot: Cherry Zhang <cherryyz@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Than McIntosh <thanm@google.com> Reviewed-by: Jeremy Faller <jeremy@golang.org>
Diffstat (limited to 'src/cmd/link/internal/ld/deadcode.go')
-rw-r--r--src/cmd/link/internal/ld/deadcode.go24
1 files changed, 22 insertions, 2 deletions
diff --git a/src/cmd/link/internal/ld/deadcode.go b/src/cmd/link/internal/ld/deadcode.go
index d59b1f2c65..1060bbca3b 100644
--- a/src/cmd/link/internal/ld/deadcode.go
+++ b/src/cmd/link/internal/ld/deadcode.go
@@ -102,8 +102,10 @@ func (d *deadcodePass) flood() {
isgotype := d.ldr.IsGoType(symIdx)
relocs := d.ldr.Relocs(symIdx)
+ var usedInIface bool
if isgotype {
+ usedInIface = d.ldr.AttrUsedInIface(symIdx)
p := d.ldr.Data(symIdx)
if len(p) != 0 && decodetypeKind(d.ctxt.Arch, p)&kindMask == kindInterface {
for _, sig := range d.decodeIfaceMethods(d.ldr, d.ctxt.Arch, symIdx, &relocs) {
@@ -126,7 +128,9 @@ func (d *deadcodePass) flood() {
if i+2 >= relocs.Count() {
panic("expect three consecutive R_METHODOFF relocs")
}
- methods = append(methods, methodref{src: symIdx, r: i})
+ if usedInIface {
+ methods = append(methods, methodref{src: symIdx, r: i})
+ }
i += 2
continue
}
@@ -136,7 +140,23 @@ func (d *deadcodePass) flood() {
// do nothing for now as we still load all type symbols.
continue
}
- d.mark(r.Sym(), symIdx)
+ rs := r.Sym()
+ if isgotype && usedInIface && d.ldr.IsGoType(rs) && !d.ldr.AttrUsedInIface(rs) {
+ // If a type is converted to an interface, it is possible to obtain an
+ // interface with a "child" type of it using reflection (e.g. obtain an
+ // interface of T from []chan T). We need to traverse its "child" types
+ // with UsedInIface attribute set.
+ // When visiting the child type (chan T in the example above), it will
+ // have UsedInIface set, so it in turn will mark and (re)visit its children
+ // (e.g. T above).
+ // We unset the reachable bit here, so if the child type is already visited,
+ // it will be visited again.
+ // Note that a type symbol can be visited at most twice, one without
+ // UsedInIface and one with. So termination is still guaranteed.
+ d.ldr.SetAttrUsedInIface(rs, true)
+ d.ldr.SetAttrReachable(rs, false)
+ }
+ d.mark(rs, symIdx)
}
naux := d.ldr.NAux(symIdx)
for i := 0; i < naux; i++ {