cc = 1 // this appears to yield better performance than 0.
}
- visitor := hairyVisitor{budget: inlineMaxBudget, extraCallCost: cc}
+ // At this point in the game the function we're looking at may
+ // have "stale" autos, vars that still appear in the Dcl list, but
+ // which no longer have any uses in the function body (due to
+ // elimination by deadcode). We'd like to exclude these dead vars
+ // when creating the "Inline.Dcl" field below; to accomplish this,
+ // the hairyVisitor below builds up a map of used/referenced
+ // locals, and we use this map to produce a pruned Inline.Dcl
+ // list. See issue 25249 for more context.
+
+ visitor := hairyVisitor{
+ budget: inlineMaxBudget,
+ extraCallCost: cc,
+ usedLocals: make(map[*Node]bool),
+ }
if visitor.visitList(fn.Nbody) {
reason = visitor.reason
return
n.Func.Inl = &Inline{
Cost: inlineMaxBudget - visitor.budget,
- Dcl: inlcopylist(n.Name.Defn.Func.Dcl),
+ Dcl: inlcopylist(pruneUnusedAutos(n.Name.Defn.Func.Dcl, &visitor)),
Body: inlcopylist(fn.Nbody.Slice()),
}
budget int32
reason string
extraCallCost int32
+ usedLocals map[*Node]bool
}
// Look for anything we want to punt on.
return v.visitList(n.Ninit) || v.visitList(n.Nbody) ||
v.visitList(n.Rlist)
}
+
+ case ONAME:
+ if n.Class() == PAUTO {
+ v.usedLocals[n] = true
+ }
+
}
v.budget--
pos.SetBase(newbase)
return Ctxt.PosTable.XPos(pos)
}
+
+func pruneUnusedAutos(ll []*Node, vis *hairyVisitor) []*Node {
+ s := make([]*Node, 0, len(ll))
+ for _, n := range ll {
+ if n.Class() == PAUTO {
+ if _, found := vis.usedLocals[n]; !found {
+ continue
+ }
+ }
+ s = append(s, n)
+ }
+ return s
+}
)
const (
- NoOpt = "-gcflags=-l -N"
- OptInl4 = "-gcflags=all=-l=4"
- OptInl4DwLoc = "-gcflags=all=-l=4 -dwarflocationlists"
+ DefaultOpt = "-gcflags="
+ NoOpt = "-gcflags=-l -N"
+ OptInl4 = "-gcflags=all=-l=4"
)
func TestRuntimeTypesPresent(t *testing.T) {
return &builtFile{f, dst}
}
+func envWithGoPathSet(gp string) []string {
+ env := os.Environ()
+ for i := 0; i < len(env); i++ {
+ if strings.HasPrefix(env[i], "GOPATH=") {
+ env[i] = "GOPATH=" + gp
+ return env
+ }
+ }
+ env = append(env, "GOPATH="+gp)
+ return env
+}
+
+// Similar to gobuild() above, but runs off a separate GOPATH environment
+
+func gobuildTestdata(t *testing.T, tdir string, gopathdir string, packtobuild string, gcflags string) *builtFile {
+ dst := filepath.Join(tdir, "out.exe")
+
+ // Run a build with an updated GOPATH
+ cmd := exec.Command(testenv.GoToolPath(t), "build", gcflags, "-o", dst, packtobuild)
+ cmd.Env = envWithGoPathSet(gopathdir)
+ if b, err := cmd.CombinedOutput(); err != nil {
+ t.Logf("build: %s\n", b)
+ t.Fatalf("build error: %v", err)
+ }
+
+ f, err := objfilepkg.Open(dst)
+ if err != nil {
+ t.Fatal(err)
+ }
+ return &builtFile{f, dst}
+}
+
func TestEmbeddedStructMarker(t *testing.T) {
testenv.MustHaveGoBuild(t)
}
}
-func abstractOriginSanity(t *testing.T, flags string) {
- // Nothing special about net/http here, this is just a convenient
- // way to pull in a lot of code.
- const prog = `
-package main
-
-import (
- "net/http"
- "net/http/httptest"
-)
-
-type statusHandler int
+func abstractOriginSanity(t *testing.T, gopathdir string, flags string) {
-func (h *statusHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
- w.WriteHeader(int(*h))
-}
-
-func main() {
- status := statusHandler(http.StatusNotFound)
- s := httptest.NewServer(&status)
- defer s.Close()
-}
-`
dir, err := ioutil.TempDir("", "TestAbstractOriginSanity")
if err != nil {
t.Fatalf("could not create directory: %v", err)
defer os.RemoveAll(dir)
// Build with inlining, to exercise DWARF inlining support.
- f := gobuild(t, dir, prog, flags)
+ f := gobuildTestdata(t, dir, gopathdir, "main", flags)
d, err := f.DWARF()
if err != nil {
t.Skip("skipping on solaris and darwin, pending resolution of issue #23168")
}
- abstractOriginSanity(t, OptInl4)
+ if wd, err := os.Getwd(); err == nil {
+ gopathdir := filepath.Join(wd, "testdata", "httptest")
+ abstractOriginSanity(t, gopathdir, OptInl4)
+ } else {
+ t.Fatalf("os.Getwd() failed %v", err)
+ }
}
-func TestAbstractOriginSanityWithLocationLists(t *testing.T) {
+func TestAbstractOriginSanityIssue25459(t *testing.T) {
testenv.MustHaveGoBuild(t)
if runtime.GOOS == "plan9" {
t.Skip("skipping on not-amd64 not-x86; location lists not supported")
}
- abstractOriginSanity(t, OptInl4DwLoc)
+ if wd, err := os.Getwd(); err == nil {
+ gopathdir := filepath.Join(wd, "testdata", "issue25459")
+ abstractOriginSanity(t, gopathdir, DefaultOpt)
+ } else {
+ t.Fatalf("os.Getwd() failed %v", err)
+ }
}
func TestRuntimeTypeAttr(t *testing.T) {