Skip to content

Commit

Permalink
cmd/compile: add column details to export data
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
mdempsky committed Sep 27, 2019
1 parent 683ef8c commit 95b8cbf
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 47 deletions.
59 changes: 36 additions & 23 deletions src/cmd/compile/internal/gc/iexport.go
Original file line number Diff line number Diff line change
Expand Up @@ -184,8 +184,9 @@
// }
//
//
// 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.
Expand All @@ -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.
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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) {
Expand Down
25 changes: 13 additions & 12 deletions src/cmd/compile/internal/gc/iimport.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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
Expand All @@ -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)
}

Expand Down
6 changes: 4 additions & 2 deletions src/go/internal/gcimporter/bimport.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
42 changes: 32 additions & 10 deletions src/go/internal/gcimporter/iimport.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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)
}
Expand All @@ -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),
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -249,6 +251,7 @@ type importReader struct {
currPkg *types.Package
prevFile string
prevLine int64
prevColumn int64
}

func (r *importReader) obj(name string) {
Expand Down Expand Up @@ -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
Expand All @@ -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 {
Expand Down

0 comments on commit 95b8cbf

Please sign in to comment.