]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.link] cmd/link: assign special indices for builtin functions
authorCherry Zhang <cherryyz@google.com>
Fri, 18 Oct 2019 21:08:35 +0000 (17:08 -0400)
committerCherry Zhang <cherryyz@google.com>
Thu, 24 Oct 2019 15:24:20 +0000 (15:24 +0000)
Compiler-generated function references (e.g. call to
runtime.newobject) appear frequently. We assign special indices
for them, so they don't need to be referenced by name.

Change-Id: I2072594cbc56c9e1037a26e4aae12e68c2436e9f
Reviewed-on: https://go-review.googlesource.com/c/go/+/202085
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
src/cmd/internal/goobj/readnew.go
src/cmd/internal/goobj2/builtin.go [new file with mode: 0644]
src/cmd/internal/goobj2/builtinlist.go [new file with mode: 0644]
src/cmd/internal/goobj2/mkbuiltin.go [new file with mode: 0644]
src/cmd/internal/obj/sym.go
src/cmd/link/internal/loader/loader.go

index de05f37c3b6aef6e90c23e149a0a766449c55070..3f9d0d1db6fbdb70f5e840e55f124f831f8a8c04 100644 (file)
@@ -49,7 +49,8 @@ func (r *objReader) readNew() {
                case goobj2.PkgIdxNone:
                        i = int(s.SymIdx) + rr.NSym()
                case goobj2.PkgIdxBuiltin:
-                       panic("PkgIdxBuiltin is unused")
+                       name, abi := goobj2.BuiltinName(int(s.SymIdx))
+                       return SymID{name, int64(abi)}
                case goobj2.PkgIdxSelf:
                        i = int(s.SymIdx)
                default:
diff --git a/src/cmd/internal/goobj2/builtin.go b/src/cmd/internal/goobj2/builtin.go
new file mode 100644 (file)
index 0000000..65f9dd5
--- /dev/null
@@ -0,0 +1,45 @@
+// Copyright 2019 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.
+
+package goobj2
+
+// Builtin (compiler-generated) function references appear
+// frequently. We assign special indices for them, so they
+// don't need to be referenced by name.
+
+// NBuiltin returns the number of listed builtin
+// symbols.
+func NBuiltin() int {
+       return len(builtins)
+}
+
+// BuiltinName returns the name and ABI of the i-th
+// builtin symbol.
+func BuiltinName(i int) (string, int) {
+       return builtins[i].name, builtins[i].abi
+}
+
+// BuiltinIdx returns the index of the builtin with the
+// given name and abi, or -1 if it is not a builtin.
+func BuiltinIdx(name string, abi int) int {
+       i, ok := builtinMap[name]
+       if !ok {
+               return -1
+       }
+       if builtins[i].abi != abi {
+               return -1
+       }
+       return i
+}
+
+//go:generate go run mkbuiltin.go
+
+var builtinMap map[string]int
+
+func init() {
+       builtinMap = make(map[string]int, len(builtins))
+       for i, b := range builtins {
+               builtinMap[b.name] = i
+       }
+}
diff --git a/src/cmd/internal/goobj2/builtinlist.go b/src/cmd/internal/goobj2/builtinlist.go
new file mode 100644 (file)
index 0000000..bcab6f2
--- /dev/null
@@ -0,0 +1,194 @@
+// Code generated by mkbuiltin.go. DO NOT EDIT.
+
+package goobj2
+
+var builtins = [...]struct {
+       name string
+       abi  int
+}{
+       {"runtime.newobject", 1},
+       {"runtime.panicdivide", 1},
+       {"runtime.panicshift", 1},
+       {"runtime.panicmakeslicelen", 1},
+       {"runtime.throwinit", 1},
+       {"runtime.panicwrap", 1},
+       {"runtime.gopanic", 1},
+       {"runtime.gorecover", 1},
+       {"runtime.goschedguarded", 1},
+       {"runtime.goPanicIndex", 1},
+       {"runtime.goPanicIndexU", 1},
+       {"runtime.goPanicSliceAlen", 1},
+       {"runtime.goPanicSliceAlenU", 1},
+       {"runtime.goPanicSliceAcap", 1},
+       {"runtime.goPanicSliceAcapU", 1},
+       {"runtime.goPanicSliceB", 1},
+       {"runtime.goPanicSliceBU", 1},
+       {"runtime.goPanicSlice3Alen", 1},
+       {"runtime.goPanicSlice3AlenU", 1},
+       {"runtime.goPanicSlice3Acap", 1},
+       {"runtime.goPanicSlice3AcapU", 1},
+       {"runtime.goPanicSlice3B", 1},
+       {"runtime.goPanicSlice3BU", 1},
+       {"runtime.goPanicSlice3C", 1},
+       {"runtime.goPanicSlice3CU", 1},
+       {"runtime.printbool", 1},
+       {"runtime.printfloat", 1},
+       {"runtime.printint", 1},
+       {"runtime.printhex", 1},
+       {"runtime.printuint", 1},
+       {"runtime.printcomplex", 1},
+       {"runtime.printstring", 1},
+       {"runtime.printpointer", 1},
+       {"runtime.printiface", 1},
+       {"runtime.printeface", 1},
+       {"runtime.printslice", 1},
+       {"runtime.printnl", 1},
+       {"runtime.printsp", 1},
+       {"runtime.printlock", 1},
+       {"runtime.printunlock", 1},
+       {"runtime.concatstring2", 1},
+       {"runtime.concatstring3", 1},
+       {"runtime.concatstring4", 1},
+       {"runtime.concatstring5", 1},
+       {"runtime.concatstrings", 1},
+       {"runtime.cmpstring", 1},
+       {"runtime.intstring", 1},
+       {"runtime.slicebytetostring", 1},
+       {"runtime.slicebytetostringtmp", 1},
+       {"runtime.slicerunetostring", 1},
+       {"runtime.stringtoslicebyte", 1},
+       {"runtime.stringtoslicerune", 1},
+       {"runtime.slicecopy", 1},
+       {"runtime.slicestringcopy", 1},
+       {"runtime.decoderune", 1},
+       {"runtime.countrunes", 1},
+       {"runtime.convI2I", 1},
+       {"runtime.convT16", 1},
+       {"runtime.convT32", 1},
+       {"runtime.convT64", 1},
+       {"runtime.convTstring", 1},
+       {"runtime.convTslice", 1},
+       {"runtime.convT2E", 1},
+       {"runtime.convT2Enoptr", 1},
+       {"runtime.convT2I", 1},
+       {"runtime.convT2Inoptr", 1},
+       {"runtime.assertE2I", 1},
+       {"runtime.assertE2I2", 1},
+       {"runtime.assertI2I", 1},
+       {"runtime.assertI2I2", 1},
+       {"runtime.panicdottypeE", 1},
+       {"runtime.panicdottypeI", 1},
+       {"runtime.panicnildottype", 1},
+       {"runtime.ifaceeq", 1},
+       {"runtime.efaceeq", 1},
+       {"runtime.fastrand", 1},
+       {"runtime.makemap64", 1},
+       {"runtime.makemap", 1},
+       {"runtime.makemap_small", 1},
+       {"runtime.mapaccess1", 1},
+       {"runtime.mapaccess1_fast32", 1},
+       {"runtime.mapaccess1_fast64", 1},
+       {"runtime.mapaccess1_faststr", 1},
+       {"runtime.mapaccess1_fat", 1},
+       {"runtime.mapaccess2", 1},
+       {"runtime.mapaccess2_fast32", 1},
+       {"runtime.mapaccess2_fast64", 1},
+       {"runtime.mapaccess2_faststr", 1},
+       {"runtime.mapaccess2_fat", 1},
+       {"runtime.mapassign", 1},
+       {"runtime.mapassign_fast32", 1},
+       {"runtime.mapassign_fast32ptr", 1},
+       {"runtime.mapassign_fast64", 1},
+       {"runtime.mapassign_fast64ptr", 1},
+       {"runtime.mapassign_faststr", 1},
+       {"runtime.mapiterinit", 1},
+       {"runtime.mapdelete", 1},
+       {"runtime.mapdelete_fast32", 1},
+       {"runtime.mapdelete_fast64", 1},
+       {"runtime.mapdelete_faststr", 1},
+       {"runtime.mapiternext", 1},
+       {"runtime.mapclear", 1},
+       {"runtime.makechan64", 1},
+       {"runtime.makechan", 1},
+       {"runtime.chanrecv1", 1},
+       {"runtime.chanrecv2", 1},
+       {"runtime.chansend1", 1},
+       {"runtime.closechan", 1},
+       {"runtime.writeBarrier", 0},
+       {"runtime.typedmemmove", 1},
+       {"runtime.typedmemclr", 1},
+       {"runtime.typedslicecopy", 1},
+       {"runtime.selectnbsend", 1},
+       {"runtime.selectnbrecv", 1},
+       {"runtime.selectnbrecv2", 1},
+       {"runtime.selectsetpc", 1},
+       {"runtime.selectgo", 1},
+       {"runtime.block", 1},
+       {"runtime.makeslice", 1},
+       {"runtime.makeslice64", 1},
+       {"runtime.growslice", 1},
+       {"runtime.memmove", 1},
+       {"runtime.memclrNoHeapPointers", 1},
+       {"runtime.memclrHasPointers", 1},
+       {"runtime.memequal", 1},
+       {"runtime.memequal0", 1},
+       {"runtime.memequal8", 1},
+       {"runtime.memequal16", 1},
+       {"runtime.memequal32", 1},
+       {"runtime.memequal64", 1},
+       {"runtime.memequal128", 1},
+       {"runtime.f32equal", 1},
+       {"runtime.f64equal", 1},
+       {"runtime.c64equal", 1},
+       {"runtime.c128equal", 1},
+       {"runtime.strequal", 1},
+       {"runtime.interequal", 1},
+       {"runtime.nilinterequal", 1},
+       {"runtime.memhash", 1},
+       {"runtime.memhash0", 1},
+       {"runtime.memhash8", 1},
+       {"runtime.memhash16", 1},
+       {"runtime.memhash32", 1},
+       {"runtime.memhash64", 1},
+       {"runtime.memhash128", 1},
+       {"runtime.f32hash", 1},
+       {"runtime.f64hash", 1},
+       {"runtime.c64hash", 1},
+       {"runtime.c128hash", 1},
+       {"runtime.strhash", 1},
+       {"runtime.interhash", 1},
+       {"runtime.nilinterhash", 1},
+       {"runtime.int64div", 1},
+       {"runtime.uint64div", 1},
+       {"runtime.int64mod", 1},
+       {"runtime.uint64mod", 1},
+       {"runtime.float64toint64", 1},
+       {"runtime.float64touint64", 1},
+       {"runtime.float64touint32", 1},
+       {"runtime.int64tofloat64", 1},
+       {"runtime.uint64tofloat64", 1},
+       {"runtime.uint32tofloat64", 1},
+       {"runtime.complex128div", 1},
+       {"runtime.racefuncenter", 1},
+       {"runtime.racefuncenterfp", 1},
+       {"runtime.racefuncexit", 1},
+       {"runtime.raceread", 1},
+       {"runtime.racewrite", 1},
+       {"runtime.racereadrange", 1},
+       {"runtime.racewriterange", 1},
+       {"runtime.msanread", 1},
+       {"runtime.msanwrite", 1},
+       {"runtime.checkptrAlignment", 1},
+       {"runtime.checkptrArithmetic", 1},
+       {"runtime.x86HasPOPCNT", 0},
+       {"runtime.x86HasSSE41", 0},
+       {"runtime.arm64HasATOMICS", 0},
+       {"runtime.gcWriteBarrier", 0},
+       {"runtime.deferproc", 1},
+       {"runtime.deferprocStack", 1},
+       {"runtime.deferreturn", 1},
+       {"runtime.newproc", 1},
+       {"runtime.morestack", 0},
+       {"runtime.morestackc", 0},
+       {"runtime.morestack_noctxt", 0},
+}
diff --git a/src/cmd/internal/goobj2/mkbuiltin.go b/src/cmd/internal/goobj2/mkbuiltin.go
new file mode 100644 (file)
index 0000000..0061aeb
--- /dev/null
@@ -0,0 +1,124 @@
+// Copyright 2019 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.
+
+// +build ignore
+
+// Generate builtinlist.go from cmd/compile/internal/gc/builtin/runtime.go.
+
+package main
+
+import (
+       "bytes"
+       "flag"
+       "fmt"
+       "go/ast"
+       "go/format"
+       "go/parser"
+       "go/token"
+       "io"
+       "io/ioutil"
+       "log"
+       "os"
+       "path/filepath"
+)
+
+var stdout = flag.Bool("stdout", false, "write to stdout instead of builtinlist.go")
+
+func main() {
+       flag.Parse()
+
+       var b bytes.Buffer
+       fmt.Fprintln(&b, "// Code generated by mkbuiltin.go. DO NOT EDIT.")
+       fmt.Fprintln(&b)
+       fmt.Fprintln(&b, "package goobj2")
+
+       mkbuiltin(&b)
+
+       out, err := format.Source(b.Bytes())
+       if err != nil {
+               log.Fatal(err)
+       }
+       if *stdout {
+               _, err = os.Stdout.Write(out)
+       } else {
+               err = ioutil.WriteFile("builtinlist.go", out, 0666)
+       }
+       if err != nil {
+               log.Fatal(err)
+       }
+}
+
+func mkbuiltin(w io.Writer) {
+       pkg := "runtime"
+       fset := token.NewFileSet()
+       path := filepath.Join("..", "..", "compile", "internal", "gc", "builtin", "runtime.go")
+       f, err := parser.ParseFile(fset, path, nil, 0)
+       if err != nil {
+               log.Fatal(err)
+       }
+
+       decls := make(map[string]bool)
+
+       fmt.Fprintf(w, "var builtins = [...]struct{ name string; abi int }{\n")
+       for _, decl := range f.Decls {
+               switch decl := decl.(type) {
+               case *ast.FuncDecl:
+                       if decl.Recv != nil {
+                               log.Fatal("methods unsupported")
+                       }
+                       if decl.Body != nil {
+                               log.Fatal("unexpected function body")
+                       }
+                       declName := pkg + "." + decl.Name.Name
+                       decls[declName] = true
+                       fmt.Fprintf(w, "{%q, 1},\n", declName) // functions are ABIInternal (1)
+               case *ast.GenDecl:
+                       if decl.Tok == token.IMPORT {
+                               continue
+                       }
+                       if decl.Tok != token.VAR {
+                               log.Fatal("unhandled declaration kind", decl.Tok)
+                       }
+                       for _, spec := range decl.Specs {
+                               spec := spec.(*ast.ValueSpec)
+                               if len(spec.Values) != 0 {
+                                       log.Fatal("unexpected values")
+                               }
+                               for _, name := range spec.Names {
+                                       declName := pkg + "." + name.Name
+                                       decls[declName] = true
+                                       fmt.Fprintf(w, "{%q, 0},\n", declName) // variables are ABI0
+                               }
+                       }
+               default:
+                       log.Fatal("unhandled decl type", decl)
+               }
+       }
+
+       // The list above only contains ones that are used by the frontend.
+       // The backend may create more references of builtin functions.
+       // Add them.
+       for _, b := range extra {
+               name := pkg + "." + b.name
+               if decls[name] {
+                       log.Fatalf("%q already added -- mkbuiltin.go out of sync?", name)
+               }
+               fmt.Fprintf(w, "{%q, %d},\n", name, b.abi)
+       }
+       fmt.Fprintln(w, "}")
+}
+
+var extra = [...]struct {
+       name string
+       abi  int
+}{
+       {"gcWriteBarrier", 0}, // asm function, ABI0
+       {"deferproc", 1},
+       {"deferprocStack", 1},
+       {"deferreturn", 1},
+       {"newproc", 1},
+       {"morestack", 0},        // asm function, ABI0
+       {"morestackc", 0},       // asm function, ABI0
+       {"morestack_noctxt", 0}, // asm function, ABI0
+}
index ab886bce36ccc85d4b50410b4b35f314e5358480..3ef886651f0d9ae972b7f897179dee5a65e5e2fa 100644 (file)
@@ -210,6 +210,17 @@ func (ctxt *Link) NumberSyms(asm bool) {
                if rs.PkgIdx != goobj2.PkgIdxInvalid {
                        return
                }
+               if !ctxt.Flag_linkshared {
+                       // Assign special index for builtin symbols.
+                       // Don't do it when linking against shared libraries, as the runtime
+                       // may be in a different library.
+                       if i := goobj2.BuiltinIdx(rs.Name, int(rs.ABI())); i != -1 {
+                               rs.PkgIdx = goobj2.PkgIdxBuiltin
+                               rs.SymIdx = int32(i)
+                               rs.Set(AttrIndexed, true)
+                               return
+                       }
+               }
                pkg := rs.Pkg
                if pkg == "" || pkg == "\"\"" || pkg == "_" || !rs.Indexed() {
                        rs.PkgIdx = goobj2.PkgIdxNone
index e3f7480ac71cd9035d8455c80dd8dcbd404a6807..846e954aa1856b89e1eb8c5780a06bd0d23276f8 100644 (file)
@@ -91,11 +91,12 @@ func makeBitmap(n int) bitmap {
 
 // A Loader loads new object files and resolves indexed symbol references.
 type Loader struct {
-       start    map[*oReader]Sym // map from object file to its start index
-       objs     []objIdx         // sorted by start index (i.e. objIdx.i)
-       max      Sym              // current max index
-       extStart Sym              // from this index on, the symbols are externally defined
-       extSyms  []nameVer        // externally defined symbols
+       start       map[*oReader]Sym // map from object file to its start index
+       objs        []objIdx         // sorted by start index (i.e. objIdx.i)
+       max         Sym              // current max index
+       extStart    Sym              // from this index on, the symbols are externally defined
+       extSyms     []nameVer        // externally defined symbols
+       builtinSyms []Sym            // global index of builtin symbols
 
        symsByName    [2]map[string]Sym // map symbol name to index, two maps are for ABI0 and ABIInternal
        extStaticSyms map[nameVer]Sym   // externally defined static symbols, keyed by name
@@ -111,6 +112,7 @@ type Loader struct {
 }
 
 func NewLoader() *Loader {
+       nbuiltin := goobj2.NBuiltin()
        return &Loader{
                start:         make(map[*oReader]Sym),
                objs:          []objIdx{{nil, 0}},
@@ -119,6 +121,7 @@ func NewLoader() *Loader {
                overwrite:     make(map[Sym]Sym),
                itablink:      make(map[Sym]struct{}),
                extStaticSyms: make(map[nameVer]Sym),
+               builtinSyms:   make([]Sym, nbuiltin),
        }
 }
 
@@ -272,7 +275,7 @@ func (l *Loader) resolve(r *oReader, s goobj2.SymRef) Sym {
                v := abiToVer(osym.ABI, r.version)
                return l.Lookup(name, v)
        case goobj2.PkgIdxBuiltin:
-               panic("PkgIdxBuiltin not used")
+               return l.builtinSyms[s.SymIdx]
        case goobj2.PkgIdxSelf:
                rr = r
        default:
@@ -575,6 +578,12 @@ func (l *Loader) Preload(arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, lib *
                if added && strings.HasPrefix(name, "go.itablink.") {
                        l.itablink[istart+Sym(i)] = struct{}{}
                }
+               if added && strings.HasPrefix(name, "runtime.") {
+                       if bi := goobj2.BuiltinIdx(name, v); bi != -1 {
+                               // This is a definition of a builtin symbol. Record where it is.
+                               l.builtinSyms[bi] = istart + Sym(i)
+                       }
+               }
        }
 
        // The caller expects us consuming all the data