Skip to content

Commit

Permalink
cmd/link: remove allocation in decoding type name
Browse files Browse the repository at this point in the history
The type name symbol is always from a Go object file and we never
change it. Convert the data to string using unsafe conversion
without allocation.

Linking cmd/go (on macOS/amd64),

name           old alloc/op   new alloc/op   delta
Deadcode_GC      1.25MB ± 0%    1.17MB ± 0%   -6.29%  (p=0.000 n=20+20)

name           old allocs/op  new allocs/op  delta
Deadcode_GC       8.98k ± 0%     0.10k ± 3%  -98.91%  (p=0.000 n=20+20)

Change-Id: I33117ad1f991e4f14ce0b38cceec50b041e3c0a4
Reviewed-on: https://go-review.googlesource.com/c/go/+/490915
TryBot-Result: Gopher Robot <[email protected]>
Run-TryBot: Cherry Mui <[email protected]>
Reviewed-by: Than McIntosh <[email protected]>
  • Loading branch information
cherrymui committed May 2, 2023
1 parent fa4781a commit 630ef2e
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 4 deletions.
9 changes: 9 additions & 0 deletions src/cmd/internal/goobj/objfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -853,6 +853,15 @@ func (r *Reader) Data(i uint32) []byte {
return r.BytesAt(base+off, int(end-off))
}

// DataString returns the i-th symbol's data as a string.
func (r *Reader) DataString(i uint32) string {
dataIdxOff := r.h.Offsets[BlkDataIdx] + i*4
base := r.h.Offsets[BlkData]
off := r.uint32At(dataIdxOff)
end := r.uint32At(dataIdxOff + 4)
return r.StringAt(base+off, end-off)
}

// NRefName returns the number of referenced symbol names.
func (r *Reader) NRefName() int {
return int(r.h.Offsets[BlkRefName+1]-r.h.Offsets[BlkRefName]) / RefNameSize
Expand Down
2 changes: 1 addition & 1 deletion src/cmd/link/internal/ld/deadcode.go
Original file line number Diff line number Diff line change
Expand Up @@ -487,7 +487,7 @@ func (d *deadcodePass) decodeIfaceMethod(ldr *loader.Loader, arch *sys.Arch, sym

// Decode the method name stored in symbol symIdx. The symbol should contain just the bytes of a method name.
func (d *deadcodePass) decodeGenericIfaceMethod(ldr *loader.Loader, symIdx loader.Sym) string {
return string(ldr.Data(symIdx))
return ldr.DataString(symIdx)
}

func (d *deadcodePass) decodetypeMethods(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, relocs *loader.Relocs) []methodsig {
Expand Down
10 changes: 7 additions & 3 deletions src/cmd/link/internal/ld/decodesym.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,9 +127,13 @@ func decodetypeName(ldr *loader.Loader, symIdx loader.Sym, relocs *loader.Relocs
return ""
}

data := ldr.Data(r)
nameLen, nameLenLen := binary.Uvarint(data[1:])
return string(data[1+nameLenLen : 1+nameLenLen+int(nameLen)])
data := ldr.DataString(r)
n := 1 + binary.MaxVarintLen64
if len(data) < n {
n = len(data)
}
nameLen, nameLenLen := binary.Uvarint([]byte(data[1:n]))
return data[1+nameLenLen : 1+nameLenLen+int(nameLen)]
}

func decodetypeNameEmbedded(ldr *loader.Loader, symIdx loader.Sym, relocs *loader.Relocs, off int) bool {
Expand Down
10 changes: 10 additions & 0 deletions src/cmd/link/internal/loader/loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -1247,6 +1247,16 @@ func (l *Loader) Data(i Sym) []byte {
return r.Data(li)
}

// Returns the symbol content of the i-th symbol as a string. i is global index.
func (l *Loader) DataString(i Sym) string {
if l.IsExternal(i) {
pp := l.getPayload(i)
return string(pp.data)
}
r, li := l.toLocal(i)
return r.DataString(li)
}

// FreeData clears the symbol data of an external symbol, allowing the memory
// to be freed earlier. No-op for non-external symbols.
// i is global index.
Expand Down

0 comments on commit 630ef2e

Please sign in to comment.