]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: add column details to export data
authorMatthew Dempsky <mdempsky@google.com>
Mon, 23 Sep 2019 21:25:22 +0000 (14:25 -0700)
committerMatthew Dempsky <mdempsky@google.com>
Fri, 27 Sep 2019 18:38:37 +0000 (18:38 +0000)
This CL updates the export data format to include column details when
writing out position data. cmd/compile is updated to generate and make
use of the new details, but go/internal/gcimporter only knows how to
read the data. It doesn't yet actually make use of it.

Experimentally across a wide range of packages, this increases export
data size by around 4%. However, it has no impact on binary size.
(Notably, it actually shrinks k8s.io/kubernetes/cmd/kubelet's binary
size by 24kB, but it's unclear to me why at this time.)

Updates #28259.

Change-Id: I351fb340839df8d3adced49b3757c4537fb91b3f
Reviewed-on: https://go-review.googlesource.com/c/go/+/196963
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
src/cmd/compile/internal/gc/iexport.go
src/cmd/compile/internal/gc/iimport.go
src/go/internal/gcimporter/bimport.go
src/go/internal/gcimporter/iimport.go

index 873de46fa408fb851384410829dad54327ddce6a..a5acd26c7fabe70455062b80a49a3690fc91ed7b 100644 (file)
 //     }
 //
 //
-// Pos encodes a file:line pair, incorporating a simple delta encoding
-// scheme within a data object. See exportWriter.pos for details.
+// Pos encodes a file:line:column triple, incorporating a simple delta
+// encoding scheme within a data object. See exportWriter.pos for
+// details.
 //
 //
 // Compiler-specific details.
@@ -212,8 +213,9 @@ import (
 )
 
 // Current indexed export format version. Increase with each format change.
+// 1: added column details to Pos
 // 0: Go1.11 encoding
-const iexportVersion = 0
+const iexportVersion = 1
 
 // predeclReserved is the number of type offsets reserved for types
 // implicitly declared in the universe block.
@@ -401,10 +403,11 @@ func (p *iexporter) pushDecl(n *Node) {
 type exportWriter struct {
        p *iexporter
 
-       data     intWriter
-       currPkg  *types.Pkg
-       prevFile string
-       prevLine int64
+       data       intWriter
+       currPkg    *types.Pkg
+       prevFile   string
+       prevLine   int64
+       prevColumn int64
 }
 
 func (p *iexporter) doDecl(n *Node) {
@@ -510,29 +513,39 @@ func (w *exportWriter) pos(pos src.XPos) {
        p := Ctxt.PosTable.Pos(pos)
        file := p.Base().AbsFilename()
        line := int64(p.RelLine())
+       column := int64(p.RelCol())
 
-       // When file is the same as the last position (common case),
-       // we can save a few bytes by delta encoding just the line
-       // number.
+       // Encode position relative to the last position: column
+       // delta, then line delta, then file name. We reserve the
+       // bottom bit of the column and line deltas to encode whether
+       // the remaining fields are present.
        //
        // Note: Because data objects may be read out of order (or not
        // at all), we can only apply delta encoding within a single
-       // object. This is handled implicitly by tracking prevFile and
-       // prevLine as fields of exportWriter.
-
-       if file == w.prevFile {
-               delta := line - w.prevLine
-               w.int64(delta)
-               if delta == deltaNewFile {
-                       w.int64(-1)
+       // object. This is handled implicitly by tracking prevFile,
+       // prevLine, and prevColumn as fields of exportWriter.
+
+       deltaColumn := (column - w.prevColumn) << 1
+       deltaLine := (line - w.prevLine) << 1
+
+       if file != w.prevFile {
+               deltaLine |= 1
+       }
+       if deltaLine != 0 {
+               deltaColumn |= 1
+       }
+
+       w.int64(deltaColumn)
+       if deltaColumn&1 != 0 {
+               w.int64(deltaLine)
+               if deltaLine&1 != 0 {
+                       w.string(file)
                }
-       } else {
-               w.int64(deltaNewFile)
-               w.int64(line) // line >= 0
-               w.string(file)
-               w.prevFile = file
        }
+
+       w.prevFile = file
        w.prevLine = line
+       w.prevColumn = column
 }
 
 func (w *exportWriter) pkg(pkg *types.Pkg) {
index 28808c51c50ed822fadd7e0ee8177f4ea5f1525d..64c554d187fcd03bf4c275dff27d6ab5c8094790 100644 (file)
@@ -242,9 +242,10 @@ type importReader struct {
        strings.Reader
        p *iimporter
 
-       currPkg  *types.Pkg
-       prevBase *src.PosBase
-       prevLine int64
+       currPkg    *types.Pkg
+       prevBase   *src.PosBase
+       prevLine   int64
+       prevColumn int64
 }
 
 func (p *iimporter) newReader(off uint64, pkg *types.Pkg) *importReader {
@@ -446,16 +447,16 @@ func (r *importReader) qualifiedIdent() *types.Sym {
 
 func (r *importReader) pos() src.XPos {
        delta := r.int64()
-       if delta != deltaNewFile {
-               r.prevLine += delta
-       } else if l := r.int64(); l == -1 {
-               r.prevLine += deltaNewFile
-       } else {
-               r.prevBase = r.posBase()
-               r.prevLine = l
+       r.prevColumn += delta >> 1
+       if delta&1 != 0 {
+               delta = r.int64()
+               r.prevLine += delta >> 1
+               if delta&1 != 0 {
+                       r.prevBase = r.posBase()
+               }
        }
 
-       if (r.prevBase == nil || r.prevBase.AbsFilename() == "") && r.prevLine == 0 {
+       if (r.prevBase == nil || r.prevBase.AbsFilename() == "") && r.prevLine == 0 && r.prevColumn == 0 {
                // TODO(mdempsky): Remove once we reliably write
                // position information for all nodes.
                return src.NoXPos
@@ -464,7 +465,7 @@ func (r *importReader) pos() src.XPos {
        if r.prevBase == nil {
                Fatalf("missing posbase")
        }
-       pos := src.MakePos(r.prevBase, uint(r.prevLine), 0)
+       pos := src.MakePos(r.prevBase, uint(r.prevLine), uint(r.prevColumn))
        return Ctxt.PosTable.XPos(pos)
 }
 
index cf03632aa201bd923cc4f43d454b13c212c5cd57..1019ccb8f77668e2579b654bc4a94f581fe0f8ee 100644 (file)
@@ -328,7 +328,7 @@ func (p *importer) pos() token.Pos {
        p.prevFile = file
        p.prevLine = line
 
-       return p.fake.pos(file, line)
+       return p.fake.pos(file, line, 0)
 }
 
 // Synthesize a token.Pos
@@ -337,7 +337,9 @@ type fakeFileSet struct {
        files map[string]*token.File
 }
 
-func (s *fakeFileSet) pos(file string, line int) token.Pos {
+func (s *fakeFileSet) pos(file string, line, column int) token.Pos {
+       // TODO(mdempsky): Make use of column.
+
        // Since we don't know the set of needed file positions, we
        // reserve maxlines positions per file.
        const maxlines = 64 * 1024
index bf480641df94816c4da94e131c96ee873ec82a17..c59dd16533173506db93882e8c14c7f10b9950e4 100644 (file)
@@ -61,8 +61,8 @@ const (
 // If the export data version is not recognized or the format is otherwise
 // compromised, an error is returned.
 func iImportData(fset *token.FileSet, imports map[string]*types.Package, data []byte, path string) (_ int, pkg *types.Package, err error) {
-       const currentVersion = 0
-       version := -1
+       const currentVersion = 1
+       version := int64(-1)
        defer func() {
                if e := recover(); e != nil {
                        if version > currentVersion {
@@ -75,9 +75,9 @@ func iImportData(fset *token.FileSet, imports map[string]*types.Package, data []
 
        r := &intReader{bytes.NewReader(data), path}
 
-       version = int(r.uint64())
+       version = int64(r.uint64())
        switch version {
-       case currentVersion:
+       case currentVersion, 0:
        default:
                errorf("unknown iexport format version %d", version)
        }
@@ -91,7 +91,8 @@ func iImportData(fset *token.FileSet, imports map[string]*types.Package, data []
        r.Seek(sLen+dLen, io.SeekCurrent)
 
        p := iimporter{
-               ipath: path,
+               ipath:   path,
+               version: int(version),
 
                stringData:  stringData,
                stringCache: make(map[uint64]string),
@@ -169,7 +170,8 @@ func iImportData(fset *token.FileSet, imports map[string]*types.Package, data []
 }
 
 type iimporter struct {
-       ipath string
+       ipath   string
+       version int
 
        stringData  []byte
        stringCache map[uint64]string
@@ -249,6 +251,7 @@ type importReader struct {
        currPkg    *types.Package
        prevFile   string
        prevLine   int64
+       prevColumn int64
 }
 
 func (r *importReader) obj(name string) {
@@ -438,6 +441,19 @@ func (r *importReader) qualifiedIdent() (*types.Package, string) {
 }
 
 func (r *importReader) pos() token.Pos {
+       if r.p.version >= 1 {
+               r.posv1()
+       } else {
+               r.posv0()
+       }
+
+       if r.prevFile == "" && r.prevLine == 0 && r.prevColumn == 0 {
+               return token.NoPos
+       }
+       return r.p.fake.pos(r.prevFile, int(r.prevLine), int(r.prevColumn))
+}
+
+func (r *importReader) posv0() {
        delta := r.int64()
        if delta != deltaNewFile {
                r.prevLine += delta
@@ -447,12 +463,18 @@ func (r *importReader) pos() token.Pos {
                r.prevFile = r.string()
                r.prevLine = l
        }
+}
 
-       if r.prevFile == "" && r.prevLine == 0 {
-               return token.NoPos
+func (r *importReader) posv1() {
+       delta := r.int64()
+       r.prevColumn += delta >> 1
+       if delta&1 != 0 {
+               delta = r.int64()
+               r.prevLine += delta >> 1
+               if delta&1 != 0 {
+                       r.prevFile = r.string()
+               }
        }
-
-       return r.p.fake.pos(r.prevFile, int(r.prevLine))
 }
 
 func (r *importReader) typ() types.Type {