mirror of
https://github.com/golang/go.git
synced 2025-05-05 23:53:05 +00:00
go.tools/ssa: new Function.Syntax() returns the declaring AST (debug mode) or just the Pos/End of the function's extent (otherwise).
R=gri CC=golang-dev https://golang.org/cl/16980043
This commit is contained in:
parent
3eb9e504e3
commit
aa2386290b
@ -514,10 +514,7 @@ func (b *builder) expr0(fn *Function, e ast.Expr) Value {
|
||||
Enclosing: fn,
|
||||
Pkg: fn.Pkg,
|
||||
Prog: fn.Prog,
|
||||
syntax: &funcSyntax{
|
||||
functype: e.Type,
|
||||
body: e.Body,
|
||||
},
|
||||
syntax: e,
|
||||
}
|
||||
fn.AnonFuncs = append(fn.AnonFuncs, fn2)
|
||||
b.buildFunction(fn2)
|
||||
@ -2214,10 +2211,25 @@ func (b *builder) buildFunction(fn *Function) {
|
||||
if fn.Blocks != nil {
|
||||
return // building already started
|
||||
}
|
||||
if fn.syntax == nil {
|
||||
|
||||
var recvField *ast.FieldList
|
||||
var body *ast.BlockStmt
|
||||
var functype *ast.FuncType
|
||||
switch n := fn.syntax.(type) {
|
||||
case nil:
|
||||
return // not a Go source function. (Synthetic, or from object file.)
|
||||
case *ast.FuncDecl:
|
||||
functype = n.Type
|
||||
recvField = n.Recv
|
||||
body = n.Body
|
||||
case *ast.FuncLit:
|
||||
functype = n.Type
|
||||
body = n.Body
|
||||
default:
|
||||
panic(n)
|
||||
}
|
||||
if fn.syntax.body == nil {
|
||||
|
||||
if body == nil {
|
||||
// External function.
|
||||
if fn.Params == nil {
|
||||
// This condition ensures we add a non-empty
|
||||
@ -2241,8 +2253,8 @@ func (b *builder) buildFunction(fn *Function) {
|
||||
defer logStack("build function %s @ %s", fn, fn.Prog.Fset.Position(fn.pos))()
|
||||
}
|
||||
fn.startBody()
|
||||
fn.createSyntacticParams()
|
||||
b.stmt(fn, fn.syntax.body)
|
||||
fn.createSyntacticParams(recvField, functype)
|
||||
b.stmt(fn, body)
|
||||
if cb := fn.currentBlock; cb != nil && (cb == fn.Blocks[0] || cb == fn.Recover || cb.Preds != nil) {
|
||||
// Run function calls deferred in this function when
|
||||
// falling off the end of the body block.
|
||||
@ -2269,11 +2281,7 @@ func (b *builder) buildFuncDecl(pkg *Package, decl *ast.FuncDecl) {
|
||||
pos: decl.Name.NamePos,
|
||||
Pkg: pkg,
|
||||
Prog: pkg.Prog,
|
||||
syntax: &funcSyntax{
|
||||
functype: decl.Type,
|
||||
recvField: decl.Recv,
|
||||
body: decl.Body,
|
||||
},
|
||||
syntax: decl,
|
||||
}
|
||||
|
||||
var v Call
|
||||
|
@ -95,26 +95,19 @@ func memberFromObject(pkg *Package, obj types.Object, syntax ast.Node) {
|
||||
pkg.Members[name] = g
|
||||
|
||||
case *types.Func:
|
||||
var fs *funcSyntax
|
||||
synthetic := "loaded from gc object file"
|
||||
if decl, ok := syntax.(*ast.FuncDecl); ok {
|
||||
synthetic = ""
|
||||
fs = &funcSyntax{
|
||||
functype: decl.Type,
|
||||
recvField: decl.Recv,
|
||||
body: decl.Body,
|
||||
}
|
||||
}
|
||||
fn := &Function{
|
||||
name: name,
|
||||
object: obj,
|
||||
Signature: obj.Type().(*types.Signature),
|
||||
Synthetic: synthetic,
|
||||
syntax: syntax,
|
||||
pos: obj.Pos(), // (iff syntax)
|
||||
Pkg: pkg,
|
||||
Prog: pkg.Prog,
|
||||
syntax: fs,
|
||||
}
|
||||
if syntax == nil {
|
||||
fn.Synthetic = "loaded from gc object file"
|
||||
}
|
||||
|
||||
pkg.values[obj] = fn
|
||||
if fn.Signature.Recv() == nil {
|
||||
pkg.Members[name] = fn // package-level function
|
||||
|
48
ssa/func.go
48
ssa/func.go
@ -147,13 +147,6 @@ type lblock struct {
|
||||
_continue *BasicBlock
|
||||
}
|
||||
|
||||
// funcSyntax holds the syntax tree for the function declaration and body.
|
||||
type funcSyntax struct {
|
||||
recvField *ast.FieldList
|
||||
body *ast.BlockStmt
|
||||
functype *ast.FuncType
|
||||
}
|
||||
|
||||
// labelledBlock returns the branch target associated with the
|
||||
// specified label, creating it if needed.
|
||||
//
|
||||
@ -221,15 +214,14 @@ func (f *Function) startBody() {
|
||||
// syntax. In addition it populates the f.objects mapping.
|
||||
//
|
||||
// Preconditions:
|
||||
// f.syntax != nil, i.e. this is a Go source function.
|
||||
// f.startBody() was called.
|
||||
// Postcondition:
|
||||
// len(f.Params) == len(f.Signature.Params) + (f.Signature.Recv() ? 1 : 0)
|
||||
//
|
||||
func (f *Function) createSyntacticParams() {
|
||||
func (f *Function) createSyntacticParams(recv *ast.FieldList, functype *ast.FuncType) {
|
||||
// Receiver (at most one inner iteration).
|
||||
if f.syntax.recvField != nil {
|
||||
for _, field := range f.syntax.recvField.List {
|
||||
if recv != nil {
|
||||
for _, field := range recv.List {
|
||||
for _, n := range field.Names {
|
||||
f.addSpilledParam(f.Pkg.objectOf(n))
|
||||
}
|
||||
@ -241,9 +233,9 @@ func (f *Function) createSyntacticParams() {
|
||||
}
|
||||
|
||||
// Parameters.
|
||||
if f.syntax.functype.Params != nil {
|
||||
if functype.Params != nil {
|
||||
n := len(f.Params) // 1 if has recv, 0 otherwise
|
||||
for _, field := range f.syntax.functype.Params.List {
|
||||
for _, field := range functype.Params.List {
|
||||
for _, n := range field.Names {
|
||||
f.addSpilledParam(f.Pkg.objectOf(n))
|
||||
}
|
||||
@ -255,8 +247,8 @@ func (f *Function) createSyntacticParams() {
|
||||
}
|
||||
|
||||
// Named results.
|
||||
if f.syntax.functype.Results != nil {
|
||||
for _, field := range f.syntax.functype.Results.List {
|
||||
if functype.Results != nil {
|
||||
for _, field := range functype.Results.List {
|
||||
// Implicit "var" decl of locals for named results.
|
||||
for _, n := range field.Names {
|
||||
f.namedResults = append(f.namedResults, f.addLocalForIdent(n))
|
||||
@ -308,7 +300,11 @@ func (f *Function) finishBody() {
|
||||
f.objects = nil
|
||||
f.currentBlock = nil
|
||||
f.lblocks = nil
|
||||
f.syntax = nil
|
||||
|
||||
// Don't pin the AST in memory (except in debug mode).
|
||||
if n := f.syntax; n != nil && !f.debugInfo() {
|
||||
f.syntax = extentNode{n.Pos(), n.End()}
|
||||
}
|
||||
|
||||
// Remove any f.Locals that are now heap-allocated.
|
||||
j := 0
|
||||
@ -380,15 +376,13 @@ func (pkg *Package) SetDebugMode(debug bool) {
|
||||
|
||||
// debugInfo reports whether debug info is wanted for this function.
|
||||
func (f *Function) debugInfo() bool {
|
||||
return f.Pkg.debug
|
||||
return f.Pkg != nil && f.Pkg.debug
|
||||
}
|
||||
|
||||
// addNamedLocal creates a local variable, adds it to function f and
|
||||
// returns it. Its name and type are taken from obj. Subsequent
|
||||
// calls to f.lookup(obj) will return the same local.
|
||||
//
|
||||
// Precondition: f.syntax != nil (i.e. a Go source function).
|
||||
//
|
||||
func (f *Function) addNamedLocal(obj types.Object) *Alloc {
|
||||
l := f.addLocal(obj.Type(), obj.Pos())
|
||||
l.Comment = obj.Name()
|
||||
@ -660,3 +654,19 @@ func (f *Function) newBasicBlock(comment string) *BasicBlock {
|
||||
func NewFunction(name string, sig *types.Signature, provenance string) *Function {
|
||||
return &Function{name: name, Signature: sig, Synthetic: provenance}
|
||||
}
|
||||
|
||||
type extentNode [2]token.Pos
|
||||
|
||||
func (n extentNode) Pos() token.Pos { return n[0] }
|
||||
func (n extentNode) End() token.Pos { return n[1] }
|
||||
|
||||
// Syntax returns an ast.Node whose Pos/End methods provide the
|
||||
// lexical extent of the function if it was defined by Go source code
|
||||
// (f.Synthetic==""), or nil otherwise.
|
||||
//
|
||||
// If f was built with debug information (see Package.SetDebugRef),
|
||||
// the result is the *ast.FuncDecl or *ast.FuncLit that declared the
|
||||
// function. Otherwise, it is an opaque Node providing only position
|
||||
// information; this avoids pinning the AST in memory.
|
||||
//
|
||||
func (f *Function) Syntax() ast.Node { return f.syntax }
|
||||
|
@ -339,6 +339,9 @@ func (s *sanity) checkFunction(fn *Function) bool {
|
||||
s.errorf("nil Pkg")
|
||||
}
|
||||
}
|
||||
if src, syn := fn.Synthetic == "", fn.Syntax() != nil; src != syn {
|
||||
s.errorf("got fromSource=%t, hasSyntax=%t; want same values", src, syn)
|
||||
}
|
||||
for i, l := range fn.Locals {
|
||||
if l.Parent() != fn {
|
||||
s.errorf("Local %s at index %d has wrong parent", l.Name(), i)
|
||||
|
@ -26,8 +26,8 @@ import (
|
||||
// Returns nil if not found; reasons might include:
|
||||
// - the node is not enclosed by any function.
|
||||
// - the node is within an anonymous function (FuncLit) and
|
||||
// its SSA function has not been created yet (pkg.BuildPackage()
|
||||
// has not yet been called).
|
||||
// its SSA function has not been created yet
|
||||
// (pkg.Build() has not yet been called).
|
||||
//
|
||||
func EnclosingFunction(pkg *Package, path []ast.Node) *Function {
|
||||
// Start with package-level function...
|
||||
|
@ -268,6 +268,7 @@ type Function struct {
|
||||
pos token.Pos
|
||||
|
||||
Synthetic string // provenance of synthetic function; "" for true source functions
|
||||
syntax ast.Node // *ast.Func{Decl,Lit}; replaced with simple ast.Node after build, unless debug mode
|
||||
Enclosing *Function // enclosing function if anon; nil if global
|
||||
Pkg *Package // enclosing package; nil for shared funcs (wrappers and error.Error)
|
||||
Prog *Program // enclosing program
|
||||
@ -283,7 +284,6 @@ type Function struct {
|
||||
currentBlock *BasicBlock // where to emit code
|
||||
objects map[types.Object]Value // addresses of local variables
|
||||
namedResults []*Alloc // tuple of named results
|
||||
syntax *funcSyntax // abstract syntax trees for Go source functions
|
||||
targets *targets // linked stack of branch targets
|
||||
lblocks map[*ast.Object]*lblock // labelled blocks
|
||||
}
|
||||
@ -1168,6 +1168,9 @@ type MapUpdate struct {
|
||||
// consistency is maintained during transformation passes by the
|
||||
// ordinary SSA renaming machinery.)
|
||||
//
|
||||
// DebugRefs are generated only for functions built with debugging
|
||||
// enabled; see Package.SetDebugMode().
|
||||
//
|
||||
type DebugRef struct {
|
||||
anInstruction
|
||||
X Value // the value whose position we're declaring
|
||||
|
Loading…
x
Reference in New Issue
Block a user