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,
|
Enclosing: fn,
|
||||||
Pkg: fn.Pkg,
|
Pkg: fn.Pkg,
|
||||||
Prog: fn.Prog,
|
Prog: fn.Prog,
|
||||||
syntax: &funcSyntax{
|
syntax: e,
|
||||||
functype: e.Type,
|
|
||||||
body: e.Body,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
fn.AnonFuncs = append(fn.AnonFuncs, fn2)
|
fn.AnonFuncs = append(fn.AnonFuncs, fn2)
|
||||||
b.buildFunction(fn2)
|
b.buildFunction(fn2)
|
||||||
@ -2214,10 +2211,25 @@ func (b *builder) buildFunction(fn *Function) {
|
|||||||
if fn.Blocks != nil {
|
if fn.Blocks != nil {
|
||||||
return // building already started
|
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.)
|
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.
|
// External function.
|
||||||
if fn.Params == nil {
|
if fn.Params == nil {
|
||||||
// This condition ensures we add a non-empty
|
// 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))()
|
defer logStack("build function %s @ %s", fn, fn.Prog.Fset.Position(fn.pos))()
|
||||||
}
|
}
|
||||||
fn.startBody()
|
fn.startBody()
|
||||||
fn.createSyntacticParams()
|
fn.createSyntacticParams(recvField, functype)
|
||||||
b.stmt(fn, fn.syntax.body)
|
b.stmt(fn, body)
|
||||||
if cb := fn.currentBlock; cb != nil && (cb == fn.Blocks[0] || cb == fn.Recover || cb.Preds != nil) {
|
if cb := fn.currentBlock; cb != nil && (cb == fn.Blocks[0] || cb == fn.Recover || cb.Preds != nil) {
|
||||||
// Run function calls deferred in this function when
|
// Run function calls deferred in this function when
|
||||||
// falling off the end of the body block.
|
// 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,
|
pos: decl.Name.NamePos,
|
||||||
Pkg: pkg,
|
Pkg: pkg,
|
||||||
Prog: pkg.Prog,
|
Prog: pkg.Prog,
|
||||||
syntax: &funcSyntax{
|
syntax: decl,
|
||||||
functype: decl.Type,
|
|
||||||
recvField: decl.Recv,
|
|
||||||
body: decl.Body,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var v Call
|
var v Call
|
||||||
|
@ -95,26 +95,19 @@ func memberFromObject(pkg *Package, obj types.Object, syntax ast.Node) {
|
|||||||
pkg.Members[name] = g
|
pkg.Members[name] = g
|
||||||
|
|
||||||
case *types.Func:
|
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{
|
fn := &Function{
|
||||||
name: name,
|
name: name,
|
||||||
object: obj,
|
object: obj,
|
||||||
Signature: obj.Type().(*types.Signature),
|
Signature: obj.Type().(*types.Signature),
|
||||||
Synthetic: synthetic,
|
syntax: syntax,
|
||||||
pos: obj.Pos(), // (iff syntax)
|
pos: obj.Pos(), // (iff syntax)
|
||||||
Pkg: pkg,
|
Pkg: pkg,
|
||||||
Prog: pkg.Prog,
|
Prog: pkg.Prog,
|
||||||
syntax: fs,
|
|
||||||
}
|
}
|
||||||
|
if syntax == nil {
|
||||||
|
fn.Synthetic = "loaded from gc object file"
|
||||||
|
}
|
||||||
|
|
||||||
pkg.values[obj] = fn
|
pkg.values[obj] = fn
|
||||||
if fn.Signature.Recv() == nil {
|
if fn.Signature.Recv() == nil {
|
||||||
pkg.Members[name] = fn // package-level function
|
pkg.Members[name] = fn // package-level function
|
||||||
|
48
ssa/func.go
48
ssa/func.go
@ -147,13 +147,6 @@ type lblock struct {
|
|||||||
_continue *BasicBlock
|
_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
|
// labelledBlock returns the branch target associated with the
|
||||||
// specified label, creating it if needed.
|
// specified label, creating it if needed.
|
||||||
//
|
//
|
||||||
@ -221,15 +214,14 @@ func (f *Function) startBody() {
|
|||||||
// syntax. In addition it populates the f.objects mapping.
|
// syntax. In addition it populates the f.objects mapping.
|
||||||
//
|
//
|
||||||
// Preconditions:
|
// Preconditions:
|
||||||
// f.syntax != nil, i.e. this is a Go source function.
|
|
||||||
// f.startBody() was called.
|
// f.startBody() was called.
|
||||||
// Postcondition:
|
// Postcondition:
|
||||||
// len(f.Params) == len(f.Signature.Params) + (f.Signature.Recv() ? 1 : 0)
|
// 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).
|
// Receiver (at most one inner iteration).
|
||||||
if f.syntax.recvField != nil {
|
if recv != nil {
|
||||||
for _, field := range f.syntax.recvField.List {
|
for _, field := range recv.List {
|
||||||
for _, n := range field.Names {
|
for _, n := range field.Names {
|
||||||
f.addSpilledParam(f.Pkg.objectOf(n))
|
f.addSpilledParam(f.Pkg.objectOf(n))
|
||||||
}
|
}
|
||||||
@ -241,9 +233,9 @@ func (f *Function) createSyntacticParams() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Parameters.
|
// Parameters.
|
||||||
if f.syntax.functype.Params != nil {
|
if functype.Params != nil {
|
||||||
n := len(f.Params) // 1 if has recv, 0 otherwise
|
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 {
|
for _, n := range field.Names {
|
||||||
f.addSpilledParam(f.Pkg.objectOf(n))
|
f.addSpilledParam(f.Pkg.objectOf(n))
|
||||||
}
|
}
|
||||||
@ -255,8 +247,8 @@ func (f *Function) createSyntacticParams() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Named results.
|
// Named results.
|
||||||
if f.syntax.functype.Results != nil {
|
if functype.Results != nil {
|
||||||
for _, field := range f.syntax.functype.Results.List {
|
for _, field := range functype.Results.List {
|
||||||
// Implicit "var" decl of locals for named results.
|
// Implicit "var" decl of locals for named results.
|
||||||
for _, n := range field.Names {
|
for _, n := range field.Names {
|
||||||
f.namedResults = append(f.namedResults, f.addLocalForIdent(n))
|
f.namedResults = append(f.namedResults, f.addLocalForIdent(n))
|
||||||
@ -308,7 +300,11 @@ func (f *Function) finishBody() {
|
|||||||
f.objects = nil
|
f.objects = nil
|
||||||
f.currentBlock = nil
|
f.currentBlock = nil
|
||||||
f.lblocks = 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.
|
// Remove any f.Locals that are now heap-allocated.
|
||||||
j := 0
|
j := 0
|
||||||
@ -380,15 +376,13 @@ func (pkg *Package) SetDebugMode(debug bool) {
|
|||||||
|
|
||||||
// debugInfo reports whether debug info is wanted for this function.
|
// debugInfo reports whether debug info is wanted for this function.
|
||||||
func (f *Function) debugInfo() bool {
|
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
|
// addNamedLocal creates a local variable, adds it to function f and
|
||||||
// returns it. Its name and type are taken from obj. Subsequent
|
// returns it. Its name and type are taken from obj. Subsequent
|
||||||
// calls to f.lookup(obj) will return the same local.
|
// 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 {
|
func (f *Function) addNamedLocal(obj types.Object) *Alloc {
|
||||||
l := f.addLocal(obj.Type(), obj.Pos())
|
l := f.addLocal(obj.Type(), obj.Pos())
|
||||||
l.Comment = obj.Name()
|
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 {
|
func NewFunction(name string, sig *types.Signature, provenance string) *Function {
|
||||||
return &Function{name: name, Signature: sig, Synthetic: provenance}
|
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")
|
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 {
|
for i, l := range fn.Locals {
|
||||||
if l.Parent() != fn {
|
if l.Parent() != fn {
|
||||||
s.errorf("Local %s at index %d has wrong parent", l.Name(), i)
|
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:
|
// Returns nil if not found; reasons might include:
|
||||||
// - the node is not enclosed by any function.
|
// - the node is not enclosed by any function.
|
||||||
// - the node is within an anonymous function (FuncLit) and
|
// - the node is within an anonymous function (FuncLit) and
|
||||||
// its SSA function has not been created yet (pkg.BuildPackage()
|
// its SSA function has not been created yet
|
||||||
// has not yet been called).
|
// (pkg.Build() has not yet been called).
|
||||||
//
|
//
|
||||||
func EnclosingFunction(pkg *Package, path []ast.Node) *Function {
|
func EnclosingFunction(pkg *Package, path []ast.Node) *Function {
|
||||||
// Start with package-level function...
|
// Start with package-level function...
|
||||||
|
@ -268,6 +268,7 @@ type Function struct {
|
|||||||
pos token.Pos
|
pos token.Pos
|
||||||
|
|
||||||
Synthetic string // provenance of synthetic function; "" for true source functions
|
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
|
Enclosing *Function // enclosing function if anon; nil if global
|
||||||
Pkg *Package // enclosing package; nil for shared funcs (wrappers and error.Error)
|
Pkg *Package // enclosing package; nil for shared funcs (wrappers and error.Error)
|
||||||
Prog *Program // enclosing program
|
Prog *Program // enclosing program
|
||||||
@ -283,7 +284,6 @@ type Function struct {
|
|||||||
currentBlock *BasicBlock // where to emit code
|
currentBlock *BasicBlock // where to emit code
|
||||||
objects map[types.Object]Value // addresses of local variables
|
objects map[types.Object]Value // addresses of local variables
|
||||||
namedResults []*Alloc // tuple of named results
|
namedResults []*Alloc // tuple of named results
|
||||||
syntax *funcSyntax // abstract syntax trees for Go source functions
|
|
||||||
targets *targets // linked stack of branch targets
|
targets *targets // linked stack of branch targets
|
||||||
lblocks map[*ast.Object]*lblock // labelled blocks
|
lblocks map[*ast.Object]*lblock // labelled blocks
|
||||||
}
|
}
|
||||||
@ -1168,6 +1168,9 @@ type MapUpdate struct {
|
|||||||
// consistency is maintained during transformation passes by the
|
// consistency is maintained during transformation passes by the
|
||||||
// ordinary SSA renaming machinery.)
|
// ordinary SSA renaming machinery.)
|
||||||
//
|
//
|
||||||
|
// DebugRefs are generated only for functions built with debugging
|
||||||
|
// enabled; see Package.SetDebugMode().
|
||||||
|
//
|
||||||
type DebugRef struct {
|
type DebugRef struct {
|
||||||
anInstruction
|
anInstruction
|
||||||
X Value // the value whose position we're declaring
|
X Value // the value whose position we're declaring
|
||||||
|
Loading…
x
Reference in New Issue
Block a user