[dev.typeparams] cmd/compile: ensure methods of generic types survive linker pruning

Calling MarkTypeUsedInInterface before inlining is problematic (when
using the containing function as the reference source), because we end
up attaching a relocation to the original function, which is then
deadcode removed because all instances of it were inlined. (All other
current uses of MarkTypeUsedInInterface happen after inlining, so they
don't have this problem.)

Instead, attach the relocation to the dictionary in which the type
appears.  This should always work, because if the dictionary is ever
deadcode eliminated, then the type can never be put in an interface,
which means we indeed don't need its methods.

This CL is a bit overkill, as not *all* types in the dictionary need
this mark, but it is sufficient for now.

Change-Id: I2d39456691f1c3df8efe3bddc3b9017e0ef37a7f
Reviewed-on: https://go-review.googlesource.com/c/go/+/336012
Trust: Keith Randall <khr@golang.org>
Trust: Dan Scales <danscales@google.com>
Reviewed-by: Dan Scales <danscales@google.com>
This commit is contained in:
Keith Randall 2021-07-20 12:55:51 -07:00
parent 73af5f718f
commit 2fe4b14795

View file

@ -566,7 +566,6 @@ const UINTSTRING = "u8" // XX fix for 32-bit arch
// buf. fieldSym is the sym of the field associated with type t, if it is in a
// struct. fieldSym could be used to have special naming for blank fields, etc.
func accumGcshape(fl []*types.Field, buf *bytes.Buffer, t *types.Type, fieldSym *types.Sym) []*types.Field {
// t.Kind() is already the kind of the underlying type, so no need to
// reference t.Underlying() to reference the underlying type.
assert(t.Kind() == t.Underlying().Kind())
@ -1220,7 +1219,6 @@ func (subst *subster) node(n ir.Node) ir.Node {
dst := subst.concretify.Typ(subst.shape2param[src].Bound())
// Mark that we use the methods of this concrete type.
// Otherwise the linker deadcode-eliminates them :(
reflectdata.MarkTypeUsedInInterface(subst.unshapifyTyp(src), subst.newf.Sym().Linksym())
ix := subst.findDictType(subst.shape2param[src])
assert(ix >= 0)
mse.X = subst.convertUsingDictionary(m.Pos(), mse.X, dst, subst.shape2param[src], ix)
@ -1566,6 +1564,11 @@ func (g *irgen) getDictionarySym(gf *ir.Name, targs []*types.Type, isMeth bool)
infoPrint(" * %v\n", t)
s := reflectdata.TypeLinksym(t)
off = objw.SymPtr(lsym, off, s, 0)
// Ensure that methods on t don't get deadcode eliminated
// by the linker.
// TODO: This is somewhat overkill, we really only need it
// for types that are put into interfaces.
reflectdata.MarkTypeUsedInInterface(t, lsym)
}
subst := typecheck.Tsubster{
Tparams: info.tparams,
@ -1577,6 +1580,7 @@ func (g *irgen) getDictionarySym(gf *ir.Name, targs []*types.Type, isMeth bool)
infoPrint(" - %v\n", ts)
s := reflectdata.TypeLinksym(ts)
off = objw.SymPtr(lsym, off, s, 0)
reflectdata.MarkTypeUsedInInterface(ts, lsym)
}
// Emit an entry for each subdictionary (after substituting targs)
for _, n := range info.subDictCalls {