From 2fe4b14795fe20fa3ba8efbe92b88f2d564509d2 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Tue, 20 Jul 2021 12:55:51 -0700 Subject: [PATCH] [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 Trust: Dan Scales Reviewed-by: Dan Scales --- src/cmd/compile/internal/noder/stencil.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go index 905ea0c88c..9e0f198262 100644 --- a/src/cmd/compile/internal/noder/stencil.go +++ b/src/cmd/compile/internal/noder/stencil.go @@ -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 {