Commit 95b8cbfe authored by Matthew Dempsky's avatar Matthew Dempsky

cmd/compile: add column details to export data

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: default avatarRobert Griesemer <gri@golang.org>
Reviewed-by: default avatarRob Pike <r@golang.org>
parent 683ef8c8
...@@ -184,8 +184,9 @@ ...@@ -184,8 +184,9 @@
// } // }
// //
// //
// Pos encodes a file:line pair, incorporating a simple delta encoding // Pos encodes a file:line:column triple, incorporating a simple delta
// scheme within a data object. See exportWriter.pos for details. // encoding scheme within a data object. See exportWriter.pos for
// details.
// //
// //
// Compiler-specific details. // Compiler-specific details.
...@@ -212,8 +213,9 @@ import ( ...@@ -212,8 +213,9 @@ import (
) )
// Current indexed export format version. Increase with each format change. // Current indexed export format version. Increase with each format change.
// 1: added column details to Pos
// 0: Go1.11 encoding // 0: Go1.11 encoding
const iexportVersion = 0 const iexportVersion = 1
// predeclReserved is the number of type offsets reserved for types // predeclReserved is the number of type offsets reserved for types
// implicitly declared in the universe block. // implicitly declared in the universe block.
...@@ -405,6 +407,7 @@ type exportWriter struct { ...@@ -405,6 +407,7 @@ type exportWriter struct {
currPkg *types.Pkg currPkg *types.Pkg
prevFile string prevFile string
prevLine int64 prevLine int64
prevColumn int64
} }
func (p *iexporter) doDecl(n *Node) { func (p *iexporter) doDecl(n *Node) {
...@@ -510,29 +513,39 @@ func (w *exportWriter) pos(pos src.XPos) { ...@@ -510,29 +513,39 @@ func (w *exportWriter) pos(pos src.XPos) {
p := Ctxt.PosTable.Pos(pos) p := Ctxt.PosTable.Pos(pos)
file := p.Base().AbsFilename() file := p.Base().AbsFilename()
line := int64(p.RelLine()) line := int64(p.RelLine())
column := int64(p.RelCol())
// When file is the same as the last position (common case), // Encode position relative to the last position: column
// we can save a few bytes by delta encoding just the line // delta, then line delta, then file name. We reserve the
// number. // 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 // Note: Because data objects may be read out of order (or not
// at all), we can only apply delta encoding within a single // at all), we can only apply delta encoding within a single
// object. This is handled implicitly by tracking prevFile and // object. This is handled implicitly by tracking prevFile,
// prevLine as fields of exportWriter. // prevLine, and prevColumn as fields of exportWriter.
if file == w.prevFile { deltaColumn := (column - w.prevColumn) << 1
delta := line - w.prevLine deltaLine := (line - w.prevLine) << 1
w.int64(delta)
if delta == deltaNewFile { if file != w.prevFile {
w.int64(-1) deltaLine |= 1
} }
} else { if deltaLine != 0 {
w.int64(deltaNewFile) deltaColumn |= 1
w.int64(line) // line >= 0 }
w.int64(deltaColumn)
if deltaColumn&1 != 0 {
w.int64(deltaLine)
if deltaLine&1 != 0 {
w.string(file) w.string(file)
w.prevFile = file
} }
}
w.prevFile = file
w.prevLine = line w.prevLine = line
w.prevColumn = column
} }
func (w *exportWriter) pkg(pkg *types.Pkg) { func (w *exportWriter) pkg(pkg *types.Pkg) {
......
...@@ -245,6 +245,7 @@ type importReader struct { ...@@ -245,6 +245,7 @@ type importReader struct {
currPkg *types.Pkg currPkg *types.Pkg
prevBase *src.PosBase prevBase *src.PosBase
prevLine int64 prevLine int64
prevColumn int64
} }
func (p *iimporter) newReader(off uint64, pkg *types.Pkg) *importReader { func (p *iimporter) newReader(off uint64, pkg *types.Pkg) *importReader {
...@@ -446,16 +447,16 @@ func (r *importReader) qualifiedIdent() *types.Sym { ...@@ -446,16 +447,16 @@ func (r *importReader) qualifiedIdent() *types.Sym {
func (r *importReader) pos() src.XPos { func (r *importReader) pos() src.XPos {
delta := r.int64() delta := r.int64()
if delta != deltaNewFile { r.prevColumn += delta >> 1
r.prevLine += delta if delta&1 != 0 {
} else if l := r.int64(); l == -1 { delta = r.int64()
r.prevLine += deltaNewFile r.prevLine += delta >> 1
} else { if delta&1 != 0 {
r.prevBase = r.posBase() r.prevBase = r.posBase()
r.prevLine = l }
} }
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 // TODO(mdempsky): Remove once we reliably write
// position information for all nodes. // position information for all nodes.
return src.NoXPos return src.NoXPos
...@@ -464,7 +465,7 @@ func (r *importReader) pos() src.XPos { ...@@ -464,7 +465,7 @@ func (r *importReader) pos() src.XPos {
if r.prevBase == nil { if r.prevBase == nil {
Fatalf("missing posbase") 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) return Ctxt.PosTable.XPos(pos)
} }
......
...@@ -328,7 +328,7 @@ func (p *importer) pos() token.Pos { ...@@ -328,7 +328,7 @@ func (p *importer) pos() token.Pos {
p.prevFile = file p.prevFile = file
p.prevLine = line p.prevLine = line
return p.fake.pos(file, line) return p.fake.pos(file, line, 0)
} }
// Synthesize a token.Pos // Synthesize a token.Pos
...@@ -337,7 +337,9 @@ type fakeFileSet struct { ...@@ -337,7 +337,9 @@ type fakeFileSet struct {
files map[string]*token.File 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 // Since we don't know the set of needed file positions, we
// reserve maxlines positions per file. // reserve maxlines positions per file.
const maxlines = 64 * 1024 const maxlines = 64 * 1024
......
...@@ -61,8 +61,8 @@ const ( ...@@ -61,8 +61,8 @@ const (
// If the export data version is not recognized or the format is otherwise // If the export data version is not recognized or the format is otherwise
// compromised, an error is returned. // 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) { func iImportData(fset *token.FileSet, imports map[string]*types.Package, data []byte, path string) (_ int, pkg *types.Package, err error) {
const currentVersion = 0 const currentVersion = 1
version := -1 version := int64(-1)
defer func() { defer func() {
if e := recover(); e != nil { if e := recover(); e != nil {
if version > currentVersion { if version > currentVersion {
...@@ -75,9 +75,9 @@ func iImportData(fset *token.FileSet, imports map[string]*types.Package, data [] ...@@ -75,9 +75,9 @@ func iImportData(fset *token.FileSet, imports map[string]*types.Package, data []
r := &intReader{bytes.NewReader(data), path} r := &intReader{bytes.NewReader(data), path}
version = int(r.uint64()) version = int64(r.uint64())
switch version { switch version {
case currentVersion: case currentVersion, 0:
default: default:
errorf("unknown iexport format version %d", version) errorf("unknown iexport format version %d", version)
} }
...@@ -92,6 +92,7 @@ func iImportData(fset *token.FileSet, imports map[string]*types.Package, data [] ...@@ -92,6 +92,7 @@ func iImportData(fset *token.FileSet, imports map[string]*types.Package, data []
p := iimporter{ p := iimporter{
ipath: path, ipath: path,
version: int(version),
stringData: stringData, stringData: stringData,
stringCache: make(map[uint64]string), stringCache: make(map[uint64]string),
...@@ -170,6 +171,7 @@ func iImportData(fset *token.FileSet, imports map[string]*types.Package, data [] ...@@ -170,6 +171,7 @@ func iImportData(fset *token.FileSet, imports map[string]*types.Package, data []
type iimporter struct { type iimporter struct {
ipath string ipath string
version int
stringData []byte stringData []byte
stringCache map[uint64]string stringCache map[uint64]string
...@@ -249,6 +251,7 @@ type importReader struct { ...@@ -249,6 +251,7 @@ type importReader struct {
currPkg *types.Package currPkg *types.Package
prevFile string prevFile string
prevLine int64 prevLine int64
prevColumn int64
} }
func (r *importReader) obj(name string) { func (r *importReader) obj(name string) {
...@@ -438,6 +441,19 @@ func (r *importReader) qualifiedIdent() (*types.Package, string) { ...@@ -438,6 +441,19 @@ func (r *importReader) qualifiedIdent() (*types.Package, string) {
} }
func (r *importReader) pos() token.Pos { 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() delta := r.int64()
if delta != deltaNewFile { if delta != deltaNewFile {
r.prevLine += delta r.prevLine += delta
...@@ -447,12 +463,18 @@ func (r *importReader) pos() token.Pos { ...@@ -447,12 +463,18 @@ func (r *importReader) pos() token.Pos {
r.prevFile = r.string() r.prevFile = r.string()
r.prevLine = l r.prevLine = l
} }
}
if r.prevFile == "" && r.prevLine == 0 { func (r *importReader) posv1() {
return token.NoPos 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 { func (r *importReader) typ() types.Type {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment