]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.link] cmd/compile, cmd/link: reference type symbol of defined type by index
authorCherry Zhang <cherryyz@google.com>
Mon, 27 Jul 2020 18:46:16 +0000 (14:46 -0400)
committerCherry Zhang <cherryyz@google.com>
Mon, 3 Aug 2020 21:11:33 +0000 (21:11 +0000)
The type descriptor symbol of a defined (named) type (and pointer
to it) is defined only in the package that defines the type. It
is not dupOK, unlike other type descriptors. So it can be
referenced by index. Currently it is referenced by name for
cross-package references, because the index is not exported and
so not known to the referencing package.

This CL passes the index through the export data, so the symbol
can be referenced by index, and does not need to be looked up by
name. This also makes such symbol references consistent: it is
referenced by index within the defining package and also cross-
package, which makes it easier for content hashing (in later CLs).

One complication is that we need to set flags on referenced
symbols (specifically, the UsedInIface flag). Before, they are
non-package refs, which naturally carry flags in the object file.
For indexed refs, we currently don't put their flags in the
object file. Introduce a new block for this.

Change-Id: I8126f8e318ac4e6609eb2ac136201fd6c264c256
Reviewed-on: https://go-review.googlesource.com/c/go/+/245718
Reviewed-by: Jeremy Faller <jeremy@golang.org>
src/cmd/compile/internal/gc/iexport.go
src/cmd/compile/internal/gc/iimport.go
src/cmd/compile/internal/gc/reflect.go
src/cmd/internal/goobj2/objfile.go
src/cmd/internal/obj/objfile2.go
src/cmd/link/internal/loader/loader.go

index 328260fc59ac9d8b0b76c7ce3cc6be933d4435b6..7a7dbdeac12574b62fc144dd341bcbab229d82ac 100644 (file)
@@ -484,6 +484,7 @@ func (p *iexporter) doDecl(n *Node) {
 
                t := n.Type
                if t.IsInterface() {
+                       w.typeExt(t)
                        break
                }
 
@@ -496,6 +497,7 @@ func (p *iexporter) doDecl(n *Node) {
                        w.signature(m.Type)
                }
 
+               w.typeExt(t)
                for _, m := range ms.Slice() {
                        w.methExt(m)
                }
@@ -1014,6 +1016,17 @@ func (w *exportWriter) symIdx(s *types.Sym) {
        }
 }
 
