]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/link: don't mark a symbol's Gotype reachable
authorCherry Zhang <cherryyz@google.com>
Fri, 1 May 2020 03:10:35 +0000 (23:10 -0400)
committerCherry Zhang <cherryyz@google.com>
Fri, 1 May 2020 18:04:59 +0000 (18:04 +0000)
A symbol being reachable doesn't imply its type descriptor is
needed. Don't mark it.

If the type is converted to interface somewhere in the program,
there will be an explicit use of the type descriptor, which
will make it marked.

A println("hello") program before and after

-rwxr-xr-x  1 cherryyz  primarygroup  1259824 Apr 30 23:00 hello
-rwxr-xr-x  1 cherryyz  primarygroup  1169680 Apr 30 23:10 hello

Updates #38782.
Updates #6853.

Change-Id: I88884c126ce75ba073f1ba059c4b892c87d2ac96
Reviewed-on: https://go-review.googlesource.com/c/go/+/231397
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Alessandro Arzilli <alessandro.arzilli@gmail.com>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
src/cmd/link/internal/ld/deadcode.go
src/cmd/link/internal/ld/deadcode_test.go
src/cmd/link/internal/ld/testdata/deadcode/reflectcall.go [new file with mode: 0644]
src/cmd/link/internal/ld/testdata/deadcode/typedesc.go [new file with mode: 0644]

index 49c5668c863b9bcf9c7a82fbef24e67fc61e4bb5..c91a18a167cf1737b903ae1e25572e17d461caa1 100644 (file)
@@ -6,6 +6,7 @@ package ld
 
 import (
        "bytes"
+       "cmd/internal/goobj2"
        "cmd/internal/objabi"
        "cmd/internal/sys"
        "cmd/link/internal/loader"
@@ -154,7 +155,15 @@ func (d *deadcodePass) flood() {
                }
                naux := d.ldr.NAux(symIdx)
                for i := 0; i < naux; i++ {
-                       d.mark(d.ldr.Aux2(symIdx, i).Sym(), symIdx)
+                       a := d.ldr.Aux2(symIdx, i)
+                       if a.Type() == goobj2.AuxGotype && !d.ctxt.linkShared {
+                               // A symbol being reachable doesn't imply we need its
+                               // type descriptor. Don't mark it.
+                               // XXX we need that for GCProg generation when linking
+                               // shared library. why?
+                               continue
+                       }
+                       d.mark(a.Sym(), symIdx)
                }
                // Some host object symbols have an outer object, which acts like a
                // "carrier" symbol, or it holds all the symbols for a particular
index 197a057c2fe8c2bd6fe179e12517872f71122008..23a8685bbb626fb60a2926c143233d7779d93c28 100644 (file)
@@ -14,28 +14,9 @@ import (
        "testing"
 )
 
-// This example uses reflect.Value.Call, but not
-// reflect.{Value,Type}.Method. This should not
-// need to bring all methods live.
-const deadcodeTestSrc = `
-package main
-import "reflect"
-
-func f() { println("call") }
-
-type T int
-func (T) M() {}
-
-func main() {
-       v := reflect.ValueOf(f)
-       v.Call(nil)
-       i := interface{}(T(1))
-       println(i)
-}
-`
-
 func TestDeadcode(t *testing.T) {
        testenv.MustHaveGoBuild(t)
+       t.Parallel()
 
        tmpdir, err := ioutil.TempDir("", "TestDeadcode")
        if err != nil {
@@ -43,19 +24,26 @@ func TestDeadcode(t *testing.T) {
        }
        defer os.RemoveAll(tmpdir)
 
-       src := filepath.Join(tmpdir, "main.go")
-       err = ioutil.WriteFile(src, []byte(deadcodeTestSrc), 0666)
-       if err != nil {
-               t.Fatal(err)
-       }
-       exe := filepath.Join(tmpdir, "main.exe")
-
-       cmd := exec.Command(testenv.GoToolPath(t), "build", "-ldflags=-dumpdep", "-o", exe, src)
-       out, err := cmd.CombinedOutput()
-       if err != nil {
-               t.Fatalf("%v: %v:\n%s", cmd.Args, err, out)
+       tests := []struct {
+               src     string
+               pattern string
+       }{
+               {"reflectcall", "main.T.M"},
+               {"typedesc", "type.main.T"},
        }
-       if bytes.Contains(out, []byte("main.T.M")) {
-               t.Errorf("main.T.M should not be reachable. Output:\n%s", out)
+       for _, test := range tests {
+               t.Run(test.src, func(t *testing.T) {
+                       t.Parallel()
+                       src := filepath.Join("testdata", "deadcode", test.src+".go")
+                       exe := filepath.Join(tmpdir, test.src+".exe")
+                       cmd := exec.Command(testenv.GoToolPath(t), "build", "-ldflags=-dumpdep", "-o", exe, src)
+                       out, err := cmd.CombinedOutput()
+                       if err != nil {
+                               t.Fatalf("%v: %v:\n%s", cmd.Args, err, out)
+                       }
+                       if bytes.Contains(out, []byte(test.pattern)) {
+                               t.Errorf("%s should not be reachable. Output:\n%s", test.pattern, out)
+                       }
+               })
        }
 }
diff --git a/src/cmd/link/internal/ld/testdata/deadcode/reflectcall.go b/src/cmd/link/internal/ld/testdata/deadcode/reflectcall.go
new file mode 100644 (file)
index 0000000..af95e46
--- /dev/null
@@ -0,0 +1,24 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This example uses reflect.Value.Call, but not
+// reflect.{Value,Type}.Method. This should not
+// need to bring all methods live.
+
+package main
+
+import "reflect"
+
+func f() { println("call") }
+
+type T int
+
+func (T) M() {}
+
+func main() {
+       v := reflect.ValueOf(f)
+       v.Call(nil)
+       i := interface{}(T(1))
+       println(i)
+}
diff --git a/src/cmd/link/internal/ld/testdata/deadcode/typedesc.go b/src/cmd/link/internal/ld/testdata/deadcode/typedesc.go
new file mode 100644 (file)
index 0000000..8246093
--- /dev/null
@@ -0,0 +1,16 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test that a live variable doesn't bring its type
+// descriptor live.
+
+package main
+
+type T [10]string
+
+var t T
+
+func main() {
+       println(t[8])
+}