1
0
mirror of https://github.com/golang/go synced 2024-11-19 13:24:42 -07:00

[dev.inline] cmd/compile: parse source files concurrently

Conversion to Nodes still happens sequentially at the moment.

Change-Id: I3407ba0711b8b92e22ece0a06fefaff863c3ccc9
Reviewed-on: https://go-review.googlesource.com/35126
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
Reviewed-by: Robert Griesemer <gri@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
Matthew Dempsky 2017-01-11 15:48:30 -08:00
parent b90aed020d
commit ec63158d71
3 changed files with 87 additions and 71 deletions

View File

@ -40,11 +40,9 @@ func plan9quote(s string) string {
return s return s
} }
type Pragma syntax.Pragma
const ( const (
// Func pragmas. // Func pragmas.
Nointerface Pragma = 1 << iota Nointerface syntax.Pragma = 1 << iota
Noescape // func parameters don't escape Noescape // func parameters don't escape
Norace // func must not have race detector annotations Norace // func must not have race detector annotations
Nosplit // func should not execute on separate stack Nosplit // func should not execute on separate stack
@ -63,7 +61,7 @@ const (
NotInHeap // values of this type must not be heap allocated NotInHeap // values of this type must not be heap allocated
) )
func pragmaValue(verb string) Pragma { func pragmaValue(verb string) syntax.Pragma {
switch verb { switch verb {
case "go:nointerface": case "go:nointerface":
if obj.Fieldtrack_enabled != 0 { if obj.Fieldtrack_enabled != 0 {
@ -78,24 +76,12 @@ func pragmaValue(verb string) Pragma {
case "go:noinline": case "go:noinline":
return Noinline return Noinline
case "go:systemstack": case "go:systemstack":
if !compiling_runtime {
yyerror("//go:systemstack only allowed in runtime")
}
return Systemstack return Systemstack
case "go:nowritebarrier": case "go:nowritebarrier":
if !compiling_runtime {
yyerror("//go:nowritebarrier only allowed in runtime")
}
return Nowritebarrier return Nowritebarrier
case "go:nowritebarrierrec": case "go:nowritebarrierrec":
if !compiling_runtime {
yyerror("//go:nowritebarrierrec only allowed in runtime")
}
return Nowritebarrierrec | Nowritebarrier // implies Nowritebarrier return Nowritebarrierrec | Nowritebarrier // implies Nowritebarrier
case "go:yeswritebarrierrec": case "go:yeswritebarrierrec":
if !compiling_runtime {
yyerror("//go:yeswritebarrierrec only allowed in runtime")
}
return Yeswritebarrierrec return Yeswritebarrierrec
case "go:cgo_unsafe_args": case "go:cgo_unsafe_args":
return CgoUnsafeArgs return CgoUnsafeArgs

View File

@ -18,34 +18,47 @@ import (
func parseFiles(filenames []string) uint { func parseFiles(filenames []string) uint {
var lines uint var lines uint
for _, filename := range filenames { var noders []*noder
lines += parseFile(filename)
if nsyntaxerrors != 0 { for _, filename := range filenames {
errorexit() p := &noder{err: make(chan syntax.Error)}
} noders = append(noders, p)
}
return lines go func(filename string) {
} defer close(p.err)
base := src.NewFileBase(filename, absFilename(filename))
func parseFile(filename string) uint {
f, err := os.Open(filename) f, err := os.Open(filename)
if err != nil { if err != nil {
fmt.Println(err) p.error(syntax.Error{Pos: src.MakePos(base, 0, 0), Msg: err.Error()})
errorexit() return
} }
defer f.Close() defer f.Close()
base := src.NewFileBase(filename, absFilename(filename)) p.file, _ = syntax.Parse(base, f, p.error, p.pragma, 0) // errors are tracked via p.error
var p noder }(filename)
file, _ := syntax.Parse(base, f, p.error, p.pragma, 0) // errors are tracked via p.error }
p.file(file) for _, p := range noders {
for e := range p.err {
yyerrorpos(e.Pos, "%s", e.Msg)
}
if nsyntaxerrors == 0 { p.node()
lines += p.file.Lines
p.file = nil // release memory
if nsyntaxerrors != 0 {
errorexit()
}
testdclstack() testdclstack()
} }
return file.Lines return lines
}
func yyerrorpos(pos src.Pos, format string, args ...interface{}) {
yyerrorl(Ctxt.PosTable.XPos(pos), format, args...)
} }
var pathPrefix string var pathPrefix string
@ -54,27 +67,41 @@ func absFilename(name string) string {
return obj.AbsFile(Ctxt.Pathname, name, pathPrefix) return obj.AbsFile(Ctxt.Pathname, name, pathPrefix)
} }
// noder transforms package syntax's AST into a Nod tree. // noder transforms package syntax's AST into a Node tree.
type noder struct { type noder struct {
linknames []src.Pos // tracks //go:linkname positions file *syntax.File
linknames []linkname
pragcgobuf string
err chan syntax.Error
} }
func (p *noder) file(file *syntax.File) { // linkname records a //go:linkname directive.
type linkname struct {
pos src.Pos
local string
remote string
}
func (p *noder) node() {
block = 1 block = 1
iota_ = -1000000 iota_ = -1000000
imported_unsafe = false imported_unsafe = false
p.lineno(file.PkgName) p.lineno(p.file.PkgName)
mkpackage(file.PkgName.Value) mkpackage(p.file.PkgName.Value)
xtop = append(xtop, p.decls(file.DeclList)...) xtop = append(xtop, p.decls(p.file.DeclList)...)
if !imported_unsafe { for _, n := range p.linknames {
for _, pos := range p.linknames { if imported_unsafe {
p.error(syntax.Error{Pos: pos, Msg: "//go:linkname only allowed in Go files that import \"unsafe\""}) lookup(n.local).Linkname = n.remote
} else {
yyerrorpos(n.pos, "//go:linkname only allowed in Go files that import \"unsafe\"")
} }
} }
pragcgobuf += p.pragcgobuf
// For compatibility with old code only (comparisons w/ toolstash): // For compatibility with old code only (comparisons w/ toolstash):
// The old line number tracking simply continued incrementing the // The old line number tracking simply continued incrementing the
// virtual line number (lexlineno) and using it also for lineno. // virtual line number (lexlineno) and using it also for lineno.
@ -84,7 +111,7 @@ func (p *noder) file(file *syntax.File) {
// for fninit and set lineno to NoPos here. // for fninit and set lineno to NoPos here.
// TODO(gri) fix this once we switched permanently to the new // TODO(gri) fix this once we switched permanently to the new
// position information. // position information.
lineno = MakePos(file.Pos().Base(), uint(file.Lines), 0) lineno = MakePos(p.file.Pos().Base(), uint(p.file.Lines), 0)
clearImports() clearImports()
} }
@ -221,7 +248,7 @@ func (p *noder) constDecl(decl *syntax.ConstDecl) []*Node {
func (p *noder) typeDecl(decl *syntax.TypeDecl) *Node { func (p *noder) typeDecl(decl *syntax.TypeDecl) *Node {
name := typedcl0(p.name(decl.Name)) name := typedcl0(p.name(decl.Name))
name.Name.Param.Pragma = Pragma(decl.Pragma) name.Name.Param.Pragma = decl.Pragma
var typ *Node var typ *Node
if decl.Type != nil { if decl.Type != nil {
@ -258,7 +285,7 @@ func (p *noder) funcDecl(fun *syntax.FuncDecl) *Node {
} }
} }
pragma := Pragma(fun.Pragma) pragma := fun.Pragma
f.Nbody.Set(body) f.Nbody.Set(body)
f.Noescape = pragma&Noescape != 0 f.Noescape = pragma&Noescape != 0
@ -1043,8 +1070,7 @@ func (p *noder) lineno(n syntax.Node) {
} }
func (p *noder) error(err error) { func (p *noder) error(err error) {
e := err.(syntax.Error) p.err <- err.(syntax.Error)
yyerrorl(Ctxt.PosTable.XPos(e.Pos), "%s", e.Msg)
} }
func (p *noder) pragma(pos src.Pos, text string) syntax.Pragma { func (p *noder) pragma(pos src.Pos, text string) syntax.Pragma {
@ -1054,26 +1080,27 @@ func (p *noder) pragma(pos src.Pos, text string) syntax.Pragma {
panic("unreachable") panic("unreachable")
case strings.HasPrefix(text, "go:linkname "): case strings.HasPrefix(text, "go:linkname "):
// Record line number so we can emit an error later if
// the file doesn't import package unsafe.
p.linknames = append(p.linknames, pos)
f := strings.Fields(text) f := strings.Fields(text)
if len(f) != 3 { if len(f) != 3 {
p.error(syntax.Error{Pos: pos, Msg: "usage: //go:linkname localname linkname"}) p.error(syntax.Error{Pos: pos, Msg: "usage: //go:linkname localname linkname"})
break break
} }
lookup(f[1]).Linkname = f[2] p.linknames = append(p.linknames, linkname{pos, f[1], f[2]})
case strings.HasPrefix(text, "go:cgo_"): case strings.HasPrefix(text, "go:cgo_"):
pragcgobuf += pragcgo(text) p.pragcgobuf += pragcgo(text)
fallthrough // because of //go:cgo_unsafe_args fallthrough // because of //go:cgo_unsafe_args
default: default:
verb := text verb := text
if i := strings.Index(text, " "); i >= 0 { if i := strings.Index(text, " "); i >= 0 {
verb = verb[:i] verb = verb[:i]
} }
return syntax.Pragma(pragmaValue(verb)) prag := pragmaValue(verb)
const runtimePragmas = Systemstack | Nowritebarrier | Nowritebarrierrec | Yeswritebarrierrec
if !compiling_runtime && prag&runtimePragmas != 0 {
p.error(syntax.Error{Pos: pos, Msg: fmt.Sprintf("//go:%s only allowed in runtime", verb)})
}
return prag
} }
return 0 return 0

View File

@ -6,7 +6,10 @@
package gc package gc
import "cmd/internal/src" import (
"cmd/compile/internal/syntax"
"cmd/internal/src"
)
// A Node is a single node in the syntax tree. // A Node is a single node in the syntax tree.
// Actually the syntax tree is a syntax DAG, because there is only one // Actually the syntax tree is a syntax DAG, because there is only one
@ -285,7 +288,7 @@ type Param struct {
// OTYPE pragmas // OTYPE pragmas
// //
// TODO: Should Func pragmas also be stored on the Name? // TODO: Should Func pragmas also be stored on the Name?
Pragma Pragma Pragma syntax.Pragma
} }
// Func holds Node fields used only with function-like nodes. // Func holds Node fields used only with function-like nodes.
@ -313,7 +316,7 @@ type Func struct {
Endlineno src.XPos Endlineno src.XPos
WBPos src.XPos // position of first write barrier WBPos src.XPos // position of first write barrier
Pragma Pragma // go:xxx function annotations Pragma syntax.Pragma // go:xxx function annotations
Dupok bool // duplicate definitions ok Dupok bool // duplicate definitions ok
Wrapper bool // is method wrapper Wrapper bool // is method wrapper
Needctxt bool // function uses context register (has closure variables) Needctxt bool // function uses context register (has closure variables)