mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
[dev.regabi] cmd/compile: move name code from node.go to name.go
No code changes here, only copying of text. This will make the diffs in a future CL readable. Passes buildall w/ toolstash -cmp. Change-Id: I1b8d8b9ec9408859e36af5ff3bef7c6c10eac0d6 Reviewed-on: https://go-review.googlesource.com/c/go/+/274092 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
be3d8b40b5
commit
420809ab08
2 changed files with 376 additions and 364 deletions
376
src/cmd/compile/internal/ir/name.go
Normal file
376
src/cmd/compile/internal/ir/name.go
Normal file
|
|
@ -0,0 +1,376 @@
|
||||||
|
// Copyright 2020 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package ir
|
||||||
|
|
||||||
|
import (
|
||||||
|
"cmd/compile/internal/base"
|
||||||
|
"cmd/compile/internal/types"
|
||||||
|
"cmd/internal/objabi"
|
||||||
|
"cmd/internal/src"
|
||||||
|
"go/constant"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Name holds Node fields used only by named nodes (ONAME, OTYPE, OPACK, OLABEL, some OLITERAL).
|
||||||
|
type Name struct {
|
||||||
|
Pack Node // real package for import . names
|
||||||
|
Pkg *types.Pkg // pkg for OPACK nodes
|
||||||
|
// For a local variable (not param) or extern, the initializing assignment (OAS or OAS2).
|
||||||
|
// For a closure var, the ONAME node of the outer captured variable
|
||||||
|
Defn Node
|
||||||
|
// The ODCLFUNC node (for a static function/method or a closure) in which
|
||||||
|
// local variable or param is declared.
|
||||||
|
Curfn Node
|
||||||
|
Param *Param // additional fields for ONAME, OTYPE
|
||||||
|
Decldepth int32 // declaration loop depth, increased for every loop or label
|
||||||
|
// Unique number for ONAME nodes within a function. Function outputs
|
||||||
|
// (results) are numbered starting at one, followed by function inputs
|
||||||
|
// (parameters), and then local variables. Vargen is used to distinguish
|
||||||
|
// local variables/params with the same name.
|
||||||
|
Vargen int32
|
||||||
|
flags bitset16
|
||||||
|
}
|
||||||
|
|
||||||
|
type Param struct {
|
||||||
|
Ntype Node
|
||||||
|
Heapaddr Node // temp holding heap address of param
|
||||||
|
|
||||||
|
// ONAME PAUTOHEAP
|
||||||
|
Stackcopy Node // the PPARAM/PPARAMOUT on-stack slot (moved func params only)
|
||||||
|
|
||||||
|
// ONAME closure linkage
|
||||||
|
// Consider:
|
||||||
|
//
|
||||||
|
// func f() {
|
||||||
|
// x := 1 // x1
|
||||||
|
// func() {
|
||||||
|
// use(x) // x2
|
||||||
|
// func() {
|
||||||
|
// use(x) // x3
|
||||||
|
// --- parser is here ---
|
||||||
|
// }()
|
||||||
|
// }()
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// There is an original declaration of x and then a chain of mentions of x
|
||||||
|
// leading into the current function. Each time x is mentioned in a new closure,
|
||||||
|
// we create a variable representing x for use in that specific closure,
|
||||||
|
// since the way you get to x is different in each closure.
|
||||||
|
//
|
||||||
|
// Let's number the specific variables as shown in the code:
|
||||||
|
// x1 is the original x, x2 is when mentioned in the closure,
|
||||||
|
// and x3 is when mentioned in the closure in the closure.
|
||||||
|
//
|
||||||
|
// We keep these linked (assume N > 1):
|
||||||
|
//
|
||||||
|
// - x1.Defn = original declaration statement for x (like most variables)
|
||||||
|
// - x1.Innermost = current innermost closure x (in this case x3), or nil for none
|
||||||
|
// - x1.IsClosureVar() = false
|
||||||
|
//
|
||||||
|
// - xN.Defn = x1, N > 1
|
||||||
|
// - xN.IsClosureVar() = true, N > 1
|
||||||
|
// - x2.Outer = nil
|
||||||
|
// - xN.Outer = x(N-1), N > 2
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// When we look up x in the symbol table, we always get x1.
|
||||||
|
// Then we can use x1.Innermost (if not nil) to get the x
|
||||||
|
// for the innermost known closure function,
|
||||||
|
// but the first reference in a closure will find either no x1.Innermost
|
||||||
|
// or an x1.Innermost with .Funcdepth < Funcdepth.
|
||||||
|
// In that case, a new xN must be created, linked in with:
|
||||||
|
//
|
||||||
|
// xN.Defn = x1
|
||||||
|
// xN.Outer = x1.Innermost
|
||||||
|
// x1.Innermost = xN
|
||||||
|
//
|
||||||
|
// When we finish the function, we'll process its closure variables
|
||||||
|
// and find xN and pop it off the list using:
|
||||||
|
//
|
||||||
|
// x1 := xN.Defn
|
||||||
|
// x1.Innermost = xN.Outer
|
||||||
|
//
|
||||||
|
// We leave x1.Innermost set so that we can still get to the original
|
||||||
|
// variable quickly. Not shown here, but once we're
|
||||||
|
// done parsing a function and no longer need xN.Outer for the
|
||||||
|
// lexical x reference links as described above, funcLit
|
||||||
|
// recomputes xN.Outer as the semantic x reference link tree,
|
||||||
|
// even filling in x in intermediate closures that might not
|
||||||
|
// have mentioned it along the way to inner closures that did.
|
||||||
|
// See funcLit for details.
|
||||||
|
//
|
||||||
|
// During the eventual compilation, then, for closure variables we have:
|
||||||
|
//
|
||||||
|
// xN.Defn = original variable
|
||||||
|
// xN.Outer = variable captured in next outward scope
|
||||||
|
// to make closure where xN appears
|
||||||
|
//
|
||||||
|
// Because of the sharding of pieces of the node, x.Defn means x.Name.Defn
|
||||||
|
// and x.Innermost/Outer means x.Name.Param.Innermost/Outer.
|
||||||
|
Innermost Node
|
||||||
|
Outer Node
|
||||||
|
|
||||||
|
// OTYPE & ONAME //go:embed info,
|
||||||
|
// sharing storage to reduce gc.Param size.
|
||||||
|
// Extra is nil, or else *Extra is a *paramType or an *embedFileList.
|
||||||
|
Extra *interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewNameAt returns a new ONAME Node associated with symbol s at position pos.
|
||||||
|
// The caller is responsible for setting n.Name.Curfn.
|
||||||
|
func NewNameAt(pos src.XPos, s *types.Sym) Node {
|
||||||
|
if s == nil {
|
||||||
|
base.Fatalf("newnamel nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
var x struct {
|
||||||
|
n node
|
||||||
|
m Name
|
||||||
|
p Param
|
||||||
|
}
|
||||||
|
n := &x.n
|
||||||
|
n.SetName(&x.m)
|
||||||
|
n.Name().Param = &x.p
|
||||||
|
|
||||||
|
n.SetOp(ONAME)
|
||||||
|
n.SetPos(pos)
|
||||||
|
n.SetOrig(n)
|
||||||
|
|
||||||
|
n.SetSym(s)
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
type paramType struct {
|
||||||
|
flag PragmaFlag
|
||||||
|
alias bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pragma returns the PragmaFlag for p, which must be for an OTYPE.
|
||||||
|
func (p *Param) Pragma() PragmaFlag {
|
||||||
|
if p.Extra == nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return (*p.Extra).(*paramType).flag
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetPragma sets the PragmaFlag for p, which must be for an OTYPE.
|
||||||
|
func (p *Param) SetPragma(flag PragmaFlag) {
|
||||||
|
if p.Extra == nil {
|
||||||
|
if flag == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
p.Extra = new(interface{})
|
||||||
|
*p.Extra = ¶mType{flag: flag}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
(*p.Extra).(*paramType).flag = flag
|
||||||
|
}
|
||||||
|
|
||||||
|
// Alias reports whether p, which must be for an OTYPE, is a type alias.
|
||||||
|
func (p *Param) Alias() bool {
|
||||||
|
if p.Extra == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
t, ok := (*p.Extra).(*paramType)
|
||||||
|
if !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return t.alias
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetAlias sets whether p, which must be for an OTYPE, is a type alias.
|
||||||
|
func (p *Param) SetAlias(alias bool) {
|
||||||
|
if p.Extra == nil {
|
||||||
|
if !alias {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
p.Extra = new(interface{})
|
||||||
|
*p.Extra = ¶mType{alias: alias}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
(*p.Extra).(*paramType).alias = alias
|
||||||
|
}
|
||||||
|
|
||||||
|
type embedFileList []string
|
||||||
|
|
||||||
|
// EmbedFiles returns the list of embedded files for p,
|
||||||
|
// which must be for an ONAME var.
|
||||||
|
func (p *Param) EmbedFiles() []string {
|
||||||
|
if p.Extra == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return *(*p.Extra).(*embedFileList)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetEmbedFiles sets the list of embedded files for p,
|
||||||
|
// which must be for an ONAME var.
|
||||||
|
func (p *Param) SetEmbedFiles(list []string) {
|
||||||
|
if p.Extra == nil {
|
||||||
|
if len(list) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
f := embedFileList(list)
|
||||||
|
p.Extra = new(interface{})
|
||||||
|
*p.Extra = &f
|
||||||
|
return
|
||||||
|
}
|
||||||
|
*(*p.Extra).(*embedFileList) = list
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
nameCaptured = 1 << iota // is the variable captured by a closure
|
||||||
|
nameReadonly
|
||||||
|
nameByval // is the variable captured by value or by reference
|
||||||
|
nameNeedzero // if it contains pointers, needs to be zeroed on function entry
|
||||||
|
nameAutoTemp // is the variable a temporary (implies no dwarf info. reset if escapes to heap)
|
||||||
|
nameUsed // for variable declared and not used error
|
||||||
|
nameIsClosureVar // PAUTOHEAP closure pseudo-variable; original at n.Name.Defn
|
||||||
|
nameIsOutputParamHeapAddr // pointer to a result parameter's heap copy
|
||||||
|
nameAssigned // is the variable ever assigned to
|
||||||
|
nameAddrtaken // address taken, even if not moved to heap
|
||||||
|
nameInlFormal // PAUTO created by inliner, derived from callee formal
|
||||||
|
nameInlLocal // PAUTO created by inliner, derived from callee local
|
||||||
|
nameOpenDeferSlot // if temporary var storing info for open-coded defers
|
||||||
|
nameLibfuzzerExtraCounter // if PEXTERN should be assigned to __libfuzzer_extra_counters section
|
||||||
|
)
|
||||||
|
|
||||||
|
func (n *Name) Captured() bool { return n.flags&nameCaptured != 0 }
|
||||||
|
func (n *Name) Readonly() bool { return n.flags&nameReadonly != 0 }
|
||||||
|
func (n *Name) Byval() bool { return n.flags&nameByval != 0 }
|
||||||
|
func (n *Name) Needzero() bool { return n.flags&nameNeedzero != 0 }
|
||||||
|
func (n *Name) AutoTemp() bool { return n.flags&nameAutoTemp != 0 }
|
||||||
|
func (n *Name) Used() bool { return n.flags&nameUsed != 0 }
|
||||||
|
func (n *Name) IsClosureVar() bool { return n.flags&nameIsClosureVar != 0 }
|
||||||
|
func (n *Name) IsOutputParamHeapAddr() bool { return n.flags&nameIsOutputParamHeapAddr != 0 }
|
||||||
|
func (n *Name) Assigned() bool { return n.flags&nameAssigned != 0 }
|
||||||
|
func (n *Name) Addrtaken() bool { return n.flags&nameAddrtaken != 0 }
|
||||||
|
func (n *Name) InlFormal() bool { return n.flags&nameInlFormal != 0 }
|
||||||
|
func (n *Name) InlLocal() bool { return n.flags&nameInlLocal != 0 }
|
||||||
|
func (n *Name) OpenDeferSlot() bool { return n.flags&nameOpenDeferSlot != 0 }
|
||||||
|
func (n *Name) LibfuzzerExtraCounter() bool { return n.flags&nameLibfuzzerExtraCounter != 0 }
|
||||||
|
|
||||||
|
func (n *Name) SetCaptured(b bool) { n.flags.set(nameCaptured, b) }
|
||||||
|
func (n *Name) SetReadonly(b bool) { n.flags.set(nameReadonly, b) }
|
||||||
|
func (n *Name) SetByval(b bool) { n.flags.set(nameByval, b) }
|
||||||
|
func (n *Name) SetNeedzero(b bool) { n.flags.set(nameNeedzero, b) }
|
||||||
|
func (n *Name) SetAutoTemp(b bool) { n.flags.set(nameAutoTemp, b) }
|
||||||
|
func (n *Name) SetUsed(b bool) { n.flags.set(nameUsed, b) }
|
||||||
|
func (n *Name) SetIsClosureVar(b bool) { n.flags.set(nameIsClosureVar, b) }
|
||||||
|
func (n *Name) SetIsOutputParamHeapAddr(b bool) { n.flags.set(nameIsOutputParamHeapAddr, b) }
|
||||||
|
func (n *Name) SetAssigned(b bool) { n.flags.set(nameAssigned, b) }
|
||||||
|
func (n *Name) SetAddrtaken(b bool) { n.flags.set(nameAddrtaken, b) }
|
||||||
|
func (n *Name) SetInlFormal(b bool) { n.flags.set(nameInlFormal, b) }
|
||||||
|
func (n *Name) SetInlLocal(b bool) { n.flags.set(nameInlLocal, b) }
|
||||||
|
func (n *Name) SetOpenDeferSlot(b bool) { n.flags.set(nameOpenDeferSlot, b) }
|
||||||
|
func (n *Name) SetLibfuzzerExtraCounter(b bool) { n.flags.set(nameLibfuzzerExtraCounter, b) }
|
||||||
|
|
||||||
|
// MarkReadonly indicates that n is an ONAME with readonly contents.
|
||||||
|
func (n *node) MarkReadonly() {
|
||||||
|
if n.Op() != ONAME {
|
||||||
|
base.Fatalf("Node.MarkReadonly %v", n.Op())
|
||||||
|
}
|
||||||
|
n.Name().SetReadonly(true)
|
||||||
|
// Mark the linksym as readonly immediately
|
||||||
|
// so that the SSA backend can use this information.
|
||||||
|
// It will be overridden later during dumpglobls.
|
||||||
|
n.Sym().Linksym().Type = objabi.SRODATA
|
||||||
|
}
|
||||||
|
|
||||||
|
// Val returns the constant.Value for the node.
|
||||||
|
func (n *node) Val() constant.Value {
|
||||||
|
if !n.HasVal() {
|
||||||
|
return constant.MakeUnknown()
|
||||||
|
}
|
||||||
|
return *n.e.(*constant.Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetVal sets the constant.Value for the node,
|
||||||
|
// which must not have been used with SetOpt.
|
||||||
|
func (n *node) SetVal(v constant.Value) {
|
||||||
|
if n.hasOpt() {
|
||||||
|
base.Flag.LowerH = 1
|
||||||
|
Dump("have Opt", n)
|
||||||
|
base.Fatalf("have Opt")
|
||||||
|
}
|
||||||
|
if n.Op() == OLITERAL {
|
||||||
|
AssertValidTypeForConst(n.Type(), v)
|
||||||
|
}
|
||||||
|
n.setHasVal(true)
|
||||||
|
n.e = &v
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int64Val returns n as an int64.
|
||||||
|
// n must be an integer or rune constant.
|
||||||
|
func (n *node) Int64Val() int64 {
|
||||||
|
if !IsConst(n, constant.Int) {
|
||||||
|
base.Fatalf("Int64Val(%v)", n)
|
||||||
|
}
|
||||||
|
x, ok := constant.Int64Val(n.Val())
|
||||||
|
if !ok {
|
||||||
|
base.Fatalf("Int64Val(%v)", n)
|
||||||
|
}
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
// CanInt64 reports whether it is safe to call Int64Val() on n.
|
||||||
|
func (n *node) CanInt64() bool {
|
||||||
|
if !IsConst(n, constant.Int) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// if the value inside n cannot be represented as an int64, the
|
||||||
|
// return value of Int64 is undefined
|
||||||
|
_, ok := constant.Int64Val(n.Val())
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uint64Val returns n as an uint64.
|
||||||
|
// n must be an integer or rune constant.
|
||||||
|
func (n *node) Uint64Val() uint64 {
|
||||||
|
if !IsConst(n, constant.Int) {
|
||||||
|
base.Fatalf("Uint64Val(%v)", n)
|
||||||
|
}
|
||||||
|
x, ok := constant.Uint64Val(n.Val())
|
||||||
|
if !ok {
|
||||||
|
base.Fatalf("Uint64Val(%v)", n)
|
||||||
|
}
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
// BoolVal returns n as a bool.
|
||||||
|
// n must be a boolean constant.
|
||||||
|
func (n *node) BoolVal() bool {
|
||||||
|
if !IsConst(n, constant.Bool) {
|
||||||
|
base.Fatalf("BoolVal(%v)", n)
|
||||||
|
}
|
||||||
|
return constant.BoolVal(n.Val())
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringVal returns the value of a literal string Node as a string.
|
||||||
|
// n must be a string constant.
|
||||||
|
func (n *node) StringVal() string {
|
||||||
|
if !IsConst(n, constant.String) {
|
||||||
|
base.Fatalf("StringVal(%v)", n)
|
||||||
|
}
|
||||||
|
return constant.StringVal(n.Val())
|
||||||
|
}
|
||||||
|
|
||||||
|
// The Class of a variable/function describes the "storage class"
|
||||||
|
// of a variable or function. During parsing, storage classes are
|
||||||
|
// called declaration contexts.
|
||||||
|
type Class uint8
|
||||||
|
|
||||||
|
//go:generate stringer -type=Class
|
||||||
|
const (
|
||||||
|
Pxxx Class = iota // no class; used during ssa conversion to indicate pseudo-variables
|
||||||
|
PEXTERN // global variables
|
||||||
|
PAUTO // local variables
|
||||||
|
PAUTOHEAP // local variables or parameters moved to heap
|
||||||
|
PPARAM // input arguments
|
||||||
|
PPARAMOUT // output results
|
||||||
|
PFUNC // global functions
|
||||||
|
|
||||||
|
// Careful: Class is stored in three bits in Node.flags.
|
||||||
|
_ = uint((1 << 3) - iota) // static assert for iota <= (1 << 3)
|
||||||
|
)
|
||||||
|
|
@ -15,7 +15,6 @@ import (
|
||||||
"cmd/compile/internal/base"
|
"cmd/compile/internal/base"
|
||||||
"cmd/compile/internal/types"
|
"cmd/compile/internal/types"
|
||||||
"cmd/internal/obj"
|
"cmd/internal/obj"
|
||||||
"cmd/internal/objabi"
|
|
||||||
"cmd/internal/src"
|
"cmd/internal/src"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -379,41 +378,6 @@ func (n *node) SetBounded(b bool) {
|
||||||
n.flags.set(nodeBounded, b)
|
n.flags.set(nodeBounded, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MarkReadonly indicates that n is an ONAME with readonly contents.
|
|
||||||
func (n *node) MarkReadonly() {
|
|
||||||
if n.Op() != ONAME {
|
|
||||||
base.Fatalf("Node.MarkReadonly %v", n.Op())
|
|
||||||
}
|
|
||||||
n.Name().SetReadonly(true)
|
|
||||||
// Mark the linksym as readonly immediately
|
|
||||||
// so that the SSA backend can use this information.
|
|
||||||
// It will be overridden later during dumpglobls.
|
|
||||||
n.Sym().Linksym().Type = objabi.SRODATA
|
|
||||||
}
|
|
||||||
|
|
||||||
// Val returns the constant.Value for the node.
|
|
||||||
func (n *node) Val() constant.Value {
|
|
||||||
if !n.HasVal() {
|
|
||||||
return constant.MakeUnknown()
|
|
||||||
}
|
|
||||||
return *n.e.(*constant.Value)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetVal sets the constant.Value for the node,
|
|
||||||
// which must not have been used with SetOpt.
|
|
||||||
func (n *node) SetVal(v constant.Value) {
|
|
||||||
if n.hasOpt() {
|
|
||||||
base.Flag.LowerH = 1
|
|
||||||
Dump("have Opt", n)
|
|
||||||
base.Fatalf("have Opt")
|
|
||||||
}
|
|
||||||
if n.Op() == OLITERAL {
|
|
||||||
AssertValidTypeForConst(n.Type(), v)
|
|
||||||
}
|
|
||||||
n.setHasVal(true)
|
|
||||||
n.e = &v
|
|
||||||
}
|
|
||||||
|
|
||||||
// Opt returns the optimizer data for the node.
|
// Opt returns the optimizer data for the node.
|
||||||
func (n *node) Opt() interface{} {
|
func (n *node) Opt() interface{} {
|
||||||
if !n.hasOpt() {
|
if !n.hasOpt() {
|
||||||
|
|
@ -500,235 +464,6 @@ func PkgFuncName(n Node) string {
|
||||||
func (n *node) CanBeAnSSASym() {
|
func (n *node) CanBeAnSSASym() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Name holds Node fields used only by named nodes (ONAME, OTYPE, OPACK, OLABEL, some OLITERAL).
|
|
||||||
type Name struct {
|
|
||||||
Pack Node // real package for import . names
|
|
||||||
Pkg *types.Pkg // pkg for OPACK nodes
|
|
||||||
// For a local variable (not param) or extern, the initializing assignment (OAS or OAS2).
|
|
||||||
// For a closure var, the ONAME node of the outer captured variable
|
|
||||||
Defn Node
|
|
||||||
// The ODCLFUNC node (for a static function/method or a closure) in which
|
|
||||||
// local variable or param is declared.
|
|
||||||
Curfn Node
|
|
||||||
Param *Param // additional fields for ONAME, OTYPE
|
|
||||||
Decldepth int32 // declaration loop depth, increased for every loop or label
|
|
||||||
// Unique number for ONAME nodes within a function. Function outputs
|
|
||||||
// (results) are numbered starting at one, followed by function inputs
|
|
||||||
// (parameters), and then local variables. Vargen is used to distinguish
|
|
||||||
// local variables/params with the same name.
|
|
||||||
Vargen int32
|
|
||||||
flags bitset16
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
nameCaptured = 1 << iota // is the variable captured by a closure
|
|
||||||
nameReadonly
|
|
||||||
nameByval // is the variable captured by value or by reference
|
|
||||||
nameNeedzero // if it contains pointers, needs to be zeroed on function entry
|
|
||||||
nameAutoTemp // is the variable a temporary (implies no dwarf info. reset if escapes to heap)
|
|
||||||
nameUsed // for variable declared and not used error
|
|
||||||
nameIsClosureVar // PAUTOHEAP closure pseudo-variable; original at n.Name.Defn
|
|
||||||
nameIsOutputParamHeapAddr // pointer to a result parameter's heap copy
|
|
||||||
nameAssigned // is the variable ever assigned to
|
|
||||||
nameAddrtaken // address taken, even if not moved to heap
|
|
||||||
nameInlFormal // PAUTO created by inliner, derived from callee formal
|
|
||||||
nameInlLocal // PAUTO created by inliner, derived from callee local
|
|
||||||
nameOpenDeferSlot // if temporary var storing info for open-coded defers
|
|
||||||
nameLibfuzzerExtraCounter // if PEXTERN should be assigned to __libfuzzer_extra_counters section
|
|
||||||
)
|
|
||||||
|
|
||||||
func (n *Name) Captured() bool { return n.flags&nameCaptured != 0 }
|
|
||||||
func (n *Name) Readonly() bool { return n.flags&nameReadonly != 0 }
|
|
||||||
func (n *Name) Byval() bool { return n.flags&nameByval != 0 }
|
|
||||||
func (n *Name) Needzero() bool { return n.flags&nameNeedzero != 0 }
|
|
||||||
func (n *Name) AutoTemp() bool { return n.flags&nameAutoTemp != 0 }
|
|
||||||
func (n *Name) Used() bool { return n.flags&nameUsed != 0 }
|
|
||||||
func (n *Name) IsClosureVar() bool { return n.flags&nameIsClosureVar != 0 }
|
|
||||||
func (n *Name) IsOutputParamHeapAddr() bool { return n.flags&nameIsOutputParamHeapAddr != 0 }
|
|
||||||
func (n *Name) Assigned() bool { return n.flags&nameAssigned != 0 }
|
|
||||||
func (n *Name) Addrtaken() bool { return n.flags&nameAddrtaken != 0 }
|
|
||||||
func (n *Name) InlFormal() bool { return n.flags&nameInlFormal != 0 }
|
|
||||||
func (n *Name) InlLocal() bool { return n.flags&nameInlLocal != 0 }
|
|
||||||
func (n *Name) OpenDeferSlot() bool { return n.flags&nameOpenDeferSlot != 0 }
|
|
||||||
func (n *Name) LibfuzzerExtraCounter() bool { return n.flags&nameLibfuzzerExtraCounter != 0 }
|
|
||||||
|
|
||||||
func (n *Name) SetCaptured(b bool) { n.flags.set(nameCaptured, b) }
|
|
||||||
func (n *Name) SetReadonly(b bool) { n.flags.set(nameReadonly, b) }
|
|
||||||
func (n *Name) SetByval(b bool) { n.flags.set(nameByval, b) }
|
|
||||||
func (n *Name) SetNeedzero(b bool) { n.flags.set(nameNeedzero, b) }
|
|
||||||
func (n *Name) SetAutoTemp(b bool) { n.flags.set(nameAutoTemp, b) }
|
|
||||||
func (n *Name) SetUsed(b bool) { n.flags.set(nameUsed, b) }
|
|
||||||
func (n *Name) SetIsClosureVar(b bool) { n.flags.set(nameIsClosureVar, b) }
|
|
||||||
func (n *Name) SetIsOutputParamHeapAddr(b bool) { n.flags.set(nameIsOutputParamHeapAddr, b) }
|
|
||||||
func (n *Name) SetAssigned(b bool) { n.flags.set(nameAssigned, b) }
|
|
||||||
func (n *Name) SetAddrtaken(b bool) { n.flags.set(nameAddrtaken, b) }
|
|
||||||
func (n *Name) SetInlFormal(b bool) { n.flags.set(nameInlFormal, b) }
|
|
||||||
func (n *Name) SetInlLocal(b bool) { n.flags.set(nameInlLocal, b) }
|
|
||||||
func (n *Name) SetOpenDeferSlot(b bool) { n.flags.set(nameOpenDeferSlot, b) }
|
|
||||||
func (n *Name) SetLibfuzzerExtraCounter(b bool) { n.flags.set(nameLibfuzzerExtraCounter, b) }
|
|
||||||
|
|
||||||
type Param struct {
|
|
||||||
Ntype Node
|
|
||||||
Heapaddr Node // temp holding heap address of param
|
|
||||||
|
|
||||||
// ONAME PAUTOHEAP
|
|
||||||
Stackcopy Node // the PPARAM/PPARAMOUT on-stack slot (moved func params only)
|
|
||||||
|
|
||||||
// ONAME closure linkage
|
|
||||||
// Consider:
|
|
||||||
//
|
|
||||||
// func f() {
|
|
||||||
// x := 1 // x1
|
|
||||||
// func() {
|
|
||||||
// use(x) // x2
|
|
||||||
// func() {
|
|
||||||
// use(x) // x3
|
|
||||||
// --- parser is here ---
|
|
||||||
// }()
|
|
||||||
// }()
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// There is an original declaration of x and then a chain of mentions of x
|
|
||||||
// leading into the current function. Each time x is mentioned in a new closure,
|
|
||||||
// we create a variable representing x for use in that specific closure,
|
|
||||||
// since the way you get to x is different in each closure.
|
|
||||||
//
|
|
||||||
// Let's number the specific variables as shown in the code:
|
|
||||||
// x1 is the original x, x2 is when mentioned in the closure,
|
|
||||||
// and x3 is when mentioned in the closure in the closure.
|
|
||||||
//
|
|
||||||
// We keep these linked (assume N > 1):
|
|
||||||
//
|
|
||||||
// - x1.Defn = original declaration statement for x (like most variables)
|
|
||||||
// - x1.Innermost = current innermost closure x (in this case x3), or nil for none
|
|
||||||
// - x1.IsClosureVar() = false
|
|
||||||
//
|
|
||||||
// - xN.Defn = x1, N > 1
|
|
||||||
// - xN.IsClosureVar() = true, N > 1
|
|
||||||
// - x2.Outer = nil
|
|
||||||
// - xN.Outer = x(N-1), N > 2
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// When we look up x in the symbol table, we always get x1.
|
|
||||||
// Then we can use x1.Innermost (if not nil) to get the x
|
|
||||||
// for the innermost known closure function,
|
|
||||||
// but the first reference in a closure will find either no x1.Innermost
|
|
||||||
// or an x1.Innermost with .Funcdepth < Funcdepth.
|
|
||||||
// In that case, a new xN must be created, linked in with:
|
|
||||||
//
|
|
||||||
// xN.Defn = x1
|
|
||||||
// xN.Outer = x1.Innermost
|
|
||||||
// x1.Innermost = xN
|
|
||||||
//
|
|
||||||
// When we finish the function, we'll process its closure variables
|
|
||||||
// and find xN and pop it off the list using:
|
|
||||||
//
|
|
||||||
// x1 := xN.Defn
|
|
||||||
// x1.Innermost = xN.Outer
|
|
||||||
//
|
|
||||||
// We leave x1.Innermost set so that we can still get to the original
|
|
||||||
// variable quickly. Not shown here, but once we're
|
|
||||||
// done parsing a function and no longer need xN.Outer for the
|
|
||||||
// lexical x reference links as described above, funcLit
|
|
||||||
// recomputes xN.Outer as the semantic x reference link tree,
|
|
||||||
// even filling in x in intermediate closures that might not
|
|
||||||
// have mentioned it along the way to inner closures that did.
|
|
||||||
// See funcLit for details.
|
|
||||||
//
|
|
||||||
// During the eventual compilation, then, for closure variables we have:
|
|
||||||
//
|
|
||||||
// xN.Defn = original variable
|
|
||||||
// xN.Outer = variable captured in next outward scope
|
|
||||||
// to make closure where xN appears
|
|
||||||
//
|
|
||||||
// Because of the sharding of pieces of the node, x.Defn means x.Name.Defn
|
|
||||||
// and x.Innermost/Outer means x.Name.Param.Innermost/Outer.
|
|
||||||
Innermost Node
|
|
||||||
Outer Node
|
|
||||||
|
|
||||||
// OTYPE & ONAME //go:embed info,
|
|
||||||
// sharing storage to reduce gc.Param size.
|
|
||||||
// Extra is nil, or else *Extra is a *paramType or an *embedFileList.
|
|
||||||
Extra *interface{}
|
|
||||||
}
|
|
||||||
|
|
||||||
type paramType struct {
|
|
||||||
flag PragmaFlag
|
|
||||||
alias bool
|
|
||||||
}
|
|
||||||
|
|
||||||
type embedFileList []string
|
|
||||||
|
|
||||||
// Pragma returns the PragmaFlag for p, which must be for an OTYPE.
|
|
||||||
func (p *Param) Pragma() PragmaFlag {
|
|
||||||
if p.Extra == nil {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
return (*p.Extra).(*paramType).flag
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetPragma sets the PragmaFlag for p, which must be for an OTYPE.
|
|
||||||
func (p *Param) SetPragma(flag PragmaFlag) {
|
|
||||||
if p.Extra == nil {
|
|
||||||
if flag == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
p.Extra = new(interface{})
|
|
||||||
*p.Extra = ¶mType{flag: flag}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
(*p.Extra).(*paramType).flag = flag
|
|
||||||
}
|
|
||||||
|
|
||||||
// Alias reports whether p, which must be for an OTYPE, is a type alias.
|
|
||||||
func (p *Param) Alias() bool {
|
|
||||||
if p.Extra == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
t, ok := (*p.Extra).(*paramType)
|
|
||||||
if !ok {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return t.alias
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetAlias sets whether p, which must be for an OTYPE, is a type alias.
|
|
||||||
func (p *Param) SetAlias(alias bool) {
|
|
||||||
if p.Extra == nil {
|
|
||||||
if !alias {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
p.Extra = new(interface{})
|
|
||||||
*p.Extra = ¶mType{alias: alias}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
(*p.Extra).(*paramType).alias = alias
|
|
||||||
}
|
|
||||||
|
|
||||||
// EmbedFiles returns the list of embedded files for p,
|
|
||||||
// which must be for an ONAME var.
|
|
||||||
func (p *Param) EmbedFiles() []string {
|
|
||||||
if p.Extra == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return *(*p.Extra).(*embedFileList)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetEmbedFiles sets the list of embedded files for p,
|
|
||||||
// which must be for an ONAME var.
|
|
||||||
func (p *Param) SetEmbedFiles(list []string) {
|
|
||||||
if p.Extra == nil {
|
|
||||||
if len(list) == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
f := embedFileList(list)
|
|
||||||
p.Extra = new(interface{})
|
|
||||||
*p.Extra = &f
|
|
||||||
return
|
|
||||||
}
|
|
||||||
*(*p.Extra).(*embedFileList) = list
|
|
||||||
}
|
|
||||||
|
|
||||||
// A Func corresponds to a single function in a Go program
|
// A Func corresponds to a single function in a Go program
|
||||||
// (and vice versa: each function is denoted by exactly one *Func).
|
// (and vice versa: each function is denoted by exactly one *Func).
|
||||||
//
|
//
|
||||||
|
|
@ -1369,49 +1104,6 @@ func (s NodeSet) Sorted(less func(Node, Node) bool) []Node {
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewNameAt returns a new ONAME Node associated with symbol s at position pos.
|
|
||||||
// The caller is responsible for setting n.Name.Curfn.
|
|
||||||
func NewNameAt(pos src.XPos, s *types.Sym) Node {
|
|
||||||
if s == nil {
|
|
||||||
base.Fatalf("newnamel nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
var x struct {
|
|
||||||
n node
|
|
||||||
m Name
|
|
||||||
p Param
|
|
||||||
}
|
|
||||||
n := &x.n
|
|
||||||
n.SetName(&x.m)
|
|
||||||
n.Name().Param = &x.p
|
|
||||||
|
|
||||||
n.SetOp(ONAME)
|
|
||||||
n.SetPos(pos)
|
|
||||||
n.SetOrig(n)
|
|
||||||
|
|
||||||
n.SetSym(s)
|
|
||||||
return n
|
|
||||||
}
|
|
||||||
|
|
||||||
// The Class of a variable/function describes the "storage class"
|
|
||||||
// of a variable or function. During parsing, storage classes are
|
|
||||||
// called declaration contexts.
|
|
||||||
type Class uint8
|
|
||||||
|
|
||||||
//go:generate stringer -type=Class
|
|
||||||
const (
|
|
||||||
Pxxx Class = iota // no class; used during ssa conversion to indicate pseudo-variables
|
|
||||||
PEXTERN // global variables
|
|
||||||
PAUTO // local variables
|
|
||||||
PAUTOHEAP // local variables or parameters moved to heap
|
|
||||||
PPARAM // input arguments
|
|
||||||
PPARAMOUT // output results
|
|
||||||
PFUNC // global functions
|
|
||||||
|
|
||||||
// Careful: Class is stored in three bits in Node.flags.
|
|
||||||
_ = uint((1 << 3) - iota) // static assert for iota <= (1 << 3)
|
|
||||||
)
|
|
||||||
|
|
||||||
type PragmaFlag int16
|
type PragmaFlag int16
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
@ -1550,62 +1242,6 @@ func IsConst(n Node, ct constant.Kind) bool {
|
||||||
return ConstType(n) == ct
|
return ConstType(n) == ct
|
||||||
}
|
}
|
||||||
|
|
||||||
// Int64Val returns n as an int64.
|
|
||||||
// n must be an integer or rune constant.
|
|
||||||
func (n *node) Int64Val() int64 {
|
|
||||||
if !IsConst(n, constant.Int) {
|
|
||||||
base.Fatalf("Int64Val(%v)", n)
|
|
||||||
}
|
|
||||||
x, ok := constant.Int64Val(n.Val())
|
|
||||||
if !ok {
|
|
||||||
base.Fatalf("Int64Val(%v)", n)
|
|
||||||
}
|
|
||||||
return x
|
|
||||||
}
|
|
||||||
|
|
||||||
// CanInt64 reports whether it is safe to call Int64Val() on n.
|
|
||||||
func (n *node) CanInt64() bool {
|
|
||||||
if !IsConst(n, constant.Int) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// if the value inside n cannot be represented as an int64, the
|
|
||||||
// return value of Int64 is undefined
|
|
||||||
_, ok := constant.Int64Val(n.Val())
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
// Uint64Val returns n as an uint64.
|
|
||||||
// n must be an integer or rune constant.
|
|
||||||
func (n *node) Uint64Val() uint64 {
|
|
||||||
if !IsConst(n, constant.Int) {
|
|
||||||
base.Fatalf("Uint64Val(%v)", n)
|
|
||||||
}
|
|
||||||
x, ok := constant.Uint64Val(n.Val())
|
|
||||||
if !ok {
|
|
||||||
base.Fatalf("Uint64Val(%v)", n)
|
|
||||||
}
|
|
||||||
return x
|
|
||||||
}
|
|
||||||
|
|
||||||
// BoolVal returns n as a bool.
|
|
||||||
// n must be a boolean constant.
|
|
||||||
func (n *node) BoolVal() bool {
|
|
||||||
if !IsConst(n, constant.Bool) {
|
|
||||||
base.Fatalf("BoolVal(%v)", n)
|
|
||||||
}
|
|
||||||
return constant.BoolVal(n.Val())
|
|
||||||
}
|
|
||||||
|
|
||||||
// StringVal returns the value of a literal string Node as a string.
|
|
||||||
// n must be a string constant.
|
|
||||||
func (n *node) StringVal() string {
|
|
||||||
if !IsConst(n, constant.String) {
|
|
||||||
base.Fatalf("StringVal(%v)", n)
|
|
||||||
}
|
|
||||||
return constant.StringVal(n.Val())
|
|
||||||
}
|
|
||||||
|
|
||||||
// rawcopy returns a shallow copy of n.
|
// rawcopy returns a shallow copy of n.
|
||||||
// Note: copy or sepcopy (rather than rawcopy) is usually the
|
// Note: copy or sepcopy (rather than rawcopy) is usually the
|
||||||
// correct choice (see comment with Node.copy, below).
|
// correct choice (see comment with Node.copy, below).
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue