}
fn.SetNilCheckDisabled(true)
- xtop = append(xtop, fn)
+ Target.Decls = append(Target.Decls, fn)
// Build closure. It doesn't close over any variables, so
// it contains just the function pointer.
// neither of which can be nil, and our comparisons
// are shallow.
fn.SetNilCheckDisabled(true)
- xtop = append(xtop, fn)
+ Target.Decls = append(Target.Decls, fn)
// Generate a closure which points at the function we just generated.
dsymptr(closure, 0, sym.Linksym(), 0)
if n.Op() == ir.ONAME {
n := n.(*ir.Name)
if n.Class() == ir.PFUNC {
- inlFlood(n)
+ inlFlood(n, exportsym)
}
}
fn.SetClosureCalled(top&ctxCallee != 0)
// Do not typecheck fn twice, otherwise, we will end up pushing
- // fn to xtop multiple times, causing initLSym called twice.
+ // fn to Target.Decls multiple times, causing initLSym called twice.
// See #30709
if fn.Typecheck() == 1 {
return
// Type check the body now, but only if we're inside a function.
// At top level (in a variable initialization: curfn==nil) we're not
// ready to type check code yet; we'll check it later, because the
- // underlying closure function we create is added to xtop.
+ // underlying closure function we create is added to Target.Decls.
if Curfn != nil && clo.Type() != nil {
oldfn := Curfn
Curfn = fn
Curfn = oldfn
}
- xtop = append(xtop, fn)
+ Target.Decls = append(Target.Decls, fn)
}
// globClosgen is like Func.Closgen, but for the global scope.
Curfn = fn
typecheckslice(fn.Body().Slice(), ctxStmt)
sym.Def = fn
- xtop = append(xtop, fn)
+ Target.Decls = append(Target.Decls, fn)
Curfn = savecurfn
base.Pos = saveLineNo
// Declaration stack & operations
-var externdcl []ir.Node
-
func testdclstack() {
if !types.IsDclstackValid() {
base.Fatalf("mark left on the dclstack")
if s.Name == "main" && s.Pkg.Name == "main" {
base.ErrorfAt(n.Pos(), "cannot declare main - must be func")
}
- externdcl = append(externdcl, n)
+ Target.Externs = append(Target.Externs, n)
} else {
if Curfn == nil && ctxt == ir.PAUTO {
base.Pos = n.Pos()
// important to handle it for this check, so we model it
// directly. This has to happen before transformclosure since
// it's a lot harder to work out the argument after.
- for _, n := range xtop {
+ for _, n := range Target.Decls {
if n.Op() != ir.ODCLFUNC {
continue
}
// q is the queue of ODCLFUNC Nodes to visit in BFS order.
var q ir.NameQueue
- for _, n := range xtop {
+ for _, n := range Target.Decls {
if n.Op() != ir.ODCLFUNC {
continue
}
"strings"
)
-var embedlist []ir.Node
-
const (
embedUnknown = iota
embedBytes
v.Sym().Def = v
v.Name().Ntype = typ
v.SetClass(ir.PEXTERN)
- externdcl = append(externdcl, v)
+ Target.Externs = append(Target.Externs, v)
exprs = []ir.Node{v}
}
v.Name().SetEmbedFiles(list)
- embedlist = append(embedlist, v)
+ Target.Embeds = append(Target.Embeds, v)
return exprs
}
}
func dumpembeds() {
- for _, v := range embedlist {
+ for _, v := range Target.Embeds {
initEmbed(v)
}
}
}
}
-var asmlist []ir.Node
-
// exportsym marks n for export (or reexport).
func exportsym(n *ir.Name) {
if n.Sym().OnExportList() {
fmt.Printf("export symbol %v\n", n.Sym())
}
- exportlist = append(exportlist, n)
+ Target.Exports = append(Target.Exports, n)
}
func initname(s string) bool {
}
if base.Flag.AsmHdr != "" && !n.Sym().Asm() {
n.Sym().SetAsm(true)
- asmlist = append(asmlist, n)
+ Target.Asms = append(Target.Asms, n)
}
}
base.Fatalf("%v", err)
}
fmt.Fprintf(b, "// generated by compile -asmhdr from package %s\n\n", types.LocalPkg.Name)
- for _, n := range asmlist {
+ for _, n := range Target.Asms {
if n.Sym().IsBlank() {
continue
}
iscmp [ir.OEND]bool
)
-var xtop []ir.Node
-
-var exportlist []*ir.Name
-
var importlist []*ir.Func // imported functions and methods with inlinable bodies
var (
{
// TODO(mdempsky): Separate from bexport logic.
p := &exporter{marked: make(map[*types.Type]bool)}
- for _, n := range exportlist {
+ for _, n := range Target.Exports {
p.markObject(n)
}
}
}
// Initialize work queue with exported declarations.
- for _, n := range exportlist {
+ for _, n := range Target.Exports {
p.pushDecl(n)
}
}
func builtinCall(pos src.XPos, op ir.Op) *ir.CallExpr {
- return ir.NewCallExpr(pos, ir.OCALL, mkname(types.BuiltinPkg.Lookup(ir.OpNames[op])), nil)
+ return ir.NewCallExpr(pos, ir.OCALL, ir.NewIdent(base.Pos, types.BuiltinPkg.Lookup(ir.OpNames[op])), nil)
}
func npos(pos src.XPos, n ir.Node) ir.Node {
return s
}
-// List of imported packages, in source code order. See #31636.
-var sourceOrderImports []*types.Pkg
-
// fninit makes an initialization record for the package.
// See runtime/proc.go:initTask for its layout.
// The 3 tasks for initialization are:
var fns []*obj.LSym // functions to call for package initialization
// Find imported packages with init tasks.
- for _, pkg := range sourceOrderImports {
+ for _, pkg := range Target.Imports {
n := resolve(oldname(pkg.Lookup(".inittask")))
if n.Op() == ir.ONONAME {
continue
Curfn = fn
typecheckslice(nf, ctxStmt)
Curfn = nil
- xtop = append(xtop, fn)
+ Target.Decls = append(Target.Decls, fn)
fns = append(fns, initializers.Linksym())
}
if initTodo.Dcl != nil {
initTodo = nil
// Record user init functions.
- for i := 0; i < renameinitgen; i++ {
- s := lookupN("init.", i)
- fn := ir.AsNode(s.Def).Name().Defn.(*ir.Func)
+ for _, fn := range Target.Inits {
// Skip init functions with empty bodies.
if fn.Body().Len() == 1 {
if stmt := fn.Body().First(); stmt.Op() == ir.OBLOCK && stmt.(*ir.BlockStmt).List().Len() == 0 {
continue
}
}
- fns = append(fns, s.Linksym())
+ fns = append(fns, fn.Nname.Sym().Linksym())
}
if len(deps) == 0 && len(fns) == 0 && types.LocalPkg.Name != "main" && types.LocalPkg.Name != "runtime" {
// inlFlood marks n's inline body for export and recursively ensures
// all called functions are marked too.
-func inlFlood(n *ir.Name) {
+func inlFlood(n *ir.Name, exportsym func(*ir.Name)) {
if n == nil {
return
}
ir.VisitList(ir.AsNodes(fn.Inl.Body), func(n ir.Node) {
switch n.Op() {
case ir.OMETHEXPR, ir.ODOTMETH:
- inlFlood(methodExprName(n))
+ inlFlood(methodExprName(n), exportsym)
case ir.ONAME:
n := n.(*ir.Name)
switch n.Class() {
case ir.PFUNC:
- inlFlood(n)
+ inlFlood(n, exportsym)
exportsym(n)
case ir.PEXTERN:
exportsym(n)
}
}
+// Target is the package being compiled.
+var Target *ir.Package
+
// timing data for compiler phases
var timings Timings
Widthptr = thearch.LinkArch.PtrSize
Widthreg = thearch.LinkArch.RegSize
+ Target = new(ir.Package)
+
// initialize types package
// (we need to do this to break dependencies that otherwise
// would lead to import cycles)
// to avoid cycles like #18640.
// TODO(gri) Remove this again once we have a fix for #25838.
- // Don't use range--typecheck can add closures to xtop.
+ // Don't use range--typecheck can add closures to Target.Decls.
timings.Start("fe", "typecheck", "top1")
- for i := 0; i < len(xtop); i++ {
- n := xtop[i]
+ for i := 0; i < len(Target.Decls); i++ {
+ n := Target.Decls[i]
if op := n.Op(); op != ir.ODCL && op != ir.OAS && op != ir.OAS2 && (op != ir.ODCLTYPE || !n.(*ir.Decl).Left().Name().Alias()) {
- xtop[i] = typecheck(n, ctxStmt)
+ Target.Decls[i] = typecheck(n, ctxStmt)
}
}
// Phase 2: Variable assignments.
// To check interface assignments, depends on phase 1.
- // Don't use range--typecheck can add closures to xtop.
+ // Don't use range--typecheck can add closures to Target.Decls.
timings.Start("fe", "typecheck", "top2")
- for i := 0; i < len(xtop); i++ {
- n := xtop[i]
+ for i := 0; i < len(Target.Decls); i++ {
+ n := Target.Decls[i]
if op := n.Op(); op == ir.ODCL || op == ir.OAS || op == ir.OAS2 || op == ir.ODCLTYPE && n.(*ir.Decl).Left().Name().Alias() {
- xtop[i] = typecheck(n, ctxStmt)
+ Target.Decls[i] = typecheck(n, ctxStmt)
}
}
// Phase 3: Type check function bodies.
- // Don't use range--typecheck can add closures to xtop.
+ // Don't use range--typecheck can add closures to Target.Decls.
timings.Start("fe", "typecheck", "func")
var fcount int64
- for i := 0; i < len(xtop); i++ {
- n := xtop[i]
+ for i := 0; i < len(Target.Decls); i++ {
+ n := Target.Decls[i]
if n.Op() == ir.ODCLFUNC {
Curfn = n.(*ir.Func)
decldepth = 1
// TODO(mdempsky): This should be handled when type checking their
// corresponding ODCL nodes.
timings.Start("fe", "typecheck", "externdcls")
- for i, n := range externdcl {
+ for i, n := range Target.Externs {
if n.Op() == ir.ONAME {
- externdcl[i] = typecheck(externdcl[i], ctxExpr)
+ Target.Externs[i] = typecheck(Target.Externs[i], ctxExpr)
}
}
timings.AddEvent(fcount, "funcs")
- fninit(xtop)
+ fninit(Target.Decls)
// Phase 4: Decide how to capture closed variables.
// This needs to run before escape analysis,
// because variables captured by value do not escape.
timings.Start("fe", "capturevars")
- for _, n := range xtop {
+ for _, n := range Target.Decls {
if n.Op() == ir.ODCLFUNC && n.Func().OClosure != nil {
Curfn = n.(*ir.Func)
capturevars(Curfn)
if base.Flag.LowerL != 0 {
// Find functions that can be inlined and clone them before walk expands them.
- visitBottomUp(xtop, func(list []*ir.Func, recursive bool) {
+ visitBottomUp(Target.Decls, func(list []*ir.Func, recursive bool) {
numfns := numNonClosures(list)
for _, n := range list {
if !recursive || numfns > 1 {
})
}
- for _, n := range xtop {
+ for _, n := range Target.Decls {
if n.Op() == ir.ODCLFUNC {
devirtualize(n.(*ir.Func))
}
// Large values are also moved off stack in escape analysis;
// because large values may contain pointers, it must happen early.
timings.Start("fe", "escapes")
- escapes(xtop)
+ escapes(Target.Decls)
// Collect information for go:nowritebarrierrec
// checking. This must happen before transformclosure.
// This needs to happen before walk, because closures must be transformed
// before walk reaches a call of a closure.
timings.Start("fe", "xclosures")
- for _, n := range xtop {
+ for _, n := range Target.Decls {
if n.Op() == ir.ODCLFUNC && n.Func().OClosure != nil {
Curfn = n.(*ir.Func)
transformclosure(Curfn)
peekitabs()
// Phase 8: Compile top level functions.
- // Don't use range--walk can add functions to xtop.
+ // Don't use range--walk can add functions to Target.Decls.
timings.Start("be", "compilefuncs")
fcount = 0
- for i := 0; i < len(xtop); i++ {
- n := xtop[i]
+ for i := 0; i < len(Target.Decls); i++ {
+ n := Target.Decls[i]
if n.Op() == ir.ODCLFUNC {
funccompile(n.(*ir.Func))
fcount++
// parseFiles concurrently parses files into *syntax.File structures.
// Each declaration in every *syntax.File is converted to a syntax tree
-// and its root represented by *Node is appended to xtop.
+// and its root represented by *Node is appended to Target.Decls.
// Returns the total count of parsed lines.
func parseFiles(filenames []string) uint {
noders := make([]*noder, 0, len(filenames))
p.checkUnused(pragma)
}
- xtop = append(xtop, p.decls(p.file.DeclList)...)
+ Target.Decls = append(Target.Decls, p.decls(p.file.DeclList)...)
base.Pos = src.NoXPos
clearImports()
}
}
- pragcgobuf = append(pragcgobuf, p.pragcgobuf...)
+ Target.CgoPragmas = append(Target.CgoPragmas, p.pragcgobuf...)
}
func (p *noder) decls(decls []syntax.Decl) (l []ir.Node) {
}
if !ipkg.Direct {
- sourceOrderImports = append(sourceOrderImports, ipkg)
+ Target.Imports = append(Target.Imports, ipkg)
}
ipkg.Direct = true
if len(t.Params) > 0 || len(t.Results) > 0 {
base.ErrorfAt(f.Pos(), "func init must have no arguments and no return values")
}
+ Target.Inits = append(Target.Inits, f)
}
if types.LocalPkg.Name == "main" && name.Name == "main" {
}
func dumpdata() {
- externs := len(externdcl)
- xtops := len(xtop)
+ numExterns := len(Target.Externs)
+ numDecls := len(Target.Decls)
- dumpglobls()
+ dumpglobls(Target.Externs)
+ dumpfuncsyms()
addptabs()
- exportlistLen := len(exportlist)
- addsignats(externdcl)
+ numExports := len(Target.Exports)
+ addsignats(Target.Externs)
dumpsignats()
dumptabs()
ptabsLen := len(ptabs)
// In the typical case, we loop 0 or 1 times.
// It was not until issue 24761 that we found any code that required a loop at all.
for {
- for i := xtops; i < len(xtop); i++ {
- n := xtop[i]
+ for i := numDecls; i < len(Target.Decls); i++ {
+ n := Target.Decls[i]
if n.Op() == ir.ODCLFUNC {
funccompile(n.(*ir.Func))
}
}
- xtops = len(xtop)
+ numDecls = len(Target.Decls)
compileFunctions()
dumpsignats()
- if xtops == len(xtop) {
+ if numDecls == len(Target.Decls) {
break
}
}
// Dump extra globals.
- tmp := externdcl
-
- if externdcl != nil {
- externdcl = externdcl[externs:]
- }
- dumpglobls()
- externdcl = tmp
+ dumpglobls(Target.Externs[numExterns:])
if zerosize > 0 {
zero := mappkg.Lookup("zero")
addGCLocals()
- if exportlistLen != len(exportlist) {
- base.Fatalf("exportlist changed after compile functions loop")
+ if numExports != len(Target.Exports) {
+ base.Fatalf("Target.Exports changed after compile functions loop")
}
if ptabsLen != len(ptabs) {
base.Fatalf("ptabs changed after compile functions loop")
func dumpLinkerObj(bout *bio.Writer) {
printObjHeader(bout)
- if len(pragcgobuf) != 0 {
+ if len(Target.CgoPragmas) != 0 {
// write empty export section; must be before cgo section
fmt.Fprintf(bout, "\n$$\n\n$$\n\n")
fmt.Fprintf(bout, "\n$$ // cgo\n")
- if err := json.NewEncoder(bout).Encode(pragcgobuf); err != nil {
+ if err := json.NewEncoder(bout).Encode(Target.CgoPragmas); err != nil {
base.Fatalf("serializing pragcgobuf: %v", err)
}
fmt.Fprintf(bout, "\n$$\n\n")
if !base.Ctxt.Flag_dynlink || types.LocalPkg.Name != "main" {
return
}
- for _, exportn := range exportlist {
+ for _, exportn := range Target.Exports {
s := exportn.Sym()
nn := ir.AsNode(s.Def)
if nn == nil {
base.Ctxt.DwarfIntConst(base.Ctxt.Pkgpath, n.Sym().Name, typesymname(t), ir.IntVal(t, v))
}
-func dumpglobls() {
+func dumpglobls(externs []ir.Node) {
// add globals
- for _, n := range externdcl {
+ for _, n := range externs {
switch n.Op() {
case ir.ONAME:
dumpGlobal(n.(*ir.Name))
dumpGlobalConst(n)
}
}
+}
+func dumpfuncsyms() {
sort.Slice(funcsyms, func(i, j int) bool {
return funcsyms[i].LinksymName() < funcsyms[j].LinksymName()
})
dsymptr(sf, 0, s.Linksym(), 0)
ggloblsym(sf, int32(Widthptr), obj.DUPOK|obj.RODATA)
}
-
- // Do not reprocess funcsyms on next dumpglobls call.
- funcsyms = nil
}
// addGCLocals adds gcargs, gclocals, gcregs, and stack object symbols to Ctxt.Data.
// candidate AND was not inlined (yet), put it onto the compile
// queue instead of compiling it immediately. This is in case we
// wind up inlining it into a method wrapper that is generated by
- // compiling a function later on in the xtop list.
+ // compiling a function later on in the Target.Decls list.
if ir.IsMethod(fn) && isInlinableButNotInlined(fn) {
return false
}
escapeFuncs([]*ir.Func{fn}, false)
Curfn = nil
- xtop = append(xtop, fn)
+ Target.Decls = append(Target.Decls, fn)
}
func paramNnames(ft *types.Type) []ir.Node {
typecheckFunc(fn)
typecheckslice(fn.Body().Slice(), ctxStmt)
- xtop = append(xtop, fn)
+ Target.Decls = append(Target.Decls, fn)
call = ir.NewCallExpr(base.Pos, ir.OCALL, fn.Nname, n.List().Slice())
return walkexpr(typecheck(call, ctxStmt), init)
--- /dev/null
+// 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/types"
+
+// A Package holds information about the package being compiled.
+type Package struct {
+ // Imports, listed in source order.
+ // See golang.org/issue/31636.
+ Imports []*types.Pkg
+
+ // Init functions, listed in source order.
+ Inits []*Func
+
+ // Top-level declarations.
+ Decls []Node
+
+ // Extern (package global) declarations.
+ Externs []Node
+
+ // Assembly function declarations.
+ Asms []*Name
+
+ // Cgo directives.
+ CgoPragmas [][]string
+
+ // Variables with //go:embed lines.
+ Embeds []*Name
+
+ // Exported (or re-exported) symbols.
+ Exports []*Name
+}