mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
[dev.regabi] cmd/compile: clean up Node.Func
The original meaning of type Func was "extra fields factored out of a few cases of type Node having to do with functions", but those specific cases didn't necessarily have any relation. A typical declared function is represented by an ODCLFUNC Node at its declaration and an ONAME node at its uses, and both those have a .Func field, but they are *different* Funcs. Similarly, a closure is represented both by an OCLOSURE Node for the value itself and an ODCLFUNC Node for the underlying function implementing the closure. Those too have *different* Funcs, and the Func.Closure field in one points to the other and vice versa. This has led to no end of confusion over the years. This CL elevates type Func to be the canonical identifier for a given Go function. This looks like a trivial CL but in fact is the result of a lot of scaffolding and rewriting, discarded once the result was achieved, to separate out the three different kinds of Func nodes into three separate fields, limited in use to each specific Node type, to understand which Func fields are used by which Node types and what the possible overlaps are. There were a few overlaps, most notably around closures, which led to more fields being added to type Func to keep them separate even though there is now a single Func instead of two different ones for each function. A future CL can and should change Curfn to be a *Func instead of a *Node, finally eliminating the confusion about whether Curfn is an ODCLFUNC node (as it is most of the time) or an ONAME node (as it is when type-checking an inlined function body). Although sizeof_test.go makes it look like Func is growing by two words, there are now half as many Funcs in a running compilation, so the memory footprint has actually been reduced substantially. Change-Id: I598bd96c95728093dc769a835d48f2154a406a61 Reviewed-on: https://go-review.googlesource.com/c/go/+/272253 Trust: Russ Cox <rsc@golang.org> Run-TryBot: Russ Cox <rsc@golang.org> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Matthew Dempsky <mdempsky@google.com>
This commit is contained in:
parent
8e2106327c
commit
fd11a32c92
19 changed files with 211 additions and 182 deletions
|
|
@ -578,62 +578,66 @@ func (p *Param) SetEmbedFiles(list []string) {
|
|||
*(*p.Extra).(*embedFileList) = list
|
||||
}
|
||||
|
||||
// Functions
|
||||
// A Func corresponds to a single function in a Go program
|
||||
// (and vice versa: each function is denoted by exactly one *Func).
|
||||
//
|
||||
// A simple function declaration is represented as an ODCLFUNC node f
|
||||
// and an ONAME node n. They're linked to one another through
|
||||
// f.Func.Nname == n and n.Name.Defn == f. When functions are
|
||||
// referenced by name in an expression, the function's ONAME node is
|
||||
// used directly.
|
||||
// There are multiple nodes that represent a Func in the IR.
|
||||
//
|
||||
// Function names have n.Class() == PFUNC. This distinguishes them
|
||||
// from variables of function type.
|
||||
// The ONAME node (Func.Name) is used for plain references to it.
|
||||
// The ODCLFUNC node (Func.Decl) is used for its declaration code.
|
||||
// The OCLOSURE node (Func.Closure) is used for a reference to a
|
||||
// function literal.
|
||||
//
|
||||
// Confusingly, n.Func and f.Func both exist, but commonly point to
|
||||
// different Funcs. (Exception: an OCALLPART's Func does point to its
|
||||
// ODCLFUNC's Func.)
|
||||
// A Func for an imported function will have only an ONAME node.
|
||||
// A declared function or method has an ONAME and an ODCLFUNC.
|
||||
// A function literal is represented directly by an OCLOSURE, but it also
|
||||
// has an ODCLFUNC (and a matching ONAME) representing the compiled
|
||||
// underlying form of the closure, which accesses the captured variables
|
||||
// using a special data structure passed in a register.
|
||||
//
|
||||
// A method declaration is represented like functions, except n.Sym
|
||||
// A method declaration is represented like functions, except f.Sym
|
||||
// will be the qualified method name (e.g., "T.m") and
|
||||
// f.Func.Shortname is the bare method name (e.g., "m").
|
||||
//
|
||||
// Method expressions are represented as ONAME/PFUNC nodes like
|
||||
// function names, but their Left and Right fields still point to the
|
||||
// type and method, respectively. They can be distinguished from
|
||||
// normal functions with isMethodExpression. Also, unlike function
|
||||
// name nodes, method expression nodes exist for each method
|
||||
// expression. The declaration ONAME can be accessed with
|
||||
// x.Type.Nname(), where x is the method expression ONAME node.
|
||||
// A method expression (T.M) is represented as an ONAME node
|
||||
// like a function name would be, but n.Left and n.Right point to
|
||||
// the type and method, respectively. A method expression can
|
||||
// be distinguished from a normal function ONAME by checking
|
||||
// n.IsMethodExpression. Unlike ordinary ONAME nodes, each
|
||||
// distinct mention of a method expression in the source code
|
||||
// constructs a fresh ONAME node.
|
||||
// TODO(rsc): Method expressions deserve their own opcode
|
||||
// instead of violating invariants of ONAME.
|
||||
//
|
||||
// Method values are represented by ODOTMETH/ODOTINTER when called
|
||||
// immediately, and OCALLPART otherwise. They are like method
|
||||
// expressions, except that for ODOTMETH/ODOTINTER the method name is
|
||||
// stored in Sym instead of Right.
|
||||
//
|
||||
// Closures are represented by OCLOSURE node c. They link back and
|
||||
// forth with the ODCLFUNC via Func.Closure; that is, c.Func.Closure
|
||||
// == f and f.Func.Closure == c.
|
||||
//
|
||||
// Function bodies are stored in f.Nbody, and inline function bodies
|
||||
// are stored in n.Func.Inl. Pragmas are stored in f.Func.Pragma.
|
||||
//
|
||||
// Imported functions skip the ODCLFUNC, so n.Name.Defn is nil. They
|
||||
// also use Dcl instead of Inldcl.
|
||||
|
||||
// Func holds Node fields used only with function-like nodes.
|
||||
// A method value (t.M) is represented by ODOTMETH/ODOTINTER
|
||||
// when it is called directly and by OCALLPART otherwise.
|
||||
// These are like method expressions, except that for ODOTMETH/ODOTINTER,
|
||||
// the method name is stored in Sym instead of Right.
|
||||
// Each OCALLPART ends up being implemented as a new
|
||||
// function, a bit like a closure, with its own ODCLFUNC.
|
||||
// The OCALLPART has uses n.Func to record the linkage to
|
||||
// the generated ODCLFUNC (as n.Func.Decl), but there is no
|
||||
// pointer from the Func back to the OCALLPART.
|
||||
type Func struct {
|
||||
Nname *Node // ONAME node
|
||||
Decl *Node // ODCLFUNC node
|
||||
OClosure *Node // OCLOSURE node
|
||||
|
||||
Shortname *types.Sym
|
||||
|
||||
// Extra entry code for the function. For example, allocate and initialize
|
||||
// memory for escaping parameters. However, just for OCLOSURE, Enter is a
|
||||
// list of ONAME nodes of captured variables
|
||||
// memory for escaping parameters.
|
||||
Enter Nodes
|
||||
Exit Nodes
|
||||
// ONAME nodes for closure params, each should have closurevar set
|
||||
Cvars Nodes
|
||||
// ONAME nodes for all params/locals for this func/closure, does NOT
|
||||
// include closurevars until transformclosure runs.
|
||||
Dcl []*Node
|
||||
|
||||
ClosureEnter Nodes // list of ONAME nodes of captured variables
|
||||
ClosureType *Node // closure representation type
|
||||
ClosureCalled bool // closure is only immediately called
|
||||
ClosureVars Nodes // closure params; each has closurevar set
|
||||
|
||||
// Parents records the parent scope of each scope within a
|
||||
// function. The root scope (0) has no parent, so the i'th
|
||||
// scope's parent is stored at Parents[i-1].
|
||||
|
|
@ -649,10 +653,6 @@ type Func struct {
|
|||
|
||||
FieldTrack map[*types.Sym]struct{}
|
||||
DebugInfo *ssa.FuncDebug
|
||||
Ntype *Node // signature
|
||||
Top int // top context (ctxCallee, etc)
|
||||
Closure *Node // OCLOSURE <-> ODCLFUNC (see header comment above)
|
||||
Nname *Node // The ONAME node associated with an ODCLFUNC (both have same Type)
|
||||
lsym *obj.LSym
|
||||
|
||||
Inl *Inline
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue