From 07ccc21295e45732e70bc0e81fe8739681c6c34b Mon Sep 17 00:00:00 2001 From: David Crawshaw Date: Sun, 28 Feb 2016 15:59:33 -0900 Subject: [PATCH] cmd/link: skip allocation when reading symbol name The object file reader in cmd/link reads the symbol name into a scratch []byte, converts it to a string, and then does a substring replacement. Instead, this CL does the replacement on the []byte into the scratch space and then creates the final string. Linking godoc without DWARF, best of ten, shows a ~10% improvement. tip: real 0m1.099s user 0m1.541s this: real 0m0.990s user 0m1.280s This is part of an attempt to make suffixarray string deduping come out as a wash, but it's not there yet: cl/19987: real 0m1.335s user 0m1.794s cl/19987+this: real 0m1.225s user 0m1.540s Change-Id: Idf061fdfbd7f08aa3a1f5933d3f111fdd1659210 Reviewed-on: https://go-review.googlesource.com/20025 Reviewed-by: Ian Lance Taylor Run-TryBot: David Crawshaw Reviewed-by: Brad Fitzpatrick --- src/cmd/link/internal/ld/objfile.go | 57 ++++++++++++++++++++++------- 1 file changed, 43 insertions(+), 14 deletions(-) diff --git a/src/cmd/link/internal/ld/objfile.go b/src/cmd/link/internal/ld/objfile.go index b04244f3cc9..11cdf91d749 100644 --- a/src/cmd/link/internal/ld/objfile.go +++ b/src/cmd/link/internal/ld/objfile.go @@ -165,7 +165,7 @@ func readsym(ctxt *Link, f *obj.Biobuf, pkg string, pn string) { log.Fatalf("readsym out of sync") } t := rdint(f) - name := expandpkg(rdstring(f), pkg) + name := rdsymName(f, pkg) v := rdint(f) if v != 0 && v != 1 { log.Fatalf("invalid symbol version %d", v) @@ -424,11 +424,17 @@ func rduint8(f *obj.Biobuf) uint8 { return uint8(n) } +// rdBuf is used by rdstring and rdsymName as scratch for reading strings. +var rdBuf []byte +var emptyPkg = []byte(`"".`) + func rdstring(f *obj.Biobuf) string { - n := rdint64(f) - p := make([]byte, n) - obj.Bread(f, p) - return string(p) + n := rdint(f) + if len(rdBuf) < n { + rdBuf = make([]byte, n) + } + obj.Bread(f, rdBuf[:n]) + return string(rdBuf[:n]) } var ( @@ -452,25 +458,48 @@ func rddata(f *obj.Biobuf) []byte { return p } -var symbuf []byte - -func rdsym(ctxt *Link, f *obj.Biobuf, pkg string) *LSym { +// rdsymName reads a symbol name, replacing all "". with pkg. +func rdsymName(f *obj.Biobuf, pkg string) string { n := rdint(f) if n == 0 { rdint64(f) - return nil + return "" } - if len(symbuf) < n { - symbuf = make([]byte, n) + if len(rdBuf) < n { + rdBuf = make([]byte, n, 2*n) + } + origName := rdBuf[:n] + obj.Bread(f, origName) + adjName := rdBuf[n:n] + for { + i := bytes.Index(origName, emptyPkg) + if i == -1 { + adjName = append(adjName, origName...) + break + } + adjName = append(adjName, origName[:i]...) + adjName = append(adjName, pkg...) + adjName = append(adjName, '.') + origName = origName[i+len(emptyPkg):] + } + name := string(adjName) + if len(adjName) > len(rdBuf) { + rdBuf = adjName // save the larger buffer for reuse + } + return name +} + +func rdsym(ctxt *Link, f *obj.Biobuf, pkg string) *LSym { + name := rdsymName(f, pkg) + if name == "" { + return nil } - obj.Bread(f, symbuf[:n]) - p := string(symbuf[:n]) v := rdint(f) if v != 0 { v = ctxt.Version } - s := Linklookup(ctxt, expandpkg(p, pkg), v) + s := Linklookup(ctxt, name, v) if v == 0 && s.Name[0] == '$' && s.Type == 0 { if strings.HasPrefix(s.Name, "$f32.") {