From e8afb2911125ad65ddc02f7b83ab78a3e2f573b7 Mon Sep 17 00:00:00 2001 From: David Chase Date: Thu, 22 Sep 2022 22:27:33 -0400 Subject: [PATCH] cmd/compile: introduce "temporary" readers for more storage reuse Change-Id: Id05d6099624284a9c1583b066d1a703e806b1e22 Reviewed-on: https://go-review.googlesource.com/c/go/+/433037 Run-TryBot: David Chase Reviewed-by: Keith Randall Reviewed-by: Cuong Manh Le TryBot-Result: Gopher Robot Reviewed-by: Keith Randall --- src/cmd/compile/internal/importer/ureader.go | 89 ++++++++++------ src/go/internal/gcimporter/ureader.go | 101 ++++++++++++------- src/internal/pkgbits/decoder.go | 70 +++++++++++-- 3 files changed, 183 insertions(+), 77 deletions(-) diff --git a/src/cmd/compile/internal/importer/ureader.go b/src/cmd/compile/internal/importer/ureader.go index a227ab64db..f5c2f41069 100644 --- a/src/cmd/compile/internal/importer/ureader.go +++ b/src/cmd/compile/internal/importer/ureader.go @@ -83,6 +83,17 @@ func (pr *pkgReader) newReader(k pkgbits.RelocKind, idx pkgbits.Index, marker pk } } +func (pr *pkgReader) tempReader(k pkgbits.RelocKind, idx pkgbits.Index, marker pkgbits.SyncMarker) *reader { + return &reader{ + Decoder: pr.TempDecoder(k, idx, marker), + p: pr, + } +} + +func (pr *pkgReader) retireReader(r *reader) { + pr.RetireDecoder(&r.Decoder) +} + // @@@ Positions func (r *reader) pos() syntax.Pos { @@ -106,19 +117,21 @@ func (pr *pkgReader) posBaseIdx(idx pkgbits.Index) *syntax.PosBase { if b := pr.posBases[idx]; b != nil { return b } - - r := pr.newReader(pkgbits.RelocPosBase, idx, pkgbits.SyncPosBase) var b *syntax.PosBase + { + r := pr.tempReader(pkgbits.RelocPosBase, idx, pkgbits.SyncPosBase) - filename := r.String() + filename := r.String() - if r.Bool() { - b = syntax.NewTrimmedFileBase(filename, true) - } else { - pos := r.pos() - line := r.Uint() - col := r.Uint() - b = syntax.NewLineBase(pos, filename, true, line, col) + if r.Bool() { + b = syntax.NewTrimmedFileBase(filename, true) + } else { + pos := r.pos() + line := r.Uint() + col := r.Uint() + b = syntax.NewLineBase(pos, filename, true, line, col) + } + pr.retireReader(r) } pr.posBases[idx] = b @@ -202,11 +215,15 @@ func (pr *pkgReader) typIdx(info typeInfo, dict *readerDict) types2.Type { return typ } - r := pr.newReader(pkgbits.RelocType, idx, pkgbits.SyncTypeIdx) - r.dict = dict + var typ types2.Type + { + r := pr.tempReader(pkgbits.RelocType, idx, pkgbits.SyncTypeIdx) + r.dict = dict - typ := r.doTyp() - assert(typ != nil) + typ = r.doTyp() + assert(typ != nil) + pr.retireReader(r) + } // See comment in pkgReader.typIdx explaining how this happens. if prev := *where; prev != nil { @@ -361,12 +378,18 @@ func (r *reader) obj() (types2.Object, []types2.Type) { } func (pr *pkgReader) objIdx(idx pkgbits.Index) (*types2.Package, string) { - rname := pr.newReader(pkgbits.RelocName, idx, pkgbits.SyncObject1) + var objPkg *types2.Package + var objName string + var tag pkgbits.CodeObj + { + rname := pr.tempReader(pkgbits.RelocName, idx, pkgbits.SyncObject1) - objPkg, objName := rname.qualifiedIdent() - assert(objName != "") + objPkg, objName = rname.qualifiedIdent() + assert(objName != "") - tag := pkgbits.CodeObj(rname.Code(pkgbits.SyncCodeObj)) + tag = pkgbits.CodeObj(rname.Code(pkgbits.SyncCodeObj)) + pr.retireReader(rname) + } if tag == pkgbits.ObjStub { base.Assertf(objPkg == nil || objPkg == types2.Unsafe, "unexpected stub package: %v", objPkg) @@ -431,25 +454,27 @@ func (pr *pkgReader) objIdx(idx pkgbits.Index) (*types2.Package, string) { } func (pr *pkgReader) objDictIdx(idx pkgbits.Index) *readerDict { - r := pr.newReader(pkgbits.RelocObjDict, idx, pkgbits.SyncObject1) - var dict readerDict + { + r := pr.tempReader(pkgbits.RelocObjDict, idx, pkgbits.SyncObject1) - if implicits := r.Len(); implicits != 0 { - base.Fatalf("unexpected object with %v implicit type parameter(s)", implicits) - } + if implicits := r.Len(); implicits != 0 { + base.Fatalf("unexpected object with %v implicit type parameter(s)", implicits) + } - dict.bounds = make([]typeInfo, r.Len()) - for i := range dict.bounds { - dict.bounds[i] = r.typInfo() - } + dict.bounds = make([]typeInfo, r.Len()) + for i := range dict.bounds { + dict.bounds[i] = r.typInfo() + } - dict.derived = make([]derivedInfo, r.Len()) - dict.derivedTypes = make([]types2.Type, len(dict.derived)) - for i := range dict.derived { - dict.derived[i] = derivedInfo{r.Reloc(pkgbits.RelocType), r.Bool()} - } + dict.derived = make([]derivedInfo, r.Len()) + dict.derivedTypes = make([]types2.Type, len(dict.derived)) + for i := range dict.derived { + dict.derived[i] = derivedInfo{r.Reloc(pkgbits.RelocType), r.Bool()} + } + pr.retireReader(r) + } // function references follow, but reader doesn't need those return &dict diff --git a/src/go/internal/gcimporter/ureader.go b/src/go/internal/gcimporter/ureader.go index ad8e9a43d9..94c1f2802a 100644 --- a/src/go/internal/gcimporter/ureader.go +++ b/src/go/internal/gcimporter/ureader.go @@ -131,6 +131,17 @@ func (pr *pkgReader) newReader(k pkgbits.RelocKind, idx pkgbits.Index, marker pk } } +func (pr *pkgReader) tempReader(k pkgbits.RelocKind, idx pkgbits.Index, marker pkgbits.SyncMarker) *reader { + return &reader{ + Decoder: pr.TempDecoder(k, idx, marker), + p: pr, + } +} + +func (pr *pkgReader) retireReader(r *reader) { + pr.RetireDecoder(&r.Decoder) +} + // @@@ Positions func (r *reader) pos() token.Pos { @@ -155,26 +166,29 @@ func (pr *pkgReader) posBaseIdx(idx pkgbits.Index) string { return b } - r := pr.newReader(pkgbits.RelocPosBase, idx, pkgbits.SyncPosBase) + var filename string + { + r := pr.tempReader(pkgbits.RelocPosBase, idx, pkgbits.SyncPosBase) - // Within types2, position bases have a lot more details (e.g., - // keeping track of where //line directives appeared exactly). - // - // For go/types, we just track the file name. + // Within types2, position bases have a lot more details (e.g., + // keeping track of where //line directives appeared exactly). + // + // For go/types, we just track the file name. - filename := r.String() + filename = r.String() - if r.Bool() { // file base - // Was: "b = token.NewTrimmedFileBase(filename, true)" - } else { // line base - pos := r.pos() - line := r.Uint() - col := r.Uint() + if r.Bool() { // file base + // Was: "b = token.NewTrimmedFileBase(filename, true)" + } else { // line base + pos := r.pos() + line := r.Uint() + col := r.Uint() - // Was: "b = token.NewLineBase(pos, filename, true, line, col)" - _, _, _ = pos, line, col + // Was: "b = token.NewLineBase(pos, filename, true, line, col)" + _, _, _ = pos, line, col + } + pr.retireReader(r) } - b := filename pr.posBases[idx] = b return b @@ -286,12 +300,15 @@ func (pr *pkgReader) typIdx(info typeInfo, dict *readerDict) types.Type { return typ } - r := pr.newReader(pkgbits.RelocType, idx, pkgbits.SyncTypeIdx) - r.dict = dict - - typ := r.doTyp() - assert(typ != nil) + var typ types.Type + { + r := pr.tempReader(pkgbits.RelocType, idx, pkgbits.SyncTypeIdx) + r.dict = dict + typ = r.doTyp() + assert(typ != nil) + pr.retireReader(r) + } // See comment in pkgReader.typIdx explaining how this happens. if prev := *where; prev != nil { return prev @@ -457,12 +474,19 @@ func (r *reader) obj() (types.Object, []types.Type) { } func (pr *pkgReader) objIdx(idx pkgbits.Index) (*types.Package, string) { - rname := pr.newReader(pkgbits.RelocName, idx, pkgbits.SyncObject1) - objPkg, objName := rname.qualifiedIdent() - assert(objName != "") + var objPkg *types.Package + var objName string + var tag pkgbits.CodeObj + { + rname := pr.tempReader(pkgbits.RelocName, idx, pkgbits.SyncObject1) - tag := pkgbits.CodeObj(rname.Code(pkgbits.SyncCodeObj)) + objPkg, objName = rname.qualifiedIdent() + assert(objName != "") + + tag = pkgbits.CodeObj(rname.Code(pkgbits.SyncCodeObj)) + pr.retireReader(rname) + } if tag == pkgbits.ObjStub { assert(objPkg == nil || objPkg == types.Unsafe) @@ -567,25 +591,28 @@ func (pr *pkgReader) objIdx(idx pkgbits.Index) (*types.Package, string) { } func (pr *pkgReader) objDictIdx(idx pkgbits.Index) *readerDict { - r := pr.newReader(pkgbits.RelocObjDict, idx, pkgbits.SyncObject1) var dict readerDict - if implicits := r.Len(); implicits != 0 { - errorf("unexpected object with %v implicit type parameter(s)", implicits) - } + { + r := pr.tempReader(pkgbits.RelocObjDict, idx, pkgbits.SyncObject1) + if implicits := r.Len(); implicits != 0 { + errorf("unexpected object with %v implicit type parameter(s)", implicits) + } - dict.bounds = make([]typeInfo, r.Len()) - for i := range dict.bounds { - dict.bounds[i] = r.typInfo() - } + dict.bounds = make([]typeInfo, r.Len()) + for i := range dict.bounds { + dict.bounds[i] = r.typInfo() + } - dict.derived = make([]derivedInfo, r.Len()) - dict.derivedTypes = make([]types.Type, len(dict.derived)) - for i := range dict.derived { - dict.derived[i] = derivedInfo{r.Reloc(pkgbits.RelocType), r.Bool()} - } + dict.derived = make([]derivedInfo, r.Len()) + dict.derivedTypes = make([]types.Type, len(dict.derived)) + for i := range dict.derived { + dict.derived[i] = derivedInfo{r.Reloc(pkgbits.RelocType), r.Bool()} + } + pr.retireReader(r) + } // function references follow, but reader doesn't need those return &dict diff --git a/src/internal/pkgbits/decoder.go b/src/internal/pkgbits/decoder.go index 357e328a3b..1a18da3301 100644 --- a/src/internal/pkgbits/decoder.go +++ b/src/internal/pkgbits/decoder.go @@ -52,6 +52,8 @@ type PkgDecoder struct { // For example, section K's end positions start at elemEndsEnds[K-1] // (or 0, if K==0) and end at elemEndsEnds[K]. elemEndsEnds [numRelocs]uint32 + + scratchRelocEnt []RelocEnt } // PkgPath returns the package path for the package @@ -165,6 +167,21 @@ func (pr *PkgDecoder) NewDecoder(k RelocKind, idx Index, marker SyncMarker) Deco return r } +// TempDecoder returns a Decoder for the given (section, index) pair, +// and decodes the given SyncMarker from the element bitstream. +// If possible the Decoder should be RetireDecoder'd when it is no longer +// needed, this will avoid heap allocations. +func (pr *PkgDecoder) TempDecoder(k RelocKind, idx Index, marker SyncMarker) Decoder { + r := pr.TempDecoderRaw(k, idx) + r.Sync(marker) + return r +} + +func (pr *PkgDecoder) RetireDecoder(d *Decoder) { + pr.scratchRelocEnt = d.Relocs + d.Relocs = nil +} + // NewDecoderRaw returns a Decoder for the given (section, index) pair. // // Most callers should use NewDecoder instead. @@ -186,6 +203,30 @@ func (pr *PkgDecoder) NewDecoderRaw(k RelocKind, idx Index) Decoder { return r } +func (pr *PkgDecoder) TempDecoderRaw(k RelocKind, idx Index) Decoder { + r := Decoder{ + common: pr, + k: k, + Idx: idx, + } + + r.Data.Reset(pr.DataIdx(k, idx)) + r.Sync(SyncRelocs) + l := r.Len() + if cap(pr.scratchRelocEnt) >= l { + r.Relocs = pr.scratchRelocEnt[:l] + pr.scratchRelocEnt = nil + } else { + r.Relocs = make([]RelocEnt, l) + } + for i := range r.Relocs { + r.Sync(SyncReloc) + r.Relocs[i] = RelocEnt{RelocKind(r.Len()), Index(r.Len())} + } + + return r +} + // A Decoder provides methods for decoding an individual element's // bitstream data. type Decoder struct { @@ -408,8 +449,12 @@ func (r *Decoder) bigFloat() *big.Float { // PeekPkgPath returns the package path for the specified package // index. func (pr *PkgDecoder) PeekPkgPath(idx Index) string { - r := pr.NewDecoder(RelocPkg, idx, SyncPkgDef) - path := r.String() + var path string + { + r := pr.TempDecoder(RelocPkg, idx, SyncPkgDef) + path = r.String() + pr.RetireDecoder(&r) + } if path == "" { path = pr.pkgPath } @@ -419,14 +464,23 @@ func (pr *PkgDecoder) PeekPkgPath(idx Index) string { // PeekObj returns the package path, object name, and CodeObj for the // specified object index. func (pr *PkgDecoder) PeekObj(idx Index) (string, string, CodeObj) { - r := pr.NewDecoder(RelocName, idx, SyncObject1) - r.Sync(SyncSym) - r.Sync(SyncPkg) - path := pr.PeekPkgPath(r.Reloc(RelocPkg)) - name := r.String() + var ridx Index + var name string + var rcode int + { + r := pr.TempDecoder(RelocName, idx, SyncObject1) + r.Sync(SyncSym) + r.Sync(SyncPkg) + ridx = r.Reloc(RelocPkg) + name = r.String() + rcode = r.Code(SyncCodeObj) + pr.RetireDecoder(&r) + } + + path := pr.PeekPkgPath(ridx) assert(name != "") - tag := CodeObj(r.Code(SyncCodeObj)) + tag := CodeObj(rcode) return path, name, tag } -- 2.50.0