[dev.link] cmd/link: remove OutData

OutData was used for a symbol to point to its data in the output
buffer, in order to apply relocations. Now we fold relocation
application to Asmb next to symbol data writing. We can just pass
the output data as a local variable.

Linking cmd/compile,

name         old time/op    new time/op    delta
Asmb_GC        19.0ms ±10%    16.6ms ± 9%  -12.50%  (p=0.032 n=5+5)

name         old alloc/op   new alloc/op   delta
Asmb_GC        3.78MB ± 0%    0.14MB ± 1%  -96.41%  (p=0.008 n=5+5)

name         old live-B     new live-B     delta
Asmb_GC         27.5M ± 0%     23.9M ± 0%  -13.24%  (p=0.008 n=5+5)

Change-Id: Id870a10dce2a0a7447a05029c6d0ab39b47d0a12
Reviewed-on: https://go-review.googlesource.com/c/go/+/244017
Reviewed-by: Jeremy Faller <jeremy@golang.org>
This commit is contained in:
Cherry Zhang 2020-07-21 14:32:09 -04:00
parent bf1816c7b7
commit ee8541e5b8
7 changed files with 23 additions and 41 deletions

View file

@ -18,7 +18,6 @@ import (
// - writing out the architecture specific pieces. // - writing out the architecture specific pieces.
// This function handles the first part. // This function handles the first part.
func asmb(ctxt *Link) { func asmb(ctxt *Link) {
ctxt.loader.InitOutData()
if ctxt.IsExternal() && !ctxt.StreamExtRelocs() { if ctxt.IsExternal() && !ctxt.StreamExtRelocs() {
ctxt.loader.InitExtRelocs() ctxt.loader.InitExtRelocs()
} }

View file

@ -1026,9 +1026,9 @@ func writeBlock(ctxt *Link, out *OutBuf, ldr *loader.Loader, syms []loader.Sym,
out.WriteStringPad("", int(val-addr), pad) out.WriteStringPad("", int(val-addr), pad)
addr = val addr = val
} }
out.WriteSym(ldr, s) P := out.WriteSym(ldr, s)
st.relocsym(s, ldr.OutData(s)) st.relocsym(s, P)
addr += int64(len(ldr.Data(s))) addr += int64(len(P))
siz := ldr.SymSize(s) siz := ldr.SymSize(s)
if addr < val+siz { if addr < val+siz {
out.WriteStringPad("", int(val+siz-addr), pad) out.WriteStringPad("", int(val+siz-addr), pad)
@ -2677,8 +2677,8 @@ func compressSyms(ctxt *Link, syms []loader.Sym) []byte {
if relocs.Count() != 0 { if relocs.Count() != 0 {
relocbuf = append(relocbuf[:0], P...) relocbuf = append(relocbuf[:0], P...)
P = relocbuf P = relocbuf
}
st.relocsym(s, P) st.relocsym(s, P)
}
if _, err := z.Write(P); err != nil { if _, err := z.Write(P); err != nil {
log.Fatalf("compression failed: %s", err) log.Fatalf("compression failed: %s", err)
} }

View file

@ -159,8 +159,8 @@ func (ctxt *Link) MaxVersion() int {
// Generator symbols shouldn't grow the symbol size, and might be called in // Generator symbols shouldn't grow the symbol size, and might be called in
// parallel in the future. // parallel in the future.
// //
// Generator Symbols have their Data and OutData set to the mmapped area when // Generator Symbols have their Data set to the mmapped area when the
// the generator is called. // generator is called.
type generatorFunc func(*Link, loader.Sym) type generatorFunc func(*Link, loader.Sym)
// createGeneratorSymbol is a convenience method for creating a generator // createGeneratorSymbol is a convenience method for creating a generator

View file

@ -277,23 +277,24 @@ func (out *OutBuf) WriteStringPad(s string, n int, pad []byte) {
} }
} }
// WriteSym writes the content of a Symbol, then changes the Symbol's content // WriteSym writes the content of a Symbol, and returns the output buffer
// to point to the output buffer that we just wrote, so we can apply further // that we just wrote, so we can apply further edit to the symbol content.
// edit to the symbol content. // For generator symbols, it also sets the symbol's Data to the output
// If the output file is not Mmap'd, just writes the content. // buffer.
func (out *OutBuf) WriteSym(ldr *loader.Loader, s loader.Sym) { func (out *OutBuf) WriteSym(ldr *loader.Loader, s loader.Sym) []byte {
if !ldr.IsGeneratedSym(s) { if !ldr.IsGeneratedSym(s) {
P := ldr.Data(s) P := ldr.Data(s)
n := int64(len(P)) n := int64(len(P))
pos, buf := out.writeLoc(n) pos, buf := out.writeLoc(n)
copy(buf[pos:], P) copy(buf[pos:], P)
out.off += n out.off += n
ldr.SetOutData(s, buf[pos:pos+n]) ldr.FreeData(s)
return buf[pos : pos+n]
} else { } else {
n := ldr.SymSize(s) n := ldr.SymSize(s)
pos, buf := out.writeLoc(n) pos, buf := out.writeLoc(n)
out.off += n out.off += n
ldr.SetOutData(s, buf[pos:pos+n])
ldr.MakeSymbolUpdater(s).SetData(buf[pos : pos+n]) ldr.MakeSymbolUpdater(s).SetData(buf[pos : pos+n])
return buf[pos : pos+n]
} }
} }

View file

@ -238,7 +238,6 @@ type Loader struct {
align []uint8 // symbol 2^N alignment, indexed by global index align []uint8 // symbol 2^N alignment, indexed by global index
outdata [][]byte // symbol's data in the output buffer
extRelocs [][]ExtReloc // symbol's external relocations extRelocs [][]ExtReloc // symbol's external relocations
itablink map[Sym]struct{} // itablink[j] defined if j is go.itablink.* itablink map[Sym]struct{} // itablink[j] defined if j is go.itablink.*
@ -1230,30 +1229,16 @@ func (l *Loader) Data(i Sym) []byte {
return r.Data(li) return r.Data(li)
} }
// Returns the data of the i-th symbol in the output buffer. // FreeData clears the symbol data of an external symbol, allowing the memory
func (l *Loader) OutData(i Sym) []byte { // to be freed earlier. No-op for non-external symbols.
if int(i) < len(l.outdata) && l.outdata[i] != nil {
return l.outdata[i]
}
return l.Data(i)
}
// SetOutData sets the position of the data of the i-th symbol in the output buffer.
// i is global index. // i is global index.
func (l *Loader) SetOutData(i Sym, data []byte) { func (l *Loader) FreeData(i Sym) {
if l.IsExternal(i) { if l.IsExternal(i) {
pp := l.getPayload(i) pp := l.getPayload(i)
if pp != nil { if pp != nil {
pp.data = data pp.data = nil
return
} }
} }
l.outdata[i] = data
}
// InitOutData initializes the slice used to store symbol output data.
func (l *Loader) InitOutData() {
l.outdata = make([][]byte, l.extStart)
} }
// SetExtRelocs sets the external relocations of the i-th symbol. i is global index. // SetExtRelocs sets the external relocations of the i-th symbol. i is global index.

View file

@ -77,7 +77,7 @@ func machoreloc1(*sys.Arch, *ld.OutBuf, *loader.Loader, loader.Sym, loader.ExtRe
} }
func applyrel(arch *sys.Arch, ldr *loader.Loader, rt objabi.RelocType, off int32, s loader.Sym, val int64, t int64) int64 { func applyrel(arch *sys.Arch, ldr *loader.Loader, rt objabi.RelocType, off int32, s loader.Sym, val int64, t int64) int64 {
o := arch.ByteOrder.Uint32(ldr.OutData(s)[off:]) o := uint32(val)
switch rt { switch rt {
case objabi.R_ADDRMIPS, objabi.R_ADDRMIPSTLS: case objabi.R_ADDRMIPS, objabi.R_ADDRMIPSTLS:
return int64(o&0xffff0000 | uint32(t)&0xffff) return int64(o&0xffff0000 | uint32(t)&0xffff)

View file

@ -129,25 +129,22 @@ func archreloc(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, r loade
case objabi.R_ADDRMIPS, case objabi.R_ADDRMIPS,
objabi.R_ADDRMIPSU: objabi.R_ADDRMIPSU:
t := ldr.SymValue(rs) + r.Add() t := ldr.SymValue(rs) + r.Add()
o1 := target.Arch.ByteOrder.Uint32(ldr.OutData(s)[r.Off():])
if r.Type() == objabi.R_ADDRMIPS { if r.Type() == objabi.R_ADDRMIPS {
return int64(o1&0xffff0000 | uint32(t)&0xffff), noExtReloc, isOk return int64(val&0xffff0000 | t&0xffff), noExtReloc, isOk
} }
return int64(o1&0xffff0000 | uint32((t+1<<15)>>16)&0xffff), noExtReloc, isOk return int64(val&0xffff0000 | ((t+1<<15)>>16)&0xffff), noExtReloc, isOk
case objabi.R_ADDRMIPSTLS: case objabi.R_ADDRMIPSTLS:
// thread pointer is at 0x7000 offset from the start of TLS data area // thread pointer is at 0x7000 offset from the start of TLS data area
t := ldr.SymValue(rs) + r.Add() - 0x7000 t := ldr.SymValue(rs) + r.Add() - 0x7000
if t < -32768 || t >= 32678 { if t < -32768 || t >= 32678 {
ldr.Errorf(s, "TLS offset out of range %d", t) ldr.Errorf(s, "TLS offset out of range %d", t)
} }
o1 := target.Arch.ByteOrder.Uint32(ldr.OutData(s)[r.Off():]) return int64(val&0xffff0000 | t&0xffff), noExtReloc, isOk
return int64(o1&0xffff0000 | uint32(t)&0xffff), noExtReloc, isOk
case objabi.R_CALLMIPS, case objabi.R_CALLMIPS,
objabi.R_JMPMIPS: objabi.R_JMPMIPS:
// Low 26 bits = (S + A) >> 2 // Low 26 bits = (S + A) >> 2
t := ldr.SymValue(rs) + r.Add() t := ldr.SymValue(rs) + r.Add()
o1 := target.Arch.ByteOrder.Uint32(ldr.OutData(s)[r.Off():]) return int64(val&0xfc000000 | (t>>2)&^0xfc000000), noExtReloc, isOk
return int64(o1&0xfc000000 | uint32(t>>2)&^0xfc000000), noExtReloc, isOk
} }
return val, 0, false return val, 0, false