+func (w *exportWriter) typeExt(t *types.Type) {
+       // For type T, export the index of type descriptor symbols of T and *T.
+       if i, ok := typeSymIdx[t]; ok {
+               w.int64(i[0])
+               w.int64(i[1])
+               return
+       }
+       w.symIdx(typesym(t))
+       w.symIdx(typesym(t.PtrTo()))
+}
+
 // Inline bodies.
 
 func (w *exportWriter) stmtList(list Nodes) {
index 15a660cf558d938005298a6faffd016b2eb67f0e..29bb1e57a435a072e94157cf6c4ad7f7c0888a71 100644 (file)
@@ -316,6 +316,7 @@ func (r *importReader) doDecl(n *Node) {
                resumecheckwidth()
 
                if underlying.IsInterface() {
+                       r.typeExt(t)
                        break
                }
 
@@ -346,6 +347,7 @@ func (r *importReader) doDecl(n *Node) {
                }
                t.Methods().Set(ms)
 
+               r.typeExt(t)
                for _, m := range ms {
                        r.methExt(m)
                }
@@ -708,6 +710,17 @@ func (r *importReader) symIdx(s *types.Sym) {
        }
 }
 
+func (r *importReader) typeExt(t *types.Type) {
+       i, pi := r.int64(), r.int64()
+       if i != -1 && pi != -1 {
+               typeSymIdx[t] = [2]int64{i, pi}
+       }
+}
+
+// Map imported type T to the index of type descriptor symbols of T and *T,
+// so we can use index to reference the symbol.
+var typeSymIdx = make(map[*types.Type][2]int64)
+
 func (r *importReader) doInline(n *Node) {
        if len(n.Func.Inl.Body) != 0 {
                Fatalf("%v already has inline body", n)
index 05e64a5a9a1b6d57938afecfee5d55df65bd48b2..7758097db8cdabbf5715d5b21dce1aaaa31912ea 100644 (file)
@@ -1168,6 +1168,15 @@ func dtypesym(t *types.Type) *obj.LSym {
        if myimportpath != "runtime" || (tbase != types.Types[tbase.Etype] && tbase != types.Bytetype && tbase != types.Runetype && tbase != types.Errortype) { // int, float, etc
                // named types from other files are defined only by those files
                if tbase.Sym != nil && tbase.Sym.Pkg != localpkg {
+                       if i, ok := typeSymIdx[tbase]; ok {
+                               lsym.Pkg = tbase.Sym.Pkg.Prefix
+                               if t != tbase {
+                                       lsym.SymIdx = int32(i[1])
+                               } else {
+                                       lsym.SymIdx = int32(i[0])
+                               }
+                               lsym.Set(obj.AttrIndexed, true)
+                       }
                        return lsym
                }
                // TODO(mdempsky): Investigate whether this can happen.
index eae9b5587c2f528c1194ac047917c4171cec0c24..c3d00122e7c1f6dee576e8003137756bcba058ec 100644 (file)
@@ -41,11 +41,12 @@ import (
 //    DwarfFiles [...]string
 //
 //    SymbolDefs [...]struct {
-//       Name string
-//       ABI  uint16
-//       Type uint8
-//       Flag uint8
-//       Size uint32
+//       Name  string
+//       ABI   uint16
+//       Type  uint8
+//       Flag  uint8
+//       Flag2 uint8
+//       Size  uint32
 //    }
 //    Hashed64Defs [...]struct { // short hashed (content-addressable) symbol definitions
 //       ... // same as SymbolDefs
@@ -60,6 +61,12 @@ import (
 //       ... // same as SymbolDefs
 //    }
 //
+//    RefFlags [...]struct { // referenced symbol flags
+//       Sym   symRef
+//       Flag  uint8
+//       Flag2 uint8
+//    }
+//
 //    Hash64 [...][8]byte
 //    Hash   [...][N]byte
 //
@@ -176,6 +183,7 @@ const (
        BlkHasheddef
        BlkNonpkgdef
        BlkNonpkgref
+       BlkRefFlags
        BlkHash64
        BlkHash
        BlkRelocIdx
@@ -431,6 +439,33 @@ func (a *Aux) Write(w *Writer) { w.Bytes(a[:]) }
 // for testing
 func (a *Aux) fromBytes(b []byte) { copy(a[:], b) }
 
+// Referenced symbol flags.
+//
+// Serialized format:
+// RefFlags struct {
+//    Sym   symRef
+//    Flag  uint8
+//    Flag2 uint8
+// }
+type RefFlags [RefFlagsSize]byte
+
+const RefFlagsSize = 8 + 1 + 1
+
+func (r *RefFlags) Sym() SymRef {
+       return SymRef{binary.LittleEndian.Uint32(r[:]), binary.LittleEndian.Uint32(r[4:])}
+}
+func (r *RefFlags) Flag() uint8  { return r[8] }
+func (r *RefFlags) Flag2() uint8 { return r[9] }
+
+func (r *RefFlags) SetSym(x SymRef) {
+       binary.LittleEndian.PutUint32(r[:], x.PkgIdx)
+       binary.LittleEndian.PutUint32(r[4:], x.SymIdx)
+}
+func (r *RefFlags) SetFlag(x uint8)  { r[8] = x }
+func (r *RefFlags) SetFlag2(x uint8) { r[9] = x }
+
+func (r *RefFlags) Write(w *Writer) { w.Bytes(r[:]) }
+
 // Referenced symbol name.
 //
 // Serialized format:
@@ -689,6 +724,18 @@ func (r *Reader) Sym(i uint32) *Sym {
        return (*Sym)(unsafe.Pointer(&r.b[off]))
 }
 
+// NRefFlags returns the number of referenced symbol flags.
+func (r *Reader) NRefFlags() int {
+       return int(r.h.Offsets[BlkRefFlags+1]-r.h.Offsets[BlkRefFlags]) / RefFlagsSize
+}
+
+// RefFlags returns a pointer to the i-th referenced symbol flags.
+// Note: here i is not a local symbol index, just a counter.
+func (r *Reader) RefFlags(i int) *RefFlags {
+       off := r.h.Offsets[BlkRefFlags] + uint32(i*RefFlagsSize)
+       return (*RefFlags)(unsafe.Pointer(&r.b[off]))
+}
+
 // Hash64 returns the i-th short hashed symbol's hash.
 // Note: here i is the index of short hashed symbols, not all symbols
 // (unlike other accessors).
index 988ecdf543e04e17e207b51034f30e94c6290050..6740f422208c20ffd3668472e4e8e54a816d7918 100644 (file)
@@ -105,6 +105,10 @@ func WriteObjFile(ctxt *Link, b *bio.Writer) {
                w.Sym(s)
        }
 
+       // Referenced package symbol flags
+       h.Offsets[goobj2.BlkRefFlags] = w.Offset()
+       w.refFlags()
+
        // Hashes
        h.Offsets[goobj2.BlkHash64] = w.Offset()
        for _, s := range ctxt.hashed64defs {
@@ -468,10 +472,39 @@ func (w *writer) Aux(s *LSym) {
        }
 }
 
+// Emits flags of referenced indexed symbols.
+func (w *writer) refFlags() {
+       seen := make(map[*LSym]bool)
+       w.ctxt.traverseSyms(traverseRefs, func(rs *LSym) { // only traverse refs, not auxs, as tools don't need auxs
+               switch rs.PkgIdx {
+               case goobj2.PkgIdxNone, goobj2.PkgIdxHashed64, goobj2.PkgIdxHashed, goobj2.PkgIdxBuiltin, goobj2.PkgIdxSelf: // not an external indexed reference
+                       return
+               case goobj2.PkgIdxInvalid:
+                       panic("unindexed symbol reference")
+               }
+               if seen[rs] {
+                       return
+               }
+               seen[rs] = true
+               symref := makeSymRef(rs)
+               flag2 := uint8(0)
+               if rs.UsedInIface() {
+                       flag2 |= goobj2.SymFlagUsedInIface
+               }
+               if flag2 == 0 {
+                       return // no need to write zero flags
+               }
+               var o goobj2.RefFlags
+               o.SetSym(symref)
+               o.SetFlag2(flag2)
+               o.Write(w.Writer)
+       })
+}
+
 // Emits names of referenced indexed symbols, used by tools (objdump, nm)
 // only.
 func (w *writer) refNames() {
-       seen := make(map[goobj2.SymRef]bool)
+       seen := make(map[*LSym]bool)
        w.ctxt.traverseSyms(traverseRefs, func(rs *LSym) { // only traverse refs, not auxs, as tools don't need auxs
                switch rs.PkgIdx {
                case goobj2.PkgIdxNone, goobj2.PkgIdxHashed64, goobj2.PkgIdxHashed, goobj2.PkgIdxBuiltin, goobj2.PkgIdxSelf: // not an external indexed reference
@@ -479,11 +512,11 @@ func (w *writer) refNames() {
                case goobj2.PkgIdxInvalid:
                        panic("unindexed symbol reference")
                }
-               symref := makeSymRef(rs)
-               if seen[symref] {
+               if seen[rs] {
                        return
                }
-               seen[symref] = true
+               seen[rs] = true
+               symref := makeSymRef(rs)
                var o goobj2.RefName
                o.SetSym(symref)
                o.SetName(rs.Name, w.Writer)
index 45085f56c1fa76a6df7132b27cddaf61cbe4f656..d34e6fdf6b2e9d04024d311462ec577ae9cd0b0b 100644 (file)
@@ -2149,6 +2149,7 @@ func (l *Loader) LoadNonpkgSyms(arch *sys.Arch) {
 }
 
 func loadObjRefs(l *Loader, r *oReader, arch *sys.Arch) {
+       // load non-package refs
        ndef := uint32(r.NAlldef())
        needNameExpansion := r.NeedNameExpansion()
        for i, n := uint32(0), uint32(r.NNonpkgref()); i < n; i++ {
@@ -2167,6 +2168,15 @@ func loadObjRefs(l *Loader, r *oReader, arch *sys.Arch) {
                        l.SetAttrUsedInIface(gi, true)
                }
        }
+
+       // load flags of package refs
+       for i, n := 0, r.NRefFlags(); i < n; i++ {
+               rf := r.RefFlags(i)
+               gi := l.resolve(r, rf.Sym())
+               if rf.Flag2()&goobj2.SymFlagUsedInIface != 0 {
+                       l.SetAttrUsedInIface(gi, true)
+               }
+       }
 }
 
 func abiToVer(abi uint16, localSymVersion int) int {