]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: avoid duplicate GC bitmap symbols
authorAustin Clements <austin@google.com>
Mon, 29 Oct 2018 22:21:00 +0000 (18:21 -0400)
committerAustin Clements <austin@google.com>
Sat, 3 Nov 2018 15:12:34 +0000 (15:12 +0000)
Currently, liveness produces a distinct obj.LSym for each GC bitmap
for each function. These are then named by content hash and only
ultimately deduplicated by WriteObjFile.

For various reasons (see next commit), we want to remove this
deduplication behavior from WriteObjFile. Furthermore, it's
inefficient to produce these duplicate symbols in the first place.

GC bitmaps are the only source of duplicate symbols in the compiler.
This commit eliminates these duplicate symbols by declaring them in
the Ctxt symbol hash just like every other obj.LSym. As a result, all
GC bitmaps with the same content now refer to the same obj.LSym.

The next commit will remove deduplication from WriteObjFile.

For #27539.

Change-Id: I4f15e3d99530122cdf473b7a838c69ef5f79db59
Reviewed-on: https://go-review.googlesource.com/c/146557
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
src/cmd/compile/internal/gc/gsubr.go
src/cmd/compile/internal/gc/obj.go
src/cmd/compile/internal/gc/plive.go
src/cmd/compile/internal/gc/ssa.go
src/cmd/internal/obj/link.go
src/cmd/internal/obj/plist.go

