cmd/compile/internal/syntax: remove dependency on cmd/internal/src

For dependency reasons, the data structure implementing source
positions in the compiler is in cmd/internal/src. It contains
highly compiler specific details (e.g. inlining index).

This change introduces a parallel but simpler position
representation, defined in the syntax package, which removes
that package's dependency on cmd/internal/src, and also removes
the need to deal with certain filename-specific operations
(defined by the needs of the compiler) in the syntax package.
As a result, the syntax package becomes again a compiler-
independent, stand-alone package that at some point might
replace (or augment) the existing top-level go/* syntax-related
packages.

Additionally, line directives that update column numbers
are now correctly tracked through the syntax package, with
additional tests added. (The respective changes also need to
be made in cmd/internal/src; i.e., the compiler accepts but
still ignores column numbers in line directives.)

This change comes at the cost of a new position translation
step, but that step is cheap because it only needs to do real
work if the position base changed (i.e., if there is a new file,
or new line directive).

There is no noticeable impact on overall compiler performance
measured with `compilebench -count 5 -alloc`:

name       old time/op       new time/op       delta
Template         220ms ± 8%        228ms ±18%    ~     (p=0.548 n=5+5)
Unicode          119ms ±11%        113ms ± 5%    ~     (p=0.056 n=5+5)
GoTypes          684ms ± 6%        677ms ± 3%    ~     (p=0.841 n=5+5)
Compiler         3.19s ± 7%        3.01s ± 1%    ~     (p=0.095 n=5+5)
SSA              7.92s ± 8%        7.79s ± 1%    ~     (p=0.690 n=5+5)
Flate            141ms ± 7%        139ms ± 4%    ~     (p=0.548 n=5+5)
GoParser         173ms ±12%        171ms ± 4%    ~     (p=1.000 n=5+5)
Reflect          417ms ± 5%        411ms ± 3%    ~     (p=0.548 n=5+5)
Tar              205ms ± 5%        198ms ± 2%    ~     (p=0.690 n=5+5)
XML              232ms ± 4%        229ms ± 4%    ~     (p=0.690 n=5+5)
StdCmd           28.7s ± 5%        28.2s ± 2%    ~     (p=0.421 n=5+5)

name       old user-time/op  new user-time/op  delta
Template         269ms ± 4%        265ms ± 5%    ~     (p=0.421 n=5+5)
Unicode          153ms ± 7%        149ms ± 3%    ~     (p=0.841 n=5+5)
GoTypes          850ms ± 7%        862ms ± 4%    ~     (p=0.841 n=5+5)
Compiler         4.01s ± 5%        3.86s ± 0%    ~     (p=0.190 n=5+4)
SSA              10.9s ± 4%        10.8s ± 2%    ~     (p=0.548 n=5+5)
Flate            166ms ± 7%        167ms ± 6%    ~     (p=1.000 n=5+5)
GoParser         204ms ± 8%        206ms ± 7%    ~     (p=0.841 n=5+5)
Reflect          514ms ± 5%        508ms ± 4%    ~     (p=0.548 n=5+5)
Tar              245ms ± 6%        244ms ± 3%    ~     (p=0.690 n=5+5)
XML              280ms ± 4%        278ms ± 4%    ~     (p=0.841 n=5+5)

name       old alloc/op      new alloc/op      delta
Template        37.9MB ± 0%       37.9MB ± 0%    ~     (p=0.841 n=5+5)
Unicode         28.8MB ± 0%       28.8MB ± 0%    ~     (p=0.841 n=5+5)
GoTypes          113MB ± 0%        113MB ± 0%    ~     (p=0.151 n=5+5)
Compiler         468MB ± 0%        468MB ± 0%  -0.01%  (p=0.032 n=5+5)
SSA             1.50GB ± 0%       1.50GB ± 0%    ~     (p=0.548 n=5+5)
Flate           24.4MB ± 0%       24.4MB ± 0%    ~     (p=1.000 n=5+5)
GoParser        30.7MB ± 0%       30.7MB ± 0%    ~     (p=1.000 n=5+5)
Reflect         76.5MB ± 0%       76.5MB ± 0%    ~     (p=0.548 n=5+5)
Tar             38.9MB ± 0%       38.9MB ± 0%    ~     (p=0.222 n=5+5)
XML             41.6MB ± 0%       41.6MB ± 0%    ~     (p=0.548 n=5+5)

name       old allocs/op     new allocs/op     delta
Template          382k ± 0%         382k ± 0%  +0.01%  (p=0.008 n=5+5)
Unicode           343k ± 0%         343k ± 0%    ~     (p=0.841 n=5+5)
GoTypes          1.19M ± 0%        1.19M ± 0%  +0.01%  (p=0.008 n=5+5)
Compiler         4.53M ± 0%        4.53M ± 0%  +0.03%  (p=0.008 n=5+5)
SSA              12.4M ± 0%        12.4M ± 0%  +0.00%  (p=0.008 n=5+5)
Flate             235k ± 0%         235k ± 0%    ~     (p=0.079 n=5+5)
GoParser          318k ± 0%         318k ± 0%    ~     (p=0.730 n=5+5)
Reflect           978k ± 0%         978k ± 0%    ~     (p=1.000 n=5+5)
Tar               393k ± 0%         393k ± 0%    ~     (p=0.056 n=5+5)
XML               405k ± 0%         405k ± 0%    ~     (p=0.548 n=5+5)

name       old text-bytes    new text-bytes    delta
HelloSize        672kB ± 0%        672kB ± 0%    ~     (all equal)
CmdGoSize       7.12MB ± 0%       7.12MB ± 0%    ~     (all equal)

name       old data-bytes    new data-bytes    delta
HelloSize        133kB ± 0%        133kB ± 0%    ~     (all equal)
CmdGoSize        390kB ± 0%        390kB ± 0%    ~     (all equal)

name       old exe-bytes     new exe-bytes     delta
HelloSize       1.07MB ± 0%       1.07MB ± 0%    ~     (all equal)
CmdGoSize       11.2MB ± 0%       11.2MB ± 0%    ~     (all equal)

Passes toolstash compare.

For #22662.

Change-Id: I19edb53dd9675af57f7122cb7dba2a6d8bdcc3da
Reviewed-on: https://go-review.googlesource.com/94515
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
This commit is contained in:
Robert Griesemer 2018-01-02 16:58:37 -08:00
parent b1accced20
commit 5c08b9e8bd
14 changed files with 309 additions and 151 deletions

View file

@ -5,7 +5,6 @@
package syntax
import (
"cmd/internal/src"
"fmt"
"io"
"strconv"
@ -16,26 +15,24 @@ const debug = false
const trace = false
type parser struct {
file *src.PosBase
errh ErrorHandler
fileh FilenameHandler
mode Mode
file *PosBase
errh ErrorHandler
mode Mode
scanner
base *src.PosBase // current position base
first error // first error encountered
errcnt int // number of errors encountered
pragma Pragma // pragma flags
base *PosBase // current position base
first error // first error encountered
errcnt int // number of errors encountered
pragma Pragma // pragma flags
fnest int // function nesting level (for error handling)
xnest int // expression nesting level (for complit ambiguity resolution)
indent []byte // tracing support
}
func (p *parser) init(file *src.PosBase, r io.Reader, errh ErrorHandler, pragh PragmaHandler, fileh FilenameHandler, mode Mode) {
func (p *parser) init(file *PosBase, r io.Reader, errh ErrorHandler, pragh PragmaHandler, mode Mode) {
p.file = file
p.errh = errh
p.fileh = fileh
p.mode = mode
p.scanner.init(
r,
@ -52,15 +49,25 @@ func (p *parser) init(file *src.PosBase, r io.Reader, errh ErrorHandler, pragh P
// otherwise it must be a comment containing a line or go: directive
text := commentText(msg)
col += 2 // text starts after // or /*
if strings.HasPrefix(text, "line ") {
p.updateBase(line, col+5, text[5:])
var pos Pos // position immediately following the comment
if msg[1] == '/' {
// line comment
pos = MakePos(p.file, line+1, colbase)
} else {
// regular comment
// (if the comment spans multiple lines it's not
// a valid line directive and will be discarded
// by updateBase)
pos = MakePos(p.file, line, col+uint(len(msg)))
}
p.updateBase(pos, line, col+2+5, text[5:]) // +2 to skip over // or /*
return
}
// go: directive (but be conservative and test)
if pragh != nil && strings.HasPrefix(text, "go:") {
p.pragma |= pragh(p.posAt(line, col), text)
p.pragma |= pragh(p.posAt(line, col+2), text) // +2 to skip over // or /*
}
},
directives,
@ -76,9 +83,7 @@ func (p *parser) init(file *src.PosBase, r io.Reader, errh ErrorHandler, pragh P
p.indent = nil
}
const lineMax = 1<<24 - 1 // TODO(gri) this limit is defined for src.Pos - fix
func (p *parser) updateBase(line, col uint, text string) {
func (p *parser) updateBase(pos Pos, line, col uint, text string) {
i, n, ok := trailingDigits(text)
if i == 0 {
return // ignore (not a line directive)
@ -96,26 +101,25 @@ func (p *parser) updateBase(line, col uint, text string) {
//line filename:line:col
i, i2 = i2, i
n, n2 = n2, n
if n2 == 0 {
if n2 == 0 || n2 > PosMax {
p.errorAt(p.posAt(line, col+i2), "invalid column number: "+text[i2:])
return
}
text = text[:i2-1] // lop off :col
} else {
//line filename:line
n2 = colbase // use start of line for column
}
if n == 0 || n > lineMax {
if n == 0 || n > PosMax {
p.errorAt(p.posAt(line, col+i), "invalid line number: "+text[i:])
return
}
filename := text[:i-1] // lop off :line
absFilename := filename
if p.fileh != nil {
absFilename = p.fileh(filename)
}
// TODO(gri) handle case where filename doesn't change (see #22662)
// TODO(gri) pass column n2 to NewLinePragmaBase
p.base = src.NewLinePragmaBase(src.MakePos(p.file, line, col), filename, absFilename, uint(n) /*uint(n2)*/)
p.base = NewLineBase(pos, filename, n, n2)
}
func commentText(s string) string {
@ -162,12 +166,12 @@ func (p *parser) want(tok token) {
// Error handling
// posAt returns the Pos value for (line, col) and the current position base.
func (p *parser) posAt(line, col uint) src.Pos {
return src.MakePos(p.base, line, col)
func (p *parser) posAt(line, col uint) Pos {
return MakePos(p.base, line, col)
}
// error reports an error at the given position.
func (p *parser) errorAt(pos src.Pos, msg string) {
func (p *parser) errorAt(pos Pos, msg string) {
err := Error{pos, msg}
if p.first == nil {
p.first = err
@ -180,7 +184,7 @@ func (p *parser) errorAt(pos src.Pos, msg string) {
}
// syntaxErrorAt reports a syntax error at the given position.
func (p *parser) syntaxErrorAt(pos src.Pos, msg string) {
func (p *parser) syntaxErrorAt(pos Pos, msg string) {
if trace {
p.print("syntax error: " + msg)
}
@ -237,7 +241,7 @@ func tokstring(tok token) string {
}
// Convenience methods using the current token position.
func (p *parser) pos() src.Pos { return p.posAt(p.line, p.col) }
func (p *parser) pos() Pos { return p.posAt(p.line, p.col) }
func (p *parser) syntaxError(msg string) { p.syntaxErrorAt(p.pos(), msg) }
// The stopset contains keywords that start a statement.
@ -417,7 +421,7 @@ func isEmptyFuncDecl(dcl Decl) bool {
// list = "(" { f sep } ")" |
// "{" { f sep } "}" . // sep is optional before ")" or "}"
//
func (p *parser) list(open, sep, close token, f func() bool) src.Pos {
func (p *parser) list(open, sep, close token, f func() bool) Pos {
p.want(open)
var done bool
@ -1064,7 +1068,7 @@ func (p *parser) type_() Expr {
return typ
}
func newIndirect(pos src.Pos, typ Expr) Expr {
func newIndirect(pos Pos, typ Expr) Expr {
o := new(Operation)
o.pos = pos
o.Op = Mul
@ -1276,7 +1280,7 @@ func (p *parser) funcResult() []*Field {
return nil
}
func (p *parser) addField(styp *StructType, pos src.Pos, name *Name, typ Expr, tag *BasicLit) {
func (p *parser) addField(styp *StructType, pos Pos, name *Name, typ Expr, tag *BasicLit) {
if tag != nil {
for i := len(styp.FieldList) - len(styp.TagList); i > 0; i-- {
styp.TagList = append(styp.TagList, nil)
@ -1694,7 +1698,7 @@ func (p *parser) newRangeClause(lhs Expr, def bool) *RangeClause {
return r
}
func (p *parser) newAssignStmt(pos src.Pos, op Operator, lhs, rhs Expr) *AssignStmt {
func (p *parser) newAssignStmt(pos Pos, op Operator, lhs, rhs Expr) *AssignStmt {
a := new(AssignStmt)
a.pos = pos
a.Op = op
@ -1818,7 +1822,7 @@ func (p *parser) header(keyword token) (init SimpleStmt, cond Expr, post SimpleS
var condStmt SimpleStmt
var semi struct {
pos src.Pos
pos Pos
lit string // valid if pos.IsKnown()
}
if p.tok != _Lbrace {