From: Shahar Kohanim Date: Thu, 31 Mar 2016 15:34:02 +0000 (+0300) Subject: cmd/link: more idiomatic object reader X-Git-Tag: go1.7beta1~932 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=fe5be5aced063a16c5c36051045f8f8af313bed9;p=gostls13.git cmd/link: more idiomatic object reader name old secs new secs delta LinkCmdGo 0.52 ± 3% 0.52 ± 7% ~ (p=0.325 n=93+100) name old MaxRSS new MaxRSS delta LinkCmdGo 120k ± 1% 118k ± 4% -1.10% (p=0.000 n=87+96) Change-Id: I967660b8dc6036d28eeea1b6b30f400fadd57b05 Reviewed-on: https://go-review.googlesource.com/21372 Run-TryBot: Shahar Kohanim TryBot-Result: Gobot Gobot Reviewed-by: Brad Fitzpatrick --- diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go index 2f5d155f18..30ed0f51a4 100644 --- a/src/cmd/link/internal/ld/lib.go +++ b/src/cmd/link/internal/ld/lib.go @@ -1347,7 +1347,7 @@ func ldobj(f *obj.Biobuf, pkg string, length int64, pn string, file string, when ldpkg(f, pkg, import1-import0-2, pn, whence) // -2 for !\n obj.Bseek(f, import1, 0) - ldobjfile(Ctxt, f, pkg, eof-obj.Boffset(f), pn) + LoadObjFile(Ctxt, f, pkg, eof-obj.Boffset(f), pn) return nil } diff --git a/src/cmd/link/internal/ld/link.go b/src/cmd/link/internal/ld/link.go index e11b5dc900..67a855933e 100644 --- a/src/cmd/link/internal/ld/link.go +++ b/src/cmd/link/internal/ld/link.go @@ -189,7 +189,6 @@ type Link struct { Filesyms *LSym Moduledata *LSym LSymBatch []LSym - CurRefs []*LSym // List of symbol references for the file being read. } // The smallest possible offset from the hardware stack pointer to a local diff --git a/src/cmd/link/internal/ld/objfile.go b/src/cmd/link/internal/ld/objfile.go index b9121c6f81..bb6408aa82 100644 --- a/src/cmd/link/internal/ld/objfile.go +++ b/src/cmd/link/internal/ld/objfile.go @@ -108,8 +108,10 @@ package ld // - There are SymID in the object file that should really just be strings. import ( + "bufio" "bytes" "cmd/internal/obj" + "io" "log" "strconv" "strings" @@ -120,111 +122,143 @@ const ( endmagic = "\xff\xffgo13ld" ) -func ldobjfile(ctxt *Link, f *obj.Biobuf, pkg string, length int64, pn string) { +var emptyPkg = []byte(`"".`) + +// objReader reads Go object files. +type objReader struct { + rd *bufio.Reader + ctxt *Link + pkg string + pn string + // List of symbol references for the file being read. + dupSym *LSym + + // rdBuf is used by readString and readSymName as scratch for reading strings. + rdBuf []byte + + refs []*LSym + data []byte + reloc []Reloc + pcdata []Pcdata + autom []Auto + funcdata []*LSym + funcdataoff []int64 + file []*LSym +} + +func LoadObjFile(ctxt *Link, f *obj.Biobuf, pkg string, length int64, pn string) { start := obj.Boffset(f) - ctxt.IncVersion() + r := &objReader{ + rd: f.Reader(), + pkg: pkg, + ctxt: ctxt, + pn: pn, + dupSym: &LSym{Name: ".dup"}, + } + r.loadObjFile() + if obj.Boffset(f) != start+length { + log.Fatalf("%s: unexpected end at %d, want %d", pn, int64(obj.Boffset(f)), int64(start+length)) + } +} + +func (r *objReader) loadObjFile() { + // Increment context version, versions are used to differentiate static files in different packages + r.ctxt.IncVersion() + + // Magic header var buf [8]uint8 - obj.Bread(f, buf[:]) + r.readFull(buf[:]) if string(buf[:]) != startmagic { - log.Fatalf("%s: invalid file start %x %x %x %x %x %x %x %x", pn, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]) + log.Fatalf("%s: invalid file start %x %x %x %x %x %x %x %x", r.pn, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]) } - c := obj.Bgetc(f) - if c != 1 { - log.Fatalf("%s: invalid file version number %d", pn, c) + + // Version + c, err := r.rd.ReadByte() + if err != nil || c != 1 { + log.Fatalf("%s: invalid file version number %d", r.pn, c) } - var lib string + // Autolib for { - lib = rdstring(f) + lib := r.readString() if lib == "" { break } - addlib(ctxt, pkg, pn, lib) + addlib(r.ctxt, r.pkg, r.pn, lib) } - ctxt.CurRefs = []*LSym{nil} // zeroth ref is nil + // Symbol references + r.refs = []*LSym{nil} // zeroth ref is nil for { - c, err := f.Peek(1) + c, err := r.rd.Peek(1) if err != nil { - log.Fatalf("%s: peeking: %v", pn, err) + log.Fatalf("%s: peeking: %v", r.pn, err) } if c[0] == 0xff { - obj.Bgetc(f) + r.rd.ReadByte() break } - readref(ctxt, f, pkg, pn) + r.readRef() } - sl := rdslices(f) + // Lengths + r.readSlices() - obj.Bread(f, sl.data) + // Data section + r.readFull(r.data) + // Defined symbols for { - c, err := f.Peek(1) + c, err := r.rd.Peek(1) if err != nil { - log.Fatalf("%s: peeking: %v", pn, err) + log.Fatalf("%s: peeking: %v", r.pn, err) } if c[0] == 0xff { break } - readsym(ctxt, f, sl, pkg, pn) + r.readSym() } + // Magic footer buf = [8]uint8{} - obj.Bread(f, buf[:]) + r.readFull(buf[:]) if string(buf[:]) != endmagic { - log.Fatalf("%s: invalid file end", pn) - } - - if obj.Boffset(f) != start+length { - log.Fatalf("%s: unexpected end at %d, want %d", pn, int64(obj.Boffset(f)), int64(start+length)) + log.Fatalf("%s: invalid file end", r.pn) } } -var dupSym = &LSym{Name: ".dup"} - -type slices struct { - data []byte - reloc []Reloc - pcdata []Pcdata - autom []Auto - funcdata []*LSym - funcdataoff []int64 - file []*LSym +func (r *objReader) readSlices() { + n := r.readInt() + r.data = make([]byte, n) + n = r.readInt() + r.reloc = make([]Reloc, n) + n = r.readInt() + r.pcdata = make([]Pcdata, n) + n = r.readInt() + r.autom = make([]Auto, n) + n = r.readInt() + r.funcdata = make([]*LSym, n) + r.funcdataoff = make([]int64, n) + n = r.readInt() + r.file = make([]*LSym, n) } -func rdslices(f *obj.Biobuf) *slices { - sl := &slices{} - - n := rdint(f) - sl.data = make([]byte, n) - n = rdint(f) - sl.reloc = make([]Reloc, n) - n = rdint(f) - sl.pcdata = make([]Pcdata, n) - n = rdint(f) - sl.autom = make([]Auto, n) - n = rdint(f) - sl.funcdata = make([]*LSym, n) - sl.funcdataoff = make([]int64, n) - n = rdint(f) - sl.file = make([]*LSym, n) - return sl -} +// Symbols are prefixed so their content doesn't get confused with the magic footer. +const symPrefix = 0xfe -func readsym(ctxt *Link, f *obj.Biobuf, sl *slices, pkg string, pn string) { - if obj.Bgetc(f) != 0xfe { - log.Fatalln("readsym out of sync") +func (r *objReader) readSym() { + if c, err := r.rd.ReadByte(); c != symPrefix || err != nil { + log.Fatalln("readSym out of sync") } - t := rdint(f) - s := rdsym(ctxt, f, pkg) - flags := rdint(f) + t := r.readInt() + s := r.readSymIndex() + flags := r.readInt() dupok := flags&1 != 0 local := flags&2 != 0 - size := rdint(f) - typ := rdsym(ctxt, f, pkg) - data := rddata(f, &sl.data) - nreloc := rdint(f) + size := r.readInt() + typ := r.readSymIndex() + data := r.readData() + nreloc := r.readInt() isdup := false var dup *LSym @@ -243,17 +277,17 @@ func readsym(ctxt *Link, f *obj.Biobuf, sl *slices, pkg string, pn string) { goto overwrite } if s.Type != obj.SBSS && s.Type != obj.SNOPTRBSS && !dupok && !s.Attr.DuplicateOK() { - log.Fatalf("duplicate symbol %s (types %d and %d) in %s and %s", s.Name, s.Type, t, s.File, pn) + log.Fatalf("duplicate symbol %s (types %d and %d) in %s and %s", s.Name, s.Type, t, s.File, r.pn) } if len(s.P) > 0 { dup = s - s = dupSym + s = r.dupSym isdup = true } } overwrite: - s.File = pkg + s.File = r.pkg if dupok { s.Attr |= AttrDuplicateOK } @@ -261,7 +295,7 @@ overwrite: log.Fatalf("bad sxref") } if t == 0 { - log.Fatalf("missing type for %s in %s", s.Name, pn) + log.Fatalf("missing type for %s in %s", s.Name, r.pn) } if t == obj.SBSS && (s.Type == obj.SRODATA || s.Type == obj.SNOPTRBSS) { t = int(s.Type) @@ -279,80 +313,80 @@ overwrite: } s.P = data if nreloc > 0 { - s.R = sl.reloc[:nreloc:nreloc] + s.R = r.reloc[:nreloc:nreloc] if !isdup { - sl.reloc = sl.reloc[nreloc:] + r.reloc = r.reloc[nreloc:] } - var r *Reloc for i := 0; i < nreloc; i++ { - r = &s.R[i] - r.Off = rdint32(f) - r.Siz = rduint8(f) - r.Type = rdint32(f) - r.Add = rdint64(f) - r.Sym = rdsym(ctxt, f, pkg) + s.R[i] = Reloc{ + Off: r.readInt32(), + Siz: r.readUint8(), + Type: r.readInt32(), + Add: r.readInt64(), + Sym: r.readSymIndex(), + } } } if s.Type == obj.STEXT { - s.Args = rdint32(f) - s.Locals = rdint32(f) - if rduint8(f) != 0 { + s.Args = r.readInt32() + s.Locals = r.readInt32() + if r.readUint8() != 0 { s.Attr |= AttrNoSplit } - flags := rdint(f) + flags := r.readInt() if flags&(1<<2) != 0 { s.Attr |= AttrReflectMethod } - n := rdint(f) - s.Autom = sl.autom[:n:n] + n := r.readInt() + s.Autom = r.autom[:n:n] if !isdup { - sl.autom = sl.autom[n:] + r.autom = r.autom[n:] } for i := 0; i < n; i++ { s.Autom[i] = Auto{ - Asym: rdsym(ctxt, f, pkg), - Aoffset: rdint32(f), - Name: rdint16(f), - Gotype: rdsym(ctxt, f, pkg), + Asym: r.readSymIndex(), + Aoffset: r.readInt32(), + Name: r.readInt16(), + Gotype: r.readSymIndex(), } } s.Pcln = new(Pcln) pc := s.Pcln - pc.Pcsp.P = rddata(f, &sl.data) - pc.Pcfile.P = rddata(f, &sl.data) - pc.Pcline.P = rddata(f, &sl.data) - n = rdint(f) - pc.Pcdata = sl.pcdata[:n:n] + pc.Pcsp.P = r.readData() + pc.Pcfile.P = r.readData() + pc.Pcline.P = r.readData() + n = r.readInt() + pc.Pcdata = r.pcdata[:n:n] if !isdup { - sl.pcdata = sl.pcdata[n:] + r.pcdata = r.pcdata[n:] } for i := 0; i < n; i++ { - pc.Pcdata[i].P = rddata(f, &sl.data) + pc.Pcdata[i].P = r.readData() } - n = rdint(f) - pc.Funcdata = sl.funcdata[:n:n] - pc.Funcdataoff = sl.funcdataoff[:n:n] + n = r.readInt() + pc.Funcdata = r.funcdata[:n:n] + pc.Funcdataoff = r.funcdataoff[:n:n] if !isdup { - sl.funcdata = sl.funcdata[n:] - sl.funcdataoff = sl.funcdataoff[n:] + r.funcdata = r.funcdata[n:] + r.funcdataoff = r.funcdataoff[n:] } for i := 0; i < n; i++ { - pc.Funcdata[i] = rdsym(ctxt, f, pkg) + pc.Funcdata[i] = r.readSymIndex() } for i := 0; i < n; i++ { - pc.Funcdataoff[i] = rdint64(f) + pc.Funcdataoff[i] = r.readInt64() } - n = rdint(f) - pc.File = sl.file[:n:n] + n = r.readInt() + pc.File = r.file[:n:n] if !isdup { - sl.file = sl.file[n:] + r.file = r.file[n:] } for i := 0; i < n; i++ { - pc.File[i] = rdsym(ctxt, f, pkg) + pc.File[i] = r.readSymIndex() } if !isdup { @@ -360,30 +394,37 @@ overwrite: log.Fatalf("symbol %s listed multiple times", s.Name) } s.Attr |= AttrOnList - if ctxt.Etextp != nil { - ctxt.Etextp.Next = s + if r.ctxt.Etextp != nil { + r.ctxt.Etextp.Next = s } else { - ctxt.Textp = s + r.ctxt.Textp = s } - ctxt.Etextp = s + r.ctxt.Etextp = s } } } -func readref(ctxt *Link, f *obj.Biobuf, pkg string, pn string) { - if obj.Bgetc(f) != 0xfe { - log.Fatalf("readsym out of sync") +func (r *objReader) readFull(b []byte) { + _, err := io.ReadFull(r.rd, b) + if err != nil { + log.Fatalf("%s: error reading %s", r.pn, err) + } +} + +func (r *objReader) readRef() { + if c, err := r.rd.ReadByte(); c != symPrefix || err != nil { + log.Fatalf("readSym out of sync") } - name := rdsymName(f, pkg) - v := rdint(f) + name := r.readSymName() + v := r.readInt() if v != 0 && v != 1 { log.Fatalf("invalid symbol version %d", v) } if v == 1 { - v = ctxt.Version + v = r.ctxt.Version } - s := Linklookup(ctxt, name, v) - ctxt.CurRefs = append(ctxt.CurRefs, s) + s := Linklookup(r.ctxt, name, v) + r.refs = append(r.refs, s) if s == nil || v != 0 { return @@ -400,9 +441,9 @@ func readref(ctxt *Link, f *obj.Biobuf, pkg string, pn string) { if uint64(uint32(x)) != x { log.Panicf("$-symbol %s too large: %d", s.Name, x) } - Adduint32(ctxt, s, uint32(x)) + Adduint32(r.ctxt, s, uint32(x)) case "$f64.", "$i64.": - Adduint64(ctxt, s, x) + Adduint64(r.ctxt, s, x) default: log.Panicf("unrecognized $-symbol: %s", s.Name) } @@ -413,14 +454,13 @@ func readref(ctxt *Link, f *obj.Biobuf, pkg string, pn string) { } } -func rdint64(f *obj.Biobuf) int64 { - r := f.Reader() +func (r *objReader) readInt64() int64 { uv := uint64(0) for shift := uint(0); ; shift += 7 { if shift >= 64 { log.Fatalf("corrupt input") } - c, err := r.ReadByte() + c, err := r.rd.ReadByte() if err != nil { log.Fatalln("error reading input: ", err) } @@ -433,63 +473,61 @@ func rdint64(f *obj.Biobuf) int64 { return int64(uv>>1) ^ (int64(uint64(uv)<<63) >> 63) } -func rdint(f *obj.Biobuf) int { - n := rdint64(f) +func (r *objReader) readInt() int { + n := r.readInt64() if int64(int(n)) != n { log.Panicf("%v out of range for int", n) } return int(n) } -func rdint32(f *obj.Biobuf) int32 { - n := rdint64(f) +func (r *objReader) readInt32() int32 { + n := r.readInt64() if int64(int32(n)) != n { log.Panicf("%v out of range for int32", n) } return int32(n) } -func rdint16(f *obj.Biobuf) int16 { - n := rdint64(f) +func (r *objReader) readInt16() int16 { + n := r.readInt64() if int64(int16(n)) != n { log.Panicf("%v out of range for int16", n) } return int16(n) } -func rduint8(f *obj.Biobuf) uint8 { - n := rdint64(f) +func (r *objReader) readUint8() uint8 { + n := r.readInt64() if int64(uint8(n)) != n { log.Panicf("%v out of range for uint8", n) } 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 := rdint(f) - if len(rdBuf) < n { - rdBuf = make([]byte, n) +func (r *objReader) readString() string { + n := r.readInt() + if len(r.rdBuf) < n { + r.rdBuf = make([]byte, n) } - obj.Bread(f, rdBuf[:n]) - return string(rdBuf[:n]) + r.readFull(r.rdBuf[:n]) + return string(r.rdBuf[:n]) } -func rddata(f *obj.Biobuf, buf *[]byte) []byte { - n := rdint(f) - p := (*buf)[:n:n] - *buf = (*buf)[n:] +func (r *objReader) readData() []byte { + n := r.readInt() + p := r.data[:n:n] + r.data = r.data[n:] return p } -// rdsymName reads a symbol name, replacing all "". with pkg. -func rdsymName(f *obj.Biobuf, pkg string) string { - n := rdint(f) +// readSymName reads a symbol name, replacing all "". with pkg. +func (r *objReader) readSymName() string { + rdBuf := r.rdBuf + pkg := r.pkg + n := r.readInt() if n == 0 { - rdint64(f) + r.readInt64() return "" } @@ -497,7 +535,7 @@ func rdsymName(f *obj.Biobuf, pkg string) string { rdBuf = make([]byte, n, 2*n) } origName := rdBuf[:n] - obj.Bread(f, origName) + r.readFull(origName) adjName := rdBuf[n:n] for { i := bytes.Index(origName, emptyPkg) @@ -512,12 +550,13 @@ func rdsymName(f *obj.Biobuf, pkg string) string { } name := string(adjName) if len(adjName) > len(rdBuf) { - rdBuf = adjName // save the larger buffer for reuse + r.rdBuf = adjName // save the larger buffer for reuse } return name } -func rdsym(ctxt *Link, f *obj.Biobuf, pkg string) *LSym { - i := rdint(f) - return ctxt.CurRefs[i] +// Reads the index of a symbol reference and resolves it to a symbol +func (r *objReader) readSymIndex() *LSym { + i := r.readInt() + return r.refs[i] }