index f39ffc7365627cdabe680ec10c662c5e5757bec1..16602b998823366f58163c305fff646016a44de6 100644 (file)
@@ -185,24 +185,6 @@ func (pp *Progs) settext(fn *Node) {
        ptxt.From.Type = obj.TYPE_MEM
        ptxt.From.Name = obj.NAME_EXTERN
        ptxt.From.Sym = fn.Func.lsym
-
-       p := pp.Prog(obj.AFUNCDATA)
-       Addrconst(&p.From, objabi.FUNCDATA_ArgsPointerMaps)
-       p.To.Type = obj.TYPE_MEM
-       p.To.Name = obj.NAME_EXTERN
-       p.To.Sym = &fn.Func.lsym.Func.GCArgs
-
-       p = pp.Prog(obj.AFUNCDATA)
-       Addrconst(&p.From, objabi.FUNCDATA_LocalsPointerMaps)
-       p.To.Type = obj.TYPE_MEM
-       p.To.Name = obj.NAME_EXTERN
-       p.To.Sym = &fn.Func.lsym.Func.GCLocals
-
-       p = pp.Prog(obj.AFUNCDATA)
-       Addrconst(&p.From, objabi.FUNCDATA_RegPointerMaps)
-       p.To.Type = obj.TYPE_MEM
-       p.To.Name = obj.NAME_EXTERN
-       p.To.Sym = &fn.Func.lsym.Func.GCRegs
 }
 
 func (f *Func) initLSym() {
index a9dd092b6701841d0e1b9c93e1e59fe5dd9589ab..e3c8e07ffa71aef6278c5a73126c264545fb4cdc 100644 (file)
@@ -277,18 +277,18 @@ func dumpglobls() {
 // Though the object file format handles duplicates efficiently,
 // storing only a single copy of the data,
 // failure to remove these duplicates adds a few percent to object file size.
+//
+// This is done during the sequential phase after compilation, since
+// global symbols can't be declared during parallel compilation.
 func addGCLocals() {
-       seen := make(map[string]bool)
        for _, s := range Ctxt.Text {
                if s.Func == nil {
                        continue
                }
-               for _, gcsym := range []*obj.LSym{&s.Func.GCArgs, &s.Func.GCLocals, &s.Func.GCRegs} {
-                       if seen[gcsym.Name] {
-                               continue
+               for _, gcsym := range []*obj.LSym{s.Func.GCArgs, s.Func.GCLocals, s.Func.GCRegs} {
+                       if gcsym != nil && !gcsym.OnList() {
+                               ggloblsym(gcsym, int32(len(gcsym.P)), obj.RODATA|obj.DUPOK)
                        }
-                       Ctxt.Data = append(Ctxt.Data, gcsym)
-                       seen[gcsym.Name] = true
                }
                if x := s.Func.StackObjects; x != nil {
                        ggloblsym(x, int32(len(x.P)), obj.RODATA|obj.LOCAL)
index a38c33647eea810ea0dc5e5ef7928928ae8aa47e..601815f7c5d0047059cbd60fb78ffdb2996dc73d 100644 (file)
@@ -1461,7 +1461,7 @@ func (lv *Liveness) printDebug() {
 // first word dumped is the total number of bitmaps. The second word is the
 // length of the bitmaps. All bitmaps are assumed to be of equal length. The
 // remaining bytes are the raw bitmaps.
-func (lv *Liveness) emit(argssym, livesym, regssym *obj.LSym) {
+func (lv *Liveness) emit() (argsSym, liveSym, regsSym *obj.LSym) {
        // Size args bitmaps to be just large enough to hold the largest pointer.
        // First, find the largest Xoffset node we care about.
        // (Nodes without pointers aren't in lv.vars; see livenessShouldTrack.)
@@ -1489,13 +1489,16 @@ func (lv *Liveness) emit(argssym, livesym, regssym *obj.LSym) {
        // This would require shifting all bitmaps.
        maxLocals := lv.stkptrsize
 
+       // Temporary symbols for encoding bitmaps.
+       var argsSymTmp, liveSymTmp, regsSymTmp obj.LSym
+
        args := bvalloc(int32(maxArgs / int64(Widthptr)))
-       aoff := duint32(argssym, 0, uint32(len(lv.stackMaps))) // number of bitmaps
-       aoff = duint32(argssym, aoff, uint32(args.n))          // number of bits in each bitmap
+       aoff := duint32(&argsSymTmp, 0, uint32(len(lv.stackMaps))) // number of bitmaps
+       aoff = duint32(&argsSymTmp, aoff, uint32(args.n))          // number of bits in each bitmap
 
        locals := bvalloc(int32(maxLocals / int64(Widthptr)))
-       loff := duint32(livesym, 0, uint32(len(lv.stackMaps))) // number of bitmaps
-       loff = duint32(livesym, loff, uint32(locals.n))        // number of bits in each bitmap
+       loff := duint32(&liveSymTmp, 0, uint32(len(lv.stackMaps))) // number of bitmaps
+       loff = duint32(&liveSymTmp, loff, uint32(locals.n))        // number of bits in each bitmap
 
        for _, live := range lv.stackMaps {
                args.Clear()
@@ -1503,13 +1506,13 @@ func (lv *Liveness) emit(argssym, livesym, regssym *obj.LSym) {
 
                lv.pointerMap(live, lv.vars, args, locals)
 
-               aoff = dbvec(argssym, aoff, args)
-               loff = dbvec(livesym, loff, locals)
+               aoff = dbvec(&argsSymTmp, aoff, args)
+               loff = dbvec(&liveSymTmp, loff, locals)
        }
 
        regs := bvalloc(lv.usedRegs())
-       roff := duint32(regssym, 0, uint32(len(lv.regMaps))) // number of bitmaps
-       roff = duint32(regssym, roff, uint32(regs.n))        // number of bits in each bitmap
+       roff := duint32(&regsSymTmp, 0, uint32(len(lv.regMaps))) // number of bitmaps
+       roff = duint32(&regsSymTmp, roff, uint32(regs.n))        // number of bits in each bitmap
        if regs.n > 32 {
                // Our uint32 conversion below won't work.
                Fatalf("GP registers overflow uint32")
@@ -1519,25 +1522,29 @@ func (lv *Liveness) emit(argssym, livesym, regssym *obj.LSym) {
                for _, live := range lv.regMaps {
                        regs.Clear()
                        regs.b[0] = uint32(live)
-                       roff = dbvec(regssym, roff, regs)
+                       roff = dbvec(&regsSymTmp, roff, regs)
                }
        }
 
        // Give these LSyms content-addressable names,
        // so that they can be de-duplicated.
        // This provides significant binary size savings.
-       // It is safe to rename these LSyms because
-       // they are tracked separately from ctxt.hash.
-       argssym.Name = fmt.Sprintf("gclocals·%x", md5.Sum(argssym.P))
-       livesym.Name = fmt.Sprintf("gclocals·%x", md5.Sum(livesym.P))
-       regssym.Name = fmt.Sprintf("gclocals·%x", md5.Sum(regssym.P))
+       //
+       // These symbols will be added to Ctxt.Data by addGCLocals
+       // after parallel compilation is done.
+       makeSym := func(tmpSym *obj.LSym) *obj.LSym {
+               return Ctxt.LookupInit(fmt.Sprintf("gclocals·%x", md5.Sum(tmpSym.P)), func(lsym *obj.LSym) {
+                       lsym.P = tmpSym.P
+               })
+       }
+       return makeSym(&argsSymTmp), makeSym(&liveSymTmp), makeSym(&regsSymTmp)
 }
 
 // Entry pointer for liveness analysis. Solves for the liveness of
 // pointer variables in the function and emits a runtime data
 // structure read by the garbage collector.
 // Returns a map from GC safe points to their corresponding stack map index.
-func liveness(e *ssafn, f *ssa.Func) LivenessMap {
+func liveness(e *ssafn, f *ssa.Func, pp *Progs) LivenessMap {
        // Construct the global liveness state.
        vars, idx := getvariables(e.curfn)
        lv := newliveness(e.curfn, f, vars, idx, e.stkptrsize)
@@ -1577,7 +1584,25 @@ func liveness(e *ssafn, f *ssa.Func) LivenessMap {
 
        // Emit the live pointer map data structures
        if ls := e.curfn.Func.lsym; ls != nil {
-               lv.emit(&ls.Func.GCArgs, &ls.Func.GCLocals, &ls.Func.GCRegs)
+               ls.Func.GCArgs, ls.Func.GCLocals, ls.Func.GCRegs = lv.emit()
+
+               p := pp.Prog(obj.AFUNCDATA)
+               Addrconst(&p.From, objabi.FUNCDATA_ArgsPointerMaps)
+               p.To.Type = obj.TYPE_MEM
+               p.To.Name = obj.NAME_EXTERN
+               p.To.Sym = ls.Func.GCArgs
+
+               p = pp.Prog(obj.AFUNCDATA)
+               Addrconst(&p.From, objabi.FUNCDATA_LocalsPointerMaps)
+               p.To.Type = obj.TYPE_MEM
+               p.To.Name = obj.NAME_EXTERN
+               p.To.Sym = ls.Func.GCLocals
+
+               p = pp.Prog(obj.AFUNCDATA)
+               Addrconst(&p.From, objabi.FUNCDATA_RegPointerMaps)
+               p.To.Type = obj.TYPE_MEM
+               p.To.Name = obj.NAME_EXTERN
+               p.To.Sym = ls.Func.GCRegs
        }
        return lv.livenessMap
 }
index 4607cf19126616b437dff8ae3dc18148d0e56437..b0ccd01752470f1c65e106e756685b636aed0825 100644 (file)
@@ -5051,7 +5051,7 @@ func genssa(f *ssa.Func, pp *Progs) {
 
        e := f.Frontend().(*ssafn)
 
-       s.livenessMap = liveness(e, f)
+       s.livenessMap = liveness(e, f, pp)
        emitStackObjects(e, pp)
 
        // Remember where each block starts.
index f983d5277e07dd3cd48d9ca291e2efe765fba759..d924cbc21424b98fd3eeda8488d93ce58d100356 100644 (file)
@@ -403,9 +403,9 @@ type FuncInfo struct {
        dwarfAbsFnSym  *LSym
        dwarfIsStmtSym *LSym
 
-       GCArgs       LSym
-       GCLocals     LSym
-       GCRegs       LSym
+       GCArgs       *LSym
+       GCLocals     *LSym
+       GCRegs       *LSym
        StackObjects *LSym
 }
 
index a8675055d90d4d9411051d412d8e2eb36bb18a78..6710b375f16119a8f4672a19af14bfee1ae9d3ee 100644 (file)
@@ -147,18 +147,6 @@ func (ctxt *Link) InitTextSym(s *LSym, flag int) {
        isstmt.Type = objabi.SDWARFMISC
        isstmt.Set(AttrDuplicateOK, s.DuplicateOK())
        ctxt.Data = append(ctxt.Data, isstmt)
-
-       // Set up the function's gcargs and gclocals.
-       // They will be filled in later if needed.
-       gcargs := &s.Func.GCArgs
-       gcargs.Set(AttrDuplicateOK, true)
-       gcargs.Type = objabi.SRODATA
-       gclocals := &s.Func.GCLocals
-       gclocals.Set(AttrDuplicateOK, true)
-       gclocals.Type = objabi.SRODATA
-       gcregs := &s.Func.GCRegs
-       gcregs.Set(AttrDuplicateOK, true)
-       gcregs.Type = objabi.SRODATA
 }
 
 func (ctxt *Link) Globl(s *LSym, size int64, flag int) {