go/src/cmd/compile/internal/ir/func.go

620 lines
21 KiB
Go
Raw Normal View History

// 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/obj"
"cmd/internal/objabi"
"cmd/internal/src"
[dev.typeparams] cmd/compile: refactor closure construction typecheck.tcClosure is complicated with many code flows because all of its callers setup the closure funcs in slightly different ways. E.g., it's non-obvious who's responsible for setting the underlying func's Sym or adding it to target.Decls, or how to write new code that constructs a closure without interfering with existing code. This CL refactors everything to use three common functions in package ir: NewClosureFunc (which handle creating the Func, Name, and ClosureExpr and wiring them together), NameClosure (which generates and assigns its unique Sym), and UseClosure (which handles adding the Func to target.Decls). Most IR builders can actually name the closure right away, but the legacy noder+typecheck path may not yet know the name of the enclosing function. In particular, for methods declared with aliased receiver parameters, we need to wait until after typechecking top-level declarations to know the method's true name. So they're left anonymous until typecheck. UseClosure does relatively little work today, but it serves as a useful spot to check that the code setting up closures got it right. It may also eventually serve as an optimization point for early lifting of trivial closures, which may or may not ultimately be beneficial. Change-Id: I7da1e93c70d268f575b12d6aaeb2336eb910a6f1 Reviewed-on: https://go-review.googlesource.com/c/go/+/327051 Trust: Matthew Dempsky <mdempsky@google.com> Run-TryBot: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
2021-06-11 03:09:26 -07:00
"fmt"
"strings"
"unicode/utf8"
)
// A Func corresponds to a single function in a Go program
// (and vice versa: each function is denoted by exactly one *Func).
//
// There are multiple nodes that represent a Func in the IR.
//
// The ONAME node (Func.Nname) is used for plain references to it.
// The ODCLFUNC node (the Func itself) is used for its declaration code.
// The OCLOSURE node (Func.OClosure) is used for a reference to a
// function literal.
//
// An imported function will have an ONAME node which points to a Func
// with an empty body.
// A declared function or method has an ODCLFUNC (the Func itself) and an ONAME.
// 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 f.Sym
// will be the qualified method name (e.g., "T.m").
//
// A method expression (T.M) is represented as an OMETHEXPR node,
// in which n.Left and n.Right point to the type and method, respectively.
// Each distinct mention of a method expression in the source code
// constructs a fresh node.
//
// A method value (t.M) is represented by ODOTMETH/ODOTINTER
// when it is called directly and by OMETHVALUE otherwise.
// These are like method expressions, except that for ODOTMETH/ODOTINTER,
// the method name is stored in Sym instead of Right.
// Each OMETHVALUE ends up being implemented as a new
// function, a bit like a closure, with its own ODCLFUNC.
// The OMETHVALUE uses n.Func to record the linkage to
// the generated ODCLFUNC, but there is no
// pointer from the Func back to the OMETHVALUE.
type Func struct {
miniNode
[dev.regabi] cmd/compile: remove Left, Right etc methods [generated] Now that the generic graph structure methods - Left, Right, and so on - have been removed from the Node interface, each implementation's uses can be replaced with direct field access, using more specific names, and the methods themselves can be deleted. Passes buildall w/ toolstash -cmp. [git-generate] cd src/cmd/compile/internal/ir rf ' mv Func.iota Func.Iota_ mv Name.fn Name.Func_ ' cd ../gc rf ' ex . ../ir { import "cmd/compile/internal/ir" import "cmd/compile/internal/types" var ns ir.Nodes var b bool var i64 int64 var n ir.Node var op ir.Op var sym *types.Sym var class ir.Class var decl *ir.Decl decl.Left() -> decl.X decl.SetLeft(n) -> decl.X = n var asl *ir.AssignListStmt asl.List() -> asl.Lhs asl.PtrList() -> &asl.Lhs asl.SetList(ns) -> asl.Lhs = ns asl.Rlist() -> asl.Rhs asl.PtrRlist() -> &asl.Rhs asl.SetRlist(ns) -> asl.Rhs = ns asl.Colas() -> asl.Def asl.SetColas(b) -> asl.Def = b var as *ir.AssignStmt as.Left() -> as.X as.SetLeft(n) -> as.X = n as.Right() -> as.Y as.SetRight(n) -> as.Y = n as.Colas() -> as.Def as.SetColas(b) -> as.Def = b var ao *ir.AssignOpStmt ao.Left() -> ao.X ao.SetLeft(n) -> ao.X = n ao.Right() -> ao.Y ao.SetRight(n) -> ao.Y = n ao.SubOp() -> ao.AsOp ao.SetSubOp(op) -> ao.AsOp = op ao.Implicit() -> ao.IncDec ao.SetImplicit(b) -> ao.IncDec = b var bl *ir.BlockStmt bl.List() -> bl.List_ bl.PtrList() -> &bl.List_ bl.SetList(ns) -> bl.List_ = ns var br *ir.BranchStmt br.Sym() -> br.Label br.SetSym(sym) -> br.Label = sym var cas *ir.CaseStmt cas.List() -> cas.List_ cas.PtrList() -> &cas.List_ cas.SetList(ns) -> cas.List_ = ns cas.Body() -> cas.Body_ cas.PtrBody() -> &cas.Body_ cas.SetBody(ns) -> cas.Body_ = ns cas.Rlist() -> cas.Vars cas.PtrRlist() -> &cas.Vars cas.SetRlist(ns) -> cas.Vars = ns cas.Left() -> cas.Comm cas.SetLeft(n) -> cas.Comm = n var fr *ir.ForStmt fr.Sym() -> fr.Label fr.SetSym(sym) -> fr.Label = sym fr.Left() -> fr.Cond fr.SetLeft(n) -> fr.Cond = n fr.Right() -> fr.Post fr.SetRight(n) -> fr.Post = n fr.Body() -> fr.Body_ fr.PtrBody() -> &fr.Body_ fr.SetBody(ns) -> fr.Body_ = ns fr.List() -> fr.Late fr.PtrList() -> &fr.Late fr.SetList(ns) -> fr.Late = ns fr.HasBreak() -> fr.HasBreak_ fr.SetHasBreak(b) -> fr.HasBreak_ = b var gs *ir.GoDeferStmt gs.Left() -> gs.Call gs.SetLeft(n) -> gs.Call = n var ifs *ir.IfStmt ifs.Left() -> ifs.Cond ifs.SetLeft(n) -> ifs.Cond = n ifs.Body() -> ifs.Body_ ifs.PtrBody() -> &ifs.Body_ ifs.SetBody(ns) -> ifs.Body_ = ns ifs.Rlist() -> ifs.Else ifs.PtrRlist() -> &ifs.Else ifs.SetRlist(ns) -> ifs.Else = ns ifs.Likely() -> ifs.Likely_ ifs.SetLikely(b) -> ifs.Likely_ = b var im *ir.InlineMarkStmt im.Offset() -> im.Index im.SetOffset(i64) -> im.Index = i64 var lab *ir.LabelStmt lab.Sym() -> lab.Label lab.SetSym(sym) -> lab.Label = sym var rng *ir.RangeStmt rng.Sym() -> rng.Label rng.SetSym(sym) -> rng.Label = sym rng.Right() -> rng.X rng.SetRight(n) -> rng.X = n rng.Body() -> rng.Body_ rng.PtrBody() -> &rng.Body_ rng.SetBody(ns) -> rng.Body_ = ns rng.List() -> rng.Vars rng.PtrList() -> &rng.Vars rng.SetList(ns) -> rng.Vars = ns rng.HasBreak() -> rng.HasBreak_ rng.SetHasBreak(b) -> rng.HasBreak_ = b rng.Colas() -> rng.Def rng.SetColas(b) -> rng.Def = b var ret *ir.ReturnStmt ret.List() -> ret.Results ret.PtrList() -> &ret.Results ret.SetList(ns) -> ret.Results = ns var sel *ir.SelectStmt sel.List() -> sel.Cases sel.PtrList() -> &sel.Cases sel.SetList(ns) -> sel.Cases = ns sel.Sym() -> sel.Label sel.SetSym(sym) -> sel.Label = sym sel.HasBreak() -> sel.HasBreak_ sel.SetHasBreak(b) -> sel.HasBreak_ = b sel.Body() -> sel.Compiled sel.PtrBody() -> &sel.Compiled sel.SetBody(ns) -> sel.Compiled = ns var send *ir.SendStmt send.Left() -> send.Chan send.SetLeft(n) -> send.Chan = n send.Right() -> send.Value send.SetRight(n) -> send.Value = n var sw *ir.SwitchStmt sw.Left() -> sw.Tag sw.SetLeft(n) -> sw.Tag = n sw.List() -> sw.Cases sw.PtrList() -> &sw.Cases sw.SetList(ns) -> sw.Cases = ns sw.Body() -> sw.Compiled sw.PtrBody() -> &sw.Compiled sw.SetBody(ns) -> sw.Compiled = ns sw.Sym() -> sw.Label sw.SetSym(sym) -> sw.Label = sym sw.HasBreak() -> sw.HasBreak_ sw.SetHasBreak(b) -> sw.HasBreak_ = b var tg *ir.TypeSwitchGuard tg.Left() -> tg.Tag tg.SetLeft(nil) -> tg.Tag = nil tg.SetLeft(n) -> tg.Tag = n.(*ir.Ident) tg.Right() -> tg.X tg.SetRight(n) -> tg.X = n var adds *ir.AddStringExpr adds.List() -> adds.List_ adds.PtrList() -> &adds.List_ adds.SetList(ns) -> adds.List_ = ns var addr *ir.AddrExpr addr.Left() -> addr.X addr.SetLeft(n) -> addr.X = n addr.Right() -> addr.Alloc addr.SetRight(n) -> addr.Alloc = n var bin *ir.BinaryExpr bin.Left() -> bin.X bin.SetLeft(n) -> bin.X = n bin.Right() -> bin.Y bin.SetRight(n) -> bin.Y = n var log *ir.LogicalExpr log.Left() -> log.X log.SetLeft(n) -> log.X = n log.Right() -> log.Y log.SetRight(n) -> log.Y = n var call *ir.CallExpr call.Left() -> call.X call.SetLeft(n) -> call.X = n call.List() -> call.Args call.PtrList() -> &call.Args call.SetList(ns) -> call.Args = ns call.Rlist() -> call.Rargs call.PtrRlist() -> &call.Rargs call.SetRlist(ns) -> call.Rargs = ns call.IsDDD() -> call.DDD call.SetIsDDD(b) -> call.DDD = b call.NoInline() -> call.NoInline_ call.SetNoInline(b) -> call.NoInline_ = b call.Body() -> call.Body_ call.PtrBody() -> &call.Body_ call.SetBody(ns) -> call.Body_ = ns var cp *ir.CallPartExpr cp.Func() -> cp.Func_ cp.Left() -> cp.X cp.SetLeft(n) -> cp.X = n cp.Sym() -> cp.Method.Sym var clo *ir.ClosureExpr clo.Func() -> clo.Func_ var cr *ir.ClosureReadExpr cr.Offset() -> cr.Offset_ var cl *ir.CompLitExpr cl.Right() -> cl.Ntype cl.SetRight(nil) -> cl.Ntype = nil cl.SetRight(n) -> cl.Ntype = ir.Node(n).(ir.Ntype) cl.List() -> cl.List_ cl.PtrList() -> &cl.List_ cl.SetList(ns) -> cl.List_ = ns var conv *ir.ConvExpr conv.Left() -> conv.X conv.SetLeft(n) -> conv.X = n var ix *ir.IndexExpr ix.Left() -> ix.X ix.SetLeft(n) -> ix.X = n ix.Right() -> ix.Index ix.SetRight(n) -> ix.Index = n ix.IndexMapLValue() -> ix.Assigned ix.SetIndexMapLValue(b) -> ix.Assigned = b var kv *ir.KeyExpr kv.Left() -> kv.Key kv.SetLeft(n) -> kv.Key = n kv.Right() -> kv.Value kv.SetRight(n) -> kv.Value = n var sk *ir.StructKeyExpr sk.Sym() -> sk.Field sk.SetSym(sym) -> sk.Field = sym sk.Left() -> sk.Value sk.SetLeft(n) -> sk.Value = n sk.Offset() -> sk.Offset_ sk.SetOffset(i64) -> sk.Offset_ = i64 var ic *ir.InlinedCallExpr ic.Body() -> ic.Body_ ic.PtrBody() -> &ic.Body_ ic.SetBody(ns) -> ic.Body_ = ns ic.Rlist() -> ic.ReturnVars ic.PtrRlist() -> &ic.ReturnVars ic.SetRlist(ns) -> ic.ReturnVars = ns var mak *ir.MakeExpr mak.Left() -> mak.Len mak.SetLeft(n) -> mak.Len = n mak.Right() -> mak.Cap mak.SetRight(n) -> mak.Cap = n var par *ir.ParenExpr par.Left() -> par.X par.SetLeft(n) -> par.X = n var res *ir.ResultExpr res.Offset() -> res.Offset_ res.SetOffset(i64) -> res.Offset_ = i64 var dot *ir.SelectorExpr dot.Left() -> dot.X dot.SetLeft(n) -> dot.X = n dot.Sym() -> dot.Sel dot.SetSym(sym) -> dot.Sel = sym dot.Offset() -> dot.Offset_ dot.SetOffset(i64) -> dot.Offset_ = i64 var sl *ir.SliceExpr sl.Left() -> sl.X sl.SetLeft(n) -> sl.X = n sl.List() -> sl.List_ sl.PtrList() -> &sl.List_ sl.SetList(ns) -> sl.List_ = ns var sh *ir.SliceHeaderExpr sh.Left() -> sh.Ptr sh.SetLeft(n) -> sh.Ptr = n sh.List() -> sh.LenCap_ sh.PtrList() -> &sh.LenCap_ sh.SetList(ns) -> sh.LenCap_ = ns var st *ir.StarExpr st.Left() -> st.X st.SetLeft(n) -> st.X = n var ta *ir.TypeAssertExpr ta.Left() -> ta.X ta.SetLeft(n) -> ta.X = n ta.Right() -> ta.Ntype ta.SetRight(n) -> ta.Ntype = n ta.List() -> ta.Itab ta.PtrList() -> &ta.Itab ta.SetList(ns) -> ta.Itab = ns var u *ir.UnaryExpr u.Left() -> u.X u.SetLeft(n) -> u.X = n var fn *ir.Func fn.Body() -> fn.Body_ fn.PtrBody() -> &fn.Body_ fn.SetBody(ns) -> fn.Body_ = ns fn.Iota() -> fn.Iota_ fn.SetIota(i64) -> fn.Iota_ = i64 fn.Func() -> fn var nam *ir.Name nam.SubOp() -> nam.BuiltinOp nam.SetSubOp(op) -> nam.BuiltinOp = op nam.Class() -> nam.Class_ nam.SetClass(class) -> nam.Class_ = class nam.Func() -> nam.Func_ nam.Offset() -> nam.Offset_ nam.SetOffset(i64) -> nam.Offset_ = i64 } ex . ../ir { import "cmd/compile/internal/ir" var n ir.Nodes (&n).Append -> n.Append (&n).AppendNodes -> n.AppendNodes (&n).MoveNodes -> n.MoveNodes (&n).Prepend -> n.Prepend (&n).Set -> n.Set (&n).Set1 -> n.Set1 (&n).Set2 -> n.Set2 (&n).Set3 -> n.Set3 var ntype ir.Ntype ir.Node(ntype).(ir.Ntype) -> ntype } ' cd ../ir rf ' rm \ Decl.Left Decl.SetLeft \ AssignListStmt.List AssignListStmt.PtrList AssignListStmt.SetList \ AssignListStmt.Rlist AssignListStmt.PtrRlist AssignListStmt.SetRlist \ AssignListStmt.Colas AssignListStmt.SetColas \ AssignStmt.Left AssignStmt.SetLeft \ AssignStmt.Right AssignStmt.SetRight \ AssignStmt.Colas AssignStmt.SetColas \ AssignOpStmt.Left AssignOpStmt.SetLeft \ AssignOpStmt.Right AssignOpStmt.SetRight \ AssignOpStmt.SubOp AssignOpStmt.SetSubOp \ AssignOpStmt.Implicit AssignOpStmt.SetImplicit \ BlockStmt.List BlockStmt.PtrList BlockStmt.SetList \ BranchStmt.SetSym \ CaseStmt.List CaseStmt.PtrList CaseStmt.SetList \ CaseStmt.Body CaseStmt.PtrBody CaseStmt.SetBody \ CaseStmt.Rlist CaseStmt.PtrRlist CaseStmt.SetRlist \ CaseStmt.Left CaseStmt.SetLeft \ ForStmt.Left ForStmt.SetLeft \ ForStmt.Right ForStmt.SetRight \ ForStmt.Body ForStmt.PtrBody ForStmt.SetBody \ ForStmt.List ForStmt.PtrList ForStmt.SetList \ ForStmt.HasBreak ForStmt.SetHasBreak \ ForStmt.Sym ForStmt.SetSym \ GoDeferStmt.Left GoDeferStmt.SetLeft \ IfStmt.Left IfStmt.SetLeft \ IfStmt.Body IfStmt.PtrBody IfStmt.SetBody \ IfStmt.Rlist IfStmt.PtrRlist IfStmt.SetRlist \ IfStmt.Likely IfStmt.SetLikely \ LabelStmt.SetSym \ RangeStmt.Right RangeStmt.SetRight \ RangeStmt.Body RangeStmt.PtrBody RangeStmt.SetBody \ RangeStmt.List RangeStmt.PtrList RangeStmt.SetList \ RangeStmt.HasBreak RangeStmt.SetHasBreak \ RangeStmt.Colas RangeStmt.SetColas \ RangeStmt.Sym RangeStmt.SetSym \ ReturnStmt.List ReturnStmt.PtrList ReturnStmt.SetList \ SelectStmt.List SelectStmt.PtrList SelectStmt.SetList \ SelectStmt.HasBreak SelectStmt.SetHasBreak \ SelectStmt.Body SelectStmt.PtrBody SelectStmt.SetBody \ SelectStmt.Sym SelectStmt.SetSym \ SendStmt.Left SendStmt.SetLeft \ SendStmt.Right SendStmt.SetRight \ SwitchStmt.Left SwitchStmt.SetLeft \ SwitchStmt.List SwitchStmt.PtrList SwitchStmt.SetList \ SwitchStmt.Body SwitchStmt.PtrBody SwitchStmt.SetBody \ SwitchStmt.HasBreak SwitchStmt.SetHasBreak \ SwitchStmt.Sym SwitchStmt.SetSym \ TypeSwitchGuard.Left TypeSwitchGuard.SetLeft \ TypeSwitchGuard.Right TypeSwitchGuard.SetRight \ AddStringExpr.List AddStringExpr.PtrList AddStringExpr.SetList \ AddrExpr.Left AddrExpr.SetLeft \ AddrExpr.Right AddrExpr.SetRight \ BinaryExpr.Left BinaryExpr.SetLeft \ BinaryExpr.Right BinaryExpr.SetRight \ LogicalExpr.Left LogicalExpr.SetLeft \ LogicalExpr.Right LogicalExpr.SetRight \ CallExpr.Left CallExpr.SetLeft \ CallExpr.List CallExpr.PtrList CallExpr.SetList \ CallExpr.Rlist CallExpr.PtrRlist CallExpr.SetRlist \ CallExpr.NoInline CallExpr.SetNoInline \ CallExpr.Body CallExpr.PtrBody CallExpr.SetBody \ CallExpr.IsDDD CallExpr.SetIsDDD \ CallPartExpr.Left CallPartExpr.SetLeft \ ClosureReadExpr.Offset \ ClosureReadExpr.Type \ # provided by miniExpr already CompLitExpr.Right CompLitExpr.SetRight \ CompLitExpr.List CompLitExpr.PtrList CompLitExpr.SetList \ ConvExpr.Left ConvExpr.SetLeft \ IndexExpr.Left IndexExpr.SetLeft \ IndexExpr.Right IndexExpr.SetRight \ IndexExpr.IndexMapLValue IndexExpr.SetIndexMapLValue \ KeyExpr.Left KeyExpr.SetLeft \ KeyExpr.Right KeyExpr.SetRight \ StructKeyExpr.Left StructKeyExpr.SetLeft \ StructKeyExpr.Offset StructKeyExpr.SetOffset \ StructKeyExpr.SetSym \ InlinedCallExpr.Body InlinedCallExpr.PtrBody InlinedCallExpr.SetBody \ InlinedCallExpr.Rlist InlinedCallExpr.PtrRlist InlinedCallExpr.SetRlist \ MakeExpr.Left MakeExpr.SetLeft \ MakeExpr.Right MakeExpr.SetRight \ MethodExpr.Left MethodExpr.SetLeft \ MethodExpr.Right MethodExpr.SetRight \ MethodExpr.Offset MethodExpr.SetOffset \ MethodExpr.Class MethodExpr.SetClass \ ParenExpr.Left ParenExpr.SetLeft \ ResultExpr.Offset ResultExpr.SetOffset \ ReturnStmt.IsDDD \ SelectorExpr.Left SelectorExpr.SetLeft \ SelectorExpr.Offset SelectorExpr.SetOffset \ SelectorExpr.SetSym \ SliceExpr.Left SliceExpr.SetLeft \ SliceExpr.List SliceExpr.PtrList SliceExpr.SetList \ SliceHeaderExpr.Left SliceHeaderExpr.SetLeft \ SliceHeaderExpr.List SliceHeaderExpr.PtrList SliceHeaderExpr.SetList \ StarExpr.Left StarExpr.SetLeft \ TypeAssertExpr.Left TypeAssertExpr.SetLeft \ TypeAssertExpr.Right TypeAssertExpr.SetRight \ TypeAssertExpr.List TypeAssertExpr.PtrList TypeAssertExpr.SetList \ UnaryExpr.Left UnaryExpr.SetLeft \ Func.Body Func.PtrBody Func.SetBody \ Func.Iota Func.SetIota \ CallPartExpr.Func ClosureExpr.Func Func.Func Name.Func \ mv BlockStmt.List_ BlockStmt.List mv CaseStmt.List_ CaseStmt.List mv CaseStmt.Body_ CaseStmt.Body mv ForStmt.Body_ ForStmt.Body mv ForStmt.HasBreak_ ForStmt.HasBreak mv Func.Iota_ Func.Iota mv IfStmt.Body_ IfStmt.Body mv IfStmt.Likely_ IfStmt.Likely mv RangeStmt.Body_ RangeStmt.Body mv RangeStmt.HasBreak_ RangeStmt.HasBreak mv SelectStmt.HasBreak_ SelectStmt.HasBreak mv SwitchStmt.HasBreak_ SwitchStmt.HasBreak mv AddStringExpr.List_ AddStringExpr.List mv CallExpr.NoInline_ CallExpr.NoInline mv CallExpr.Body_ CallExpr.Body # TODO what is this? mv CallExpr.DDD CallExpr.IsDDD mv ClosureReadExpr.Offset_ ClosureReadExpr.Offset mv CompLitExpr.List_ CompLitExpr.List mv StructKeyExpr.Offset_ StructKeyExpr.Offset mv InlinedCallExpr.Body_ InlinedCallExpr.Body mv ResultExpr.Offset_ ResultExpr.Offset mv SelectorExpr.Offset_ SelectorExpr.Offset mv SliceExpr.List_ SliceExpr.List mv SliceHeaderExpr.LenCap_ SliceHeaderExpr.LenCap mv Func.Body_ Func.Body mv CallPartExpr.Func_ CallPartExpr.Func mv ClosureExpr.Func_ ClosureExpr.Func mv Name.Func_ Name.Func ' Change-Id: Ia2ee59649674f83eb123e63fda7a7781cf91cc56 Reviewed-on: https://go-review.googlesource.com/c/go/+/277935 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>
2020-12-23 00:02:08 -05:00
Body Nodes
Nname *Name // ONAME node
OClosure *ClosureExpr // OCLOSURE node
// ONAME nodes for all params/locals for this func/closure, does NOT
// include closurevars until transforming closures during walk.
// Names must be listed PPARAMs, PPARAMOUTs, then PAUTOs,
// with PPARAMs and PPARAMOUTs in order corresponding to the function signature.
// Anonymous and blank params are declared as ~pNN (for PPARAMs) and ~rNN (for PPARAMOUTs).
Dcl []*Name
// ClosureVars lists the free variables that are used within a
// function literal, but formally declared in an enclosing
// function. The variables in this slice are the closure function's
// own copy of the variables, which are used within its function
// body. They will also each have IsClosureVar set, and will have
// Byval set if they're captured by value.
ClosureVars []*Name
// Enclosed functions that need to be compiled.
// Populated during walk.
Closures []*Func
// 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].
Parents []ScopeID
// Marks records scope boundary changes.
Marks []Mark
FieldTrack map[*obj.LSym]struct{}
DebugInfo interface{}
cmd/compile: restructure ABI wrapper generation, export ABI This CL restructures how we track function ABIs and generate ABI wrappers in the compiler and adds import/export of ABIs across package boundaries. Currently, we start by tracking definition and referencing ABIs in two global maps and eventually move some of this information into the LSyms for functions. This complicates a lot of the existing code for handling wrappers and makes it particularly hard to export ABI information across packages. This change is built around instead recording this information on the ir.Func. First, this change replaces the global ABI def/ref maps with a type, which makes the data flow and lifetime of this information clear in gc.Main. These are populated during flag parsing. Then, early in the front-end, we loop over all ir.Funcs to 1. attach ABI def/ref information to the ir.Funcs and 2. create new ir.Funcs for ABI wrappers. Step 1 is slightly subtle because the information is keyed by linker symbol names, so we can't simply look things up in the compiler's regular symbol table. By generating ABI wrappers early in the front-end, we decouple this step from LSym creation, which makes LSym creation much simpler (like it was before ABI wrappers). In particular, LSyms for wrappers are now created at the same time as all other functions instead of by makeABIWrapper, which means we're back to the simpler, old situation where InitLSym was the only thing responsible for constructing function LSyms. Hence, we can restore the check that InitLSym is called exactly once per function. Attaching the ABI information to the ir.Func has several follow-on benefits: 1. It's now easy to include in the export info. This enables direct cross-package cross-ABI calls, which are important for the performance of calling various hot assembly functions (e.g., internal/bytealg.*). This was really the point of this whole change. 2. Since all Funcs, including wrappers, now record their definition ABI, callTargetLSym no longer needs to distinguish wrappers from non-wrappers, so it's now nearly trivial (it would be completely trivial except that it has to work around a handful of cases where ir.Name.Func is nil). The simplification of callTargetLSym has one desirable but potentially surprising side-effect: the compiler will now generate direct calls to the definition ABI even when ABI wrappers are turned off. This is almost completely unnoticeable except that cmd/internal/obj/wasm looks for the call from runtime.deferreturn (defined in Go) to runtime.jmpdefer (defined in assembly) to compile is specially. That now looks like a direct call to ABI0 rather than going through the ABIInternal alias. While we're in here, we also set up the structures to support more than just ABI0 and ABIInternal and add various additional consistency checks all around. Performance-wise, this reduces the overhead induced by wrappers from 1.24% geomean (on Sweet) to 0.52% geomean, and reduces the number of benchmarks impacts >2% from 5 to 3. It has no impact on compiler speed. Impact of wrappers before this change: name old time/op new time/op delta BiogoIgor 15.8s ± 2% 15.8s ± 1% ~ (p=0.863 n=25+25) BiogoKrishna 18.3s ± 6% 18.1s ± 7% -1.39% (p=0.015 n=25+25) BleveIndexBatch100 5.88s ± 3% 6.04s ± 6% +2.72% (p=0.000 n=25+25) BleveQuery 6.42s ± 1% 6.76s ± 1% +5.31% (p=0.000 n=24+24) CompileTemplate 245ms ± 3% 250ms ± 6% ~ (p=0.068 n=22+25) CompileUnicode 93.6ms ± 2% 93.9ms ± 5% ~ (p=0.958 n=22+25) CompileGoTypes 1.60s ± 2% 1.59s ± 2% ~ (p=0.115 n=24+24) CompileCompiler 104ms ± 4% 104ms ± 3% ~ (p=0.453 n=22+25) CompileSSA 11.0s ± 2% 11.0s ± 1% ~ (p=0.789 n=24+25) CompileFlate 153ms ± 2% 153ms ± 1% ~ (p=0.055 n=21+20) CompileGoParser 229ms ± 2% 230ms ± 2% ~ (p=0.305 n=21+22) CompileReflect 585ms ± 5% 582ms ± 3% ~ (p=0.365 n=25+25) CompileTar 211ms ± 1% 211ms ± 3% ~ (p=0.592 n=20+22) CompileXML 282ms ± 3% 281ms ± 2% ~ (p=0.937 n=22+23) CompileStdCmd 13.7s ± 3% 13.6s ± 2% ~ (p=0.700 n=25+25) FoglemanFauxGLRenderRotateBoat 8.67s ± 1% 8.78s ± 1% +1.30% (p=0.000 n=25+25) FoglemanPathTraceRenderGopherIter1 20.5s ± 2% 20.9s ± 2% +1.85% (p=0.000 n=25+25) GopherLuaKNucleotide 30.1s ± 2% 31.1s ± 2% +3.38% (p=0.000 n=25+25) MarkdownRenderXHTML 246ms ± 5% 250ms ± 1% +1.42% (p=0.002 n=25+23) Tile38WithinCircle100kmRequest 828µs ± 6% 885µs ± 6% +6.85% (p=0.000 n=23+25) Tile38IntersectsCircle100kmRequest 1.04ms ± 5% 1.10ms ± 7% +5.63% (p=0.000 n=25+25) Tile38KNearestLimit100Request 974µs ± 4% 972µs ± 4% ~ (p=0.356 n=25+24) [Geo mean] 588ms 595ms +1.24% (https://perf.golang.org/search?q=upload:20210328.5) And after this change: name old time/op new time/op delta BiogoIgor 15.9s ± 1% 15.8s ± 1% -0.48% (p=0.008 n=22+25) BiogoKrishna 18.4s ± 6% 17.8s ± 6% -3.55% (p=0.008 n=25+25) BleveIndexBatch100 5.86s ± 3% 5.97s ± 4% +1.88% (p=0.001 n=25+25) BleveQuery 6.42s ± 1% 6.75s ± 1% +5.14% (p=0.000 n=25+25) CompileTemplate 246ms ± 5% 245ms ± 2% ~ (p=0.472 n=23+23) CompileUnicode 93.7ms ± 3% 93.5ms ± 2% ~ (p=0.813 n=22+23) CompileGoTypes 1.60s ± 2% 1.60s ± 2% ~ (p=0.108 n=25+23) CompileCompiler 104ms ± 3% 104ms ± 2% ~ (p=0.845 n=23+23) CompileSSA 11.0s ± 2% 11.0s ± 2% ~ (p=0.525 n=25+25) CompileFlate 152ms ± 1% 153ms ± 2% ~ (p=0.408 n=22+22) CompileGoParser 230ms ± 1% 230ms ± 1% ~ (p=0.363 n=21+23) CompileReflect 582ms ± 3% 584ms ± 4% ~ (p=0.658 n=25+25) CompileTar 212ms ± 2% 211ms ± 2% ~ (p=0.315 n=23+24) CompileXML 282ms ± 1% 282ms ± 1% ~ (p=0.991 n=23+22) CompileStdCmd 13.6s ± 2% 13.6s ± 2% ~ (p=0.699 n=25+24) FoglemanFauxGLRenderRotateBoat 8.66s ± 1% 8.69s ± 1% +0.28% (p=0.002 n=25+24) FoglemanPathTraceRenderGopherIter1 20.5s ± 3% 20.5s ± 2% ~ (p=0.407 n=25+25) GopherLuaKNucleotide 30.1s ± 2% 31.2s ± 2% +3.82% (p=0.000 n=25+25) MarkdownRenderXHTML 246ms ± 3% 245ms ± 1% ~ (p=0.478 n=23+22) Tile38WithinCircle100kmRequest 820µs ± 4% 856µs ± 5% +4.39% (p=0.000 n=24+25) Tile38IntersectsCircle100kmRequest 1.05ms ± 6% 1.07ms ± 6% +1.91% (p=0.014 n=25+25) Tile38KNearestLimit100Request 970µs ± 4% 970µs ± 3% ~ (p=0.819 n=22+24) [Geo mean] 588ms 591ms +0.52% (https://perf.golang.org/search?q=upload:20210328.6) For #40724. Change-Id: I1c374e32d4bbc88efed062a1b360017d3642140d Reviewed-on: https://go-review.googlesource.com/c/go/+/305274 Trust: Austin Clements <austin@google.com> Run-TryBot: Austin Clements <austin@google.com> Reviewed-by: Cherry Zhang <cherryyz@google.com> TryBot-Result: Go Bot <gobot@golang.org>
2021-03-25 19:50:08 -04:00
LSym *obj.LSym // Linker object in this function's native ABI (Func.ABI)
Inl *Inline
cmd/compile: for rangefunc, add checks and tests, fix panic interactions Modify rangefunc #next protocol to make it more robust Extra-terrible nests of rangefunc iterators caused the prior implementation to misbehave non-locally (in outer loops). Add more rangefunc exit flag tests, parallel and tricky This tests the assertion that a rangefunc iterator running in parallel can trigger the race detector if any of the parallel goroutines attempts an early exit. It also verifies that if everything else is carefully written, that it does NOT trigger the race detector if all the parts run time completion. Another test tries to rerun a yield function within a loop, so that any per-line shared checking would be fooled. Added all the use-of-body/yield-function checking. These checks handle pathological cases that would cause rangefunc for loops to behave in surprising ways (compared to "regular" for loops). For example, a rangefunc iterator might defer-recover a panic thrown in the syntactic body of a loop; this notices the fault and panics with an explanation Modified closure naming to ID rangefunc bodies Add a "-range<N>" suffix to the name of any closure generated for a rangefunc loop body, as provided in Alessandro Arzilli's CL (which is merged into this one). Fix return values for panicky range functions This removes the delayed implementation of "return x" by ensuring that return values (in rangefunc-return-containing functions) always have names and translating the "return x" into "#rv1 = x" where #rv1 is the synthesized name of the first result. Updates #61405. Change-Id: I933299ecce04ceabcf1c0c2de8e610b2ecd1cfd8 Reviewed-on: https://go-review.googlesource.com/c/go/+/584596 Reviewed-by: Matthew Dempsky <mdempsky@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Tim King <taking@google.com>
2024-01-26 17:49:33 -05:00
// RangeParent, if non-nil, is the first non-range body function containing
// the closure for the body of a range function.
RangeParent *Func
// funcLitGen, rangeLitGen and goDeferGen track how many closures have been
// created in this function for function literals, range-over-func loops,
// and go/defer wrappers, respectively. Used by closureName for creating
// unique function names.
// Tracking goDeferGen separately avoids wrappers throwing off
// function literal numbering (e.g., runtime/trace_test.TestTraceSymbolize.func11).
cmd/compile: for rangefunc, add checks and tests, fix panic interactions Modify rangefunc #next protocol to make it more robust Extra-terrible nests of rangefunc iterators caused the prior implementation to misbehave non-locally (in outer loops). Add more rangefunc exit flag tests, parallel and tricky This tests the assertion that a rangefunc iterator running in parallel can trigger the race detector if any of the parallel goroutines attempts an early exit. It also verifies that if everything else is carefully written, that it does NOT trigger the race detector if all the parts run time completion. Another test tries to rerun a yield function within a loop, so that any per-line shared checking would be fooled. Added all the use-of-body/yield-function checking. These checks handle pathological cases that would cause rangefunc for loops to behave in surprising ways (compared to "regular" for loops). For example, a rangefunc iterator might defer-recover a panic thrown in the syntactic body of a loop; this notices the fault and panics with an explanation Modified closure naming to ID rangefunc bodies Add a "-range<N>" suffix to the name of any closure generated for a rangefunc loop body, as provided in Alessandro Arzilli's CL (which is merged into this one). Fix return values for panicky range functions This removes the delayed implementation of "return x" by ensuring that return values (in rangefunc-return-containing functions) always have names and translating the "return x" into "#rv1 = x" where #rv1 is the synthesized name of the first result. Updates #61405. Change-Id: I933299ecce04ceabcf1c0c2de8e610b2ecd1cfd8 Reviewed-on: https://go-review.googlesource.com/c/go/+/584596 Reviewed-by: Matthew Dempsky <mdempsky@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Tim King <taking@google.com>
2024-01-26 17:49:33 -05:00
funcLitGen int32
rangeLitGen int32
goDeferGen int32
Label int32 // largest auto-generated label in this function
Endlineno src.XPos
WBPos src.XPos // position of first write barrier; see SetWBPos
Pragma PragmaFlag // go:xxx function annotations
cmd/compile: restructure ABI wrapper generation, export ABI This CL restructures how we track function ABIs and generate ABI wrappers in the compiler and adds import/export of ABIs across package boundaries. Currently, we start by tracking definition and referencing ABIs in two global maps and eventually move some of this information into the LSyms for functions. This complicates a lot of the existing code for handling wrappers and makes it particularly hard to export ABI information across packages. This change is built around instead recording this information on the ir.Func. First, this change replaces the global ABI def/ref maps with a type, which makes the data flow and lifetime of this information clear in gc.Main. These are populated during flag parsing. Then, early in the front-end, we loop over all ir.Funcs to 1. attach ABI def/ref information to the ir.Funcs and 2. create new ir.Funcs for ABI wrappers. Step 1 is slightly subtle because the information is keyed by linker symbol names, so we can't simply look things up in the compiler's regular symbol table. By generating ABI wrappers early in the front-end, we decouple this step from LSym creation, which makes LSym creation much simpler (like it was before ABI wrappers). In particular, LSyms for wrappers are now created at the same time as all other functions instead of by makeABIWrapper, which means we're back to the simpler, old situation where InitLSym was the only thing responsible for constructing function LSyms. Hence, we can restore the check that InitLSym is called exactly once per function. Attaching the ABI information to the ir.Func has several follow-on benefits: 1. It's now easy to include in the export info. This enables direct cross-package cross-ABI calls, which are important for the performance of calling various hot assembly functions (e.g., internal/bytealg.*). This was really the point of this whole change. 2. Since all Funcs, including wrappers, now record their definition ABI, callTargetLSym no longer needs to distinguish wrappers from non-wrappers, so it's now nearly trivial (it would be completely trivial except that it has to work around a handful of cases where ir.Name.Func is nil). The simplification of callTargetLSym has one desirable but potentially surprising side-effect: the compiler will now generate direct calls to the definition ABI even when ABI wrappers are turned off. This is almost completely unnoticeable except that cmd/internal/obj/wasm looks for the call from runtime.deferreturn (defined in Go) to runtime.jmpdefer (defined in assembly) to compile is specially. That now looks like a direct call to ABI0 rather than going through the ABIInternal alias. While we're in here, we also set up the structures to support more than just ABI0 and ABIInternal and add various additional consistency checks all around. Performance-wise, this reduces the overhead induced by wrappers from 1.24% geomean (on Sweet) to 0.52% geomean, and reduces the number of benchmarks impacts >2% from 5 to 3. It has no impact on compiler speed. Impact of wrappers before this change: name old time/op new time/op delta BiogoIgor 15.8s ± 2% 15.8s ± 1% ~ (p=0.863 n=25+25) BiogoKrishna 18.3s ± 6% 18.1s ± 7% -1.39% (p=0.015 n=25+25) BleveIndexBatch100 5.88s ± 3% 6.04s ± 6% +2.72% (p=0.000 n=25+25) BleveQuery 6.42s ± 1% 6.76s ± 1% +5.31% (p=0.000 n=24+24) CompileTemplate 245ms ± 3% 250ms ± 6% ~ (p=0.068 n=22+25) CompileUnicode 93.6ms ± 2% 93.9ms ± 5% ~ (p=0.958 n=22+25) CompileGoTypes 1.60s ± 2% 1.59s ± 2% ~ (p=0.115 n=24+24) CompileCompiler 104ms ± 4% 104ms ± 3% ~ (p=0.453 n=22+25) CompileSSA 11.0s ± 2% 11.0s ± 1% ~ (p=0.789 n=24+25) CompileFlate 153ms ± 2% 153ms ± 1% ~ (p=0.055 n=21+20) CompileGoParser 229ms ± 2% 230ms ± 2% ~ (p=0.305 n=21+22) CompileReflect 585ms ± 5% 582ms ± 3% ~ (p=0.365 n=25+25) CompileTar 211ms ± 1% 211ms ± 3% ~ (p=0.592 n=20+22) CompileXML 282ms ± 3% 281ms ± 2% ~ (p=0.937 n=22+23) CompileStdCmd 13.7s ± 3% 13.6s ± 2% ~ (p=0.700 n=25+25) FoglemanFauxGLRenderRotateBoat 8.67s ± 1% 8.78s ± 1% +1.30% (p=0.000 n=25+25) FoglemanPathTraceRenderGopherIter1 20.5s ± 2% 20.9s ± 2% +1.85% (p=0.000 n=25+25) GopherLuaKNucleotide 30.1s ± 2% 31.1s ± 2% +3.38% (p=0.000 n=25+25) MarkdownRenderXHTML 246ms ± 5% 250ms ± 1% +1.42% (p=0.002 n=25+23) Tile38WithinCircle100kmRequest 828µs ± 6% 885µs ± 6% +6.85% (p=0.000 n=23+25) Tile38IntersectsCircle100kmRequest 1.04ms ± 5% 1.10ms ± 7% +5.63% (p=0.000 n=25+25) Tile38KNearestLimit100Request 974µs ± 4% 972µs ± 4% ~ (p=0.356 n=25+24) [Geo mean] 588ms 595ms +1.24% (https://perf.golang.org/search?q=upload:20210328.5) And after this change: name old time/op new time/op delta BiogoIgor 15.9s ± 1% 15.8s ± 1% -0.48% (p=0.008 n=22+25) BiogoKrishna 18.4s ± 6% 17.8s ± 6% -3.55% (p=0.008 n=25+25) BleveIndexBatch100 5.86s ± 3% 5.97s ± 4% +1.88% (p=0.001 n=25+25) BleveQuery 6.42s ± 1% 6.75s ± 1% +5.14% (p=0.000 n=25+25) CompileTemplate 246ms ± 5% 245ms ± 2% ~ (p=0.472 n=23+23) CompileUnicode 93.7ms ± 3% 93.5ms ± 2% ~ (p=0.813 n=22+23) CompileGoTypes 1.60s ± 2% 1.60s ± 2% ~ (p=0.108 n=25+23) CompileCompiler 104ms ± 3% 104ms ± 2% ~ (p=0.845 n=23+23) CompileSSA 11.0s ± 2% 11.0s ± 2% ~ (p=0.525 n=25+25) CompileFlate 152ms ± 1% 153ms ± 2% ~ (p=0.408 n=22+22) CompileGoParser 230ms ± 1% 230ms ± 1% ~ (p=0.363 n=21+23) CompileReflect 582ms ± 3% 584ms ± 4% ~ (p=0.658 n=25+25) CompileTar 212ms ± 2% 211ms ± 2% ~ (p=0.315 n=23+24) CompileXML 282ms ± 1% 282ms ± 1% ~ (p=0.991 n=23+22) CompileStdCmd 13.6s ± 2% 13.6s ± 2% ~ (p=0.699 n=25+24) FoglemanFauxGLRenderRotateBoat 8.66s ± 1% 8.69s ± 1% +0.28% (p=0.002 n=25+24) FoglemanPathTraceRenderGopherIter1 20.5s ± 3% 20.5s ± 2% ~ (p=0.407 n=25+25) GopherLuaKNucleotide 30.1s ± 2% 31.2s ± 2% +3.82% (p=0.000 n=25+25) MarkdownRenderXHTML 246ms ± 3% 245ms ± 1% ~ (p=0.478 n=23+22) Tile38WithinCircle100kmRequest 820µs ± 4% 856µs ± 5% +4.39% (p=0.000 n=24+25) Tile38IntersectsCircle100kmRequest 1.05ms ± 6% 1.07ms ± 6% +1.91% (p=0.014 n=25+25) Tile38KNearestLimit100Request 970µs ± 4% 970µs ± 3% ~ (p=0.819 n=22+24) [Geo mean] 588ms 591ms +0.52% (https://perf.golang.org/search?q=upload:20210328.6) For #40724. Change-Id: I1c374e32d4bbc88efed062a1b360017d3642140d Reviewed-on: https://go-review.googlesource.com/c/go/+/305274 Trust: Austin Clements <austin@google.com> Run-TryBot: Austin Clements <austin@google.com> Reviewed-by: Cherry Zhang <cherryyz@google.com> TryBot-Result: Go Bot <gobot@golang.org>
2021-03-25 19:50:08 -04:00
flags bitset16
// ABI is a function's "definition" ABI. This is the ABI that
// this function's generated code is expecting to be called by.
//
// For most functions, this will be obj.ABIInternal. It may be
// a different ABI for functions defined in assembly or ABI wrappers.
//
// This is included in the export data and tracked across packages.
ABI obj.ABI
// ABIRefs is the set of ABIs by which this function is referenced.
// For ABIs other than this function's definition ABI, the
// compiler generates ABI wrapper functions. This is only tracked
// within a package.
ABIRefs obj.ABISet
NumDefers int32 // number of defer calls in the function
NumReturns int32 // number of explicit returns in the function
// NWBRCalls records the LSyms of functions called by this
// function for go:nowritebarrierrec analysis. Only filled in
// if nowritebarrierrecCheck != nil.
NWBRCalls *[]SymAndPos
// For wrapper functions, WrappedFunc point to the original Func.
// Currently only used for go/defer wrappers.
WrappedFunc *Func
// WasmImport is used by the //go:wasmimport directive to store info about
// a WebAssembly function import.
WasmImport *WasmImport
}
// WasmImport stores metadata associated with the //go:wasmimport pragma.
type WasmImport struct {
Module string
Name string
}
// NewFunc returns a new Func with the given name and type.
//
// fpos is the position of the "func" token, and npos is the position
// of the name identifier.
//
// TODO(mdempsky): I suspect there's no need for separate fpos and
// npos.
func NewFunc(fpos, npos src.XPos, sym *types.Sym, typ *types.Type) *Func {
name := NewNameAt(npos, sym, typ)
name.Class = PFUNC
sym.SetFunc(true)
fn := &Func{Nname: name}
fn.pos = fpos
fn.op = ODCLFUNC
cmd/compile: restructure ABI wrapper generation, export ABI This CL restructures how we track function ABIs and generate ABI wrappers in the compiler and adds import/export of ABIs across package boundaries. Currently, we start by tracking definition and referencing ABIs in two global maps and eventually move some of this information into the LSyms for functions. This complicates a lot of the existing code for handling wrappers and makes it particularly hard to export ABI information across packages. This change is built around instead recording this information on the ir.Func. First, this change replaces the global ABI def/ref maps with a type, which makes the data flow and lifetime of this information clear in gc.Main. These are populated during flag parsing. Then, early in the front-end, we loop over all ir.Funcs to 1. attach ABI def/ref information to the ir.Funcs and 2. create new ir.Funcs for ABI wrappers. Step 1 is slightly subtle because the information is keyed by linker symbol names, so we can't simply look things up in the compiler's regular symbol table. By generating ABI wrappers early in the front-end, we decouple this step from LSym creation, which makes LSym creation much simpler (like it was before ABI wrappers). In particular, LSyms for wrappers are now created at the same time as all other functions instead of by makeABIWrapper, which means we're back to the simpler, old situation where InitLSym was the only thing responsible for constructing function LSyms. Hence, we can restore the check that InitLSym is called exactly once per function. Attaching the ABI information to the ir.Func has several follow-on benefits: 1. It's now easy to include in the export info. This enables direct cross-package cross-ABI calls, which are important for the performance of calling various hot assembly functions (e.g., internal/bytealg.*). This was really the point of this whole change. 2. Since all Funcs, including wrappers, now record their definition ABI, callTargetLSym no longer needs to distinguish wrappers from non-wrappers, so it's now nearly trivial (it would be completely trivial except that it has to work around a handful of cases where ir.Name.Func is nil). The simplification of callTargetLSym has one desirable but potentially surprising side-effect: the compiler will now generate direct calls to the definition ABI even when ABI wrappers are turned off. This is almost completely unnoticeable except that cmd/internal/obj/wasm looks for the call from runtime.deferreturn (defined in Go) to runtime.jmpdefer (defined in assembly) to compile is specially. That now looks like a direct call to ABI0 rather than going through the ABIInternal alias. While we're in here, we also set up the structures to support more than just ABI0 and ABIInternal and add various additional consistency checks all around. Performance-wise, this reduces the overhead induced by wrappers from 1.24% geomean (on Sweet) to 0.52% geomean, and reduces the number of benchmarks impacts >2% from 5 to 3. It has no impact on compiler speed. Impact of wrappers before this change: name old time/op new time/op delta BiogoIgor 15.8s ± 2% 15.8s ± 1% ~ (p=0.863 n=25+25) BiogoKrishna 18.3s ± 6% 18.1s ± 7% -1.39% (p=0.015 n=25+25) BleveIndexBatch100 5.88s ± 3% 6.04s ± 6% +2.72% (p=0.000 n=25+25) BleveQuery 6.42s ± 1% 6.76s ± 1% +5.31% (p=0.000 n=24+24) CompileTemplate 245ms ± 3% 250ms ± 6% ~ (p=0.068 n=22+25) CompileUnicode 93.6ms ± 2% 93.9ms ± 5% ~ (p=0.958 n=22+25) CompileGoTypes 1.60s ± 2% 1.59s ± 2% ~ (p=0.115 n=24+24) CompileCompiler 104ms ± 4% 104ms ± 3% ~ (p=0.453 n=22+25) CompileSSA 11.0s ± 2% 11.0s ± 1% ~ (p=0.789 n=24+25) CompileFlate 153ms ± 2% 153ms ± 1% ~ (p=0.055 n=21+20) CompileGoParser 229ms ± 2% 230ms ± 2% ~ (p=0.305 n=21+22) CompileReflect 585ms ± 5% 582ms ± 3% ~ (p=0.365 n=25+25) CompileTar 211ms ± 1% 211ms ± 3% ~ (p=0.592 n=20+22) CompileXML 282ms ± 3% 281ms ± 2% ~ (p=0.937 n=22+23) CompileStdCmd 13.7s ± 3% 13.6s ± 2% ~ (p=0.700 n=25+25) FoglemanFauxGLRenderRotateBoat 8.67s ± 1% 8.78s ± 1% +1.30% (p=0.000 n=25+25) FoglemanPathTraceRenderGopherIter1 20.5s ± 2% 20.9s ± 2% +1.85% (p=0.000 n=25+25) GopherLuaKNucleotide 30.1s ± 2% 31.1s ± 2% +3.38% (p=0.000 n=25+25) MarkdownRenderXHTML 246ms ± 5% 250ms ± 1% +1.42% (p=0.002 n=25+23) Tile38WithinCircle100kmRequest 828µs ± 6% 885µs ± 6% +6.85% (p=0.000 n=23+25) Tile38IntersectsCircle100kmRequest 1.04ms ± 5% 1.10ms ± 7% +5.63% (p=0.000 n=25+25) Tile38KNearestLimit100Request 974µs ± 4% 972µs ± 4% ~ (p=0.356 n=25+24) [Geo mean] 588ms 595ms +1.24% (https://perf.golang.org/search?q=upload:20210328.5) And after this change: name old time/op new time/op delta BiogoIgor 15.9s ± 1% 15.8s ± 1% -0.48% (p=0.008 n=22+25) BiogoKrishna 18.4s ± 6% 17.8s ± 6% -3.55% (p=0.008 n=25+25) BleveIndexBatch100 5.86s ± 3% 5.97s ± 4% +1.88% (p=0.001 n=25+25) BleveQuery 6.42s ± 1% 6.75s ± 1% +5.14% (p=0.000 n=25+25) CompileTemplate 246ms ± 5% 245ms ± 2% ~ (p=0.472 n=23+23) CompileUnicode 93.7ms ± 3% 93.5ms ± 2% ~ (p=0.813 n=22+23) CompileGoTypes 1.60s ± 2% 1.60s ± 2% ~ (p=0.108 n=25+23) CompileCompiler 104ms ± 3% 104ms ± 2% ~ (p=0.845 n=23+23) CompileSSA 11.0s ± 2% 11.0s ± 2% ~ (p=0.525 n=25+25) CompileFlate 152ms ± 1% 153ms ± 2% ~ (p=0.408 n=22+22) CompileGoParser 230ms ± 1% 230ms ± 1% ~ (p=0.363 n=21+23) CompileReflect 582ms ± 3% 584ms ± 4% ~ (p=0.658 n=25+25) CompileTar 212ms ± 2% 211ms ± 2% ~ (p=0.315 n=23+24) CompileXML 282ms ± 1% 282ms ± 1% ~ (p=0.991 n=23+22) CompileStdCmd 13.6s ± 2% 13.6s ± 2% ~ (p=0.699 n=25+24) FoglemanFauxGLRenderRotateBoat 8.66s ± 1% 8.69s ± 1% +0.28% (p=0.002 n=25+24) FoglemanPathTraceRenderGopherIter1 20.5s ± 3% 20.5s ± 2% ~ (p=0.407 n=25+25) GopherLuaKNucleotide 30.1s ± 2% 31.2s ± 2% +3.82% (p=0.000 n=25+25) MarkdownRenderXHTML 246ms ± 3% 245ms ± 1% ~ (p=0.478 n=23+22) Tile38WithinCircle100kmRequest 820µs ± 4% 856µs ± 5% +4.39% (p=0.000 n=24+25) Tile38IntersectsCircle100kmRequest 1.05ms ± 6% 1.07ms ± 6% +1.91% (p=0.014 n=25+25) Tile38KNearestLimit100Request 970µs ± 4% 970µs ± 3% ~ (p=0.819 n=22+24) [Geo mean] 588ms 591ms +0.52% (https://perf.golang.org/search?q=upload:20210328.6) For #40724. Change-Id: I1c374e32d4bbc88efed062a1b360017d3642140d Reviewed-on: https://go-review.googlesource.com/c/go/+/305274 Trust: Austin Clements <austin@google.com> Run-TryBot: Austin Clements <austin@google.com> Reviewed-by: Cherry Zhang <cherryyz@google.com> TryBot-Result: Go Bot <gobot@golang.org>
2021-03-25 19:50:08 -04:00
// Most functions are ABIInternal. The importer or symabis
// pass may override this.
fn.ABI = obj.ABIInternal
fn.SetTypecheck(1)
name.Func = fn
return fn
}
func (f *Func) isStmt() {}
func (n *Func) copy() Node { panic(n.no("copy")) }
func (n *Func) doChildren(do func(Node) bool) bool { return doNodes(n.Body, do) }
func (n *Func) editChildren(edit func(Node) Node) { editNodes(n.Body, edit) }
func (n *Func) editChildrenWithHidden(edit func(Node) Node) { editNodes(n.Body, edit) }
func (f *Func) Type() *types.Type { return f.Nname.Type() }
func (f *Func) Sym() *types.Sym { return f.Nname.Sym() }
func (f *Func) Linksym() *obj.LSym { return f.Nname.Linksym() }
func (f *Func) LinksymABI(abi obj.ABI) *obj.LSym { return f.Nname.LinksymABI(abi) }
// An Inline holds fields used for function bodies that can be inlined.
type Inline struct {
Cost int32 // heuristic cost of inlining this function
// Copy of Func.Dcl for use during inlining. This copy is needed
// because the function's Dcl may change from later compiler
// transformations. This field is also populated when a function
// from another package is imported and inlined.
Dcl []*Name
HaveDcl bool // whether we've loaded Dcl
// Function properties, encoded as a string (these are used for
// making inlining decisions). See cmd/compile/internal/inline/inlheur.
Properties string
// CanDelayResults reports whether it's safe for the inliner to delay
// initializing the result parameters until immediately before the
// "return" statement.
CanDelayResults bool
}
// A Mark represents a scope boundary.
type Mark struct {
// Pos is the position of the token that marks the scope
// change.
Pos src.XPos
// Scope identifies the innermost scope to the right of Pos.
Scope ScopeID
}
// A ScopeID represents a lexical scope within a function.
type ScopeID int32
const (
funcDupok = 1 << iota // duplicate definitions ok
funcWrapper // hide frame from users (elide in tracebacks, don't count as a frame for recover())
funcABIWrapper // is an ABI wrapper (also set flagWrapper)
funcNeedctxt // function uses context register (has closure variables)
// true if closure inside a function; false if a simple function or a
// closure in a global variable initialization
funcIsHiddenClosure
funcIsDeadcodeClosure // true if closure is deadcode
funcHasDefer // contains a defer statement
funcNilCheckDisabled // disable nil checks when compiling this function
funcInlinabilityChecked // inliner has already determined whether the function is inlinable
funcNeverReturns // function never returns (in most cases calls panic(), os.Exit(), or equivalent)
funcOpenCodedDeferDisallowed // can't do open-coded defers
funcClosureResultsLost // closure is called indirectly and we lost track of its results; used by escape analysis
funcPackageInit // compiler emitted .init func for package
)
type SymAndPos struct {
Sym *obj.LSym // LSym of callee
Pos src.XPos // line of call
}
func (f *Func) Dupok() bool { return f.flags&funcDupok != 0 }
func (f *Func) Wrapper() bool { return f.flags&funcWrapper != 0 }
cmd/compile: restructure ABI wrapper generation, export ABI This CL restructures how we track function ABIs and generate ABI wrappers in the compiler and adds import/export of ABIs across package boundaries. Currently, we start by tracking definition and referencing ABIs in two global maps and eventually move some of this information into the LSyms for functions. This complicates a lot of the existing code for handling wrappers and makes it particularly hard to export ABI information across packages. This change is built around instead recording this information on the ir.Func. First, this change replaces the global ABI def/ref maps with a type, which makes the data flow and lifetime of this information clear in gc.Main. These are populated during flag parsing. Then, early in the front-end, we loop over all ir.Funcs to 1. attach ABI def/ref information to the ir.Funcs and 2. create new ir.Funcs for ABI wrappers. Step 1 is slightly subtle because the information is keyed by linker symbol names, so we can't simply look things up in the compiler's regular symbol table. By generating ABI wrappers early in the front-end, we decouple this step from LSym creation, which makes LSym creation much simpler (like it was before ABI wrappers). In particular, LSyms for wrappers are now created at the same time as all other functions instead of by makeABIWrapper, which means we're back to the simpler, old situation where InitLSym was the only thing responsible for constructing function LSyms. Hence, we can restore the check that InitLSym is called exactly once per function. Attaching the ABI information to the ir.Func has several follow-on benefits: 1. It's now easy to include in the export info. This enables direct cross-package cross-ABI calls, which are important for the performance of calling various hot assembly functions (e.g., internal/bytealg.*). This was really the point of this whole change. 2. Since all Funcs, including wrappers, now record their definition ABI, callTargetLSym no longer needs to distinguish wrappers from non-wrappers, so it's now nearly trivial (it would be completely trivial except that it has to work around a handful of cases where ir.Name.Func is nil). The simplification of callTargetLSym has one desirable but potentially surprising side-effect: the compiler will now generate direct calls to the definition ABI even when ABI wrappers are turned off. This is almost completely unnoticeable except that cmd/internal/obj/wasm looks for the call from runtime.deferreturn (defined in Go) to runtime.jmpdefer (defined in assembly) to compile is specially. That now looks like a direct call to ABI0 rather than going through the ABIInternal alias. While we're in here, we also set up the structures to support more than just ABI0 and ABIInternal and add various additional consistency checks all around. Performance-wise, this reduces the overhead induced by wrappers from 1.24% geomean (on Sweet) to 0.52% geomean, and reduces the number of benchmarks impacts >2% from 5 to 3. It has no impact on compiler speed. Impact of wrappers before this change: name old time/op new time/op delta BiogoIgor 15.8s ± 2% 15.8s ± 1% ~ (p=0.863 n=25+25) BiogoKrishna 18.3s ± 6% 18.1s ± 7% -1.39% (p=0.015 n=25+25) BleveIndexBatch100 5.88s ± 3% 6.04s ± 6% +2.72% (p=0.000 n=25+25) BleveQuery 6.42s ± 1% 6.76s ± 1% +5.31% (p=0.000 n=24+24) CompileTemplate 245ms ± 3% 250ms ± 6% ~ (p=0.068 n=22+25) CompileUnicode 93.6ms ± 2% 93.9ms ± 5% ~ (p=0.958 n=22+25) CompileGoTypes 1.60s ± 2% 1.59s ± 2% ~ (p=0.115 n=24+24) CompileCompiler 104ms ± 4% 104ms ± 3% ~ (p=0.453 n=22+25) CompileSSA 11.0s ± 2% 11.0s ± 1% ~ (p=0.789 n=24+25) CompileFlate 153ms ± 2% 153ms ± 1% ~ (p=0.055 n=21+20) CompileGoParser 229ms ± 2% 230ms ± 2% ~ (p=0.305 n=21+22) CompileReflect 585ms ± 5% 582ms ± 3% ~ (p=0.365 n=25+25) CompileTar 211ms ± 1% 211ms ± 3% ~ (p=0.592 n=20+22) CompileXML 282ms ± 3% 281ms ± 2% ~ (p=0.937 n=22+23) CompileStdCmd 13.7s ± 3% 13.6s ± 2% ~ (p=0.700 n=25+25) FoglemanFauxGLRenderRotateBoat 8.67s ± 1% 8.78s ± 1% +1.30% (p=0.000 n=25+25) FoglemanPathTraceRenderGopherIter1 20.5s ± 2% 20.9s ± 2% +1.85% (p=0.000 n=25+25) GopherLuaKNucleotide 30.1s ± 2% 31.1s ± 2% +3.38% (p=0.000 n=25+25) MarkdownRenderXHTML 246ms ± 5% 250ms ± 1% +1.42% (p=0.002 n=25+23) Tile38WithinCircle100kmRequest 828µs ± 6% 885µs ± 6% +6.85% (p=0.000 n=23+25) Tile38IntersectsCircle100kmRequest 1.04ms ± 5% 1.10ms ± 7% +5.63% (p=0.000 n=25+25) Tile38KNearestLimit100Request 974µs ± 4% 972µs ± 4% ~ (p=0.356 n=25+24) [Geo mean] 588ms 595ms +1.24% (https://perf.golang.org/search?q=upload:20210328.5) And after this change: name old time/op new time/op delta BiogoIgor 15.9s ± 1% 15.8s ± 1% -0.48% (p=0.008 n=22+25) BiogoKrishna 18.4s ± 6% 17.8s ± 6% -3.55% (p=0.008 n=25+25) BleveIndexBatch100 5.86s ± 3% 5.97s ± 4% +1.88% (p=0.001 n=25+25) BleveQuery 6.42s ± 1% 6.75s ± 1% +5.14% (p=0.000 n=25+25) CompileTemplate 246ms ± 5% 245ms ± 2% ~ (p=0.472 n=23+23) CompileUnicode 93.7ms ± 3% 93.5ms ± 2% ~ (p=0.813 n=22+23) CompileGoTypes 1.60s ± 2% 1.60s ± 2% ~ (p=0.108 n=25+23) CompileCompiler 104ms ± 3% 104ms ± 2% ~ (p=0.845 n=23+23) CompileSSA 11.0s ± 2% 11.0s ± 2% ~ (p=0.525 n=25+25) CompileFlate 152ms ± 1% 153ms ± 2% ~ (p=0.408 n=22+22) CompileGoParser 230ms ± 1% 230ms ± 1% ~ (p=0.363 n=21+23) CompileReflect 582ms ± 3% 584ms ± 4% ~ (p=0.658 n=25+25) CompileTar 212ms ± 2% 211ms ± 2% ~ (p=0.315 n=23+24) CompileXML 282ms ± 1% 282ms ± 1% ~ (p=0.991 n=23+22) CompileStdCmd 13.6s ± 2% 13.6s ± 2% ~ (p=0.699 n=25+24) FoglemanFauxGLRenderRotateBoat 8.66s ± 1% 8.69s ± 1% +0.28% (p=0.002 n=25+24) FoglemanPathTraceRenderGopherIter1 20.5s ± 3% 20.5s ± 2% ~ (p=0.407 n=25+25) GopherLuaKNucleotide 30.1s ± 2% 31.2s ± 2% +3.82% (p=0.000 n=25+25) MarkdownRenderXHTML 246ms ± 3% 245ms ± 1% ~ (p=0.478 n=23+22) Tile38WithinCircle100kmRequest 820µs ± 4% 856µs ± 5% +4.39% (p=0.000 n=24+25) Tile38IntersectsCircle100kmRequest 1.05ms ± 6% 1.07ms ± 6% +1.91% (p=0.014 n=25+25) Tile38KNearestLimit100Request 970µs ± 4% 970µs ± 3% ~ (p=0.819 n=22+24) [Geo mean] 588ms 591ms +0.52% (https://perf.golang.org/search?q=upload:20210328.6) For #40724. Change-Id: I1c374e32d4bbc88efed062a1b360017d3642140d Reviewed-on: https://go-review.googlesource.com/c/go/+/305274 Trust: Austin Clements <austin@google.com> Run-TryBot: Austin Clements <austin@google.com> Reviewed-by: Cherry Zhang <cherryyz@google.com> TryBot-Result: Go Bot <gobot@golang.org>
2021-03-25 19:50:08 -04:00
func (f *Func) ABIWrapper() bool { return f.flags&funcABIWrapper != 0 }
func (f *Func) Needctxt() bool { return f.flags&funcNeedctxt != 0 }
func (f *Func) IsHiddenClosure() bool { return f.flags&funcIsHiddenClosure != 0 }
func (f *Func) IsDeadcodeClosure() bool { return f.flags&funcIsDeadcodeClosure != 0 }
func (f *Func) HasDefer() bool { return f.flags&funcHasDefer != 0 }
func (f *Func) NilCheckDisabled() bool { return f.flags&funcNilCheckDisabled != 0 }
func (f *Func) InlinabilityChecked() bool { return f.flags&funcInlinabilityChecked != 0 }
func (f *Func) NeverReturns() bool { return f.flags&funcNeverReturns != 0 }
func (f *Func) OpenCodedDeferDisallowed() bool { return f.flags&funcOpenCodedDeferDisallowed != 0 }
func (f *Func) ClosureResultsLost() bool { return f.flags&funcClosureResultsLost != 0 }
func (f *Func) IsPackageInit() bool { return f.flags&funcPackageInit != 0 }
func (f *Func) SetDupok(b bool) { f.flags.set(funcDupok, b) }
func (f *Func) SetWrapper(b bool) { f.flags.set(funcWrapper, b) }
cmd/compile: restructure ABI wrapper generation, export ABI This CL restructures how we track function ABIs and generate ABI wrappers in the compiler and adds import/export of ABIs across package boundaries. Currently, we start by tracking definition and referencing ABIs in two global maps and eventually move some of this information into the LSyms for functions. This complicates a lot of the existing code for handling wrappers and makes it particularly hard to export ABI information across packages. This change is built around instead recording this information on the ir.Func. First, this change replaces the global ABI def/ref maps with a type, which makes the data flow and lifetime of this information clear in gc.Main. These are populated during flag parsing. Then, early in the front-end, we loop over all ir.Funcs to 1. attach ABI def/ref information to the ir.Funcs and 2. create new ir.Funcs for ABI wrappers. Step 1 is slightly subtle because the information is keyed by linker symbol names, so we can't simply look things up in the compiler's regular symbol table. By generating ABI wrappers early in the front-end, we decouple this step from LSym creation, which makes LSym creation much simpler (like it was before ABI wrappers). In particular, LSyms for wrappers are now created at the same time as all other functions instead of by makeABIWrapper, which means we're back to the simpler, old situation where InitLSym was the only thing responsible for constructing function LSyms. Hence, we can restore the check that InitLSym is called exactly once per function. Attaching the ABI information to the ir.Func has several follow-on benefits: 1. It's now easy to include in the export info. This enables direct cross-package cross-ABI calls, which are important for the performance of calling various hot assembly functions (e.g., internal/bytealg.*). This was really the point of this whole change. 2. Since all Funcs, including wrappers, now record their definition ABI, callTargetLSym no longer needs to distinguish wrappers from non-wrappers, so it's now nearly trivial (it would be completely trivial except that it has to work around a handful of cases where ir.Name.Func is nil). The simplification of callTargetLSym has one desirable but potentially surprising side-effect: the compiler will now generate direct calls to the definition ABI even when ABI wrappers are turned off. This is almost completely unnoticeable except that cmd/internal/obj/wasm looks for the call from runtime.deferreturn (defined in Go) to runtime.jmpdefer (defined in assembly) to compile is specially. That now looks like a direct call to ABI0 rather than going through the ABIInternal alias. While we're in here, we also set up the structures to support more than just ABI0 and ABIInternal and add various additional consistency checks all around. Performance-wise, this reduces the overhead induced by wrappers from 1.24% geomean (on Sweet) to 0.52% geomean, and reduces the number of benchmarks impacts >2% from 5 to 3. It has no impact on compiler speed. Impact of wrappers before this change: name old time/op new time/op delta BiogoIgor 15.8s ± 2% 15.8s ± 1% ~ (p=0.863 n=25+25) BiogoKrishna 18.3s ± 6% 18.1s ± 7% -1.39% (p=0.015 n=25+25) BleveIndexBatch100 5.88s ± 3% 6.04s ± 6% +2.72% (p=0.000 n=25+25) BleveQuery 6.42s ± 1% 6.76s ± 1% +5.31% (p=0.000 n=24+24) CompileTemplate 245ms ± 3% 250ms ± 6% ~ (p=0.068 n=22+25) CompileUnicode 93.6ms ± 2% 93.9ms ± 5% ~ (p=0.958 n=22+25) CompileGoTypes 1.60s ± 2% 1.59s ± 2% ~ (p=0.115 n=24+24) CompileCompiler 104ms ± 4% 104ms ± 3% ~ (p=0.453 n=22+25) CompileSSA 11.0s ± 2% 11.0s ± 1% ~ (p=0.789 n=24+25) CompileFlate 153ms ± 2% 153ms ± 1% ~ (p=0.055 n=21+20) CompileGoParser 229ms ± 2% 230ms ± 2% ~ (p=0.305 n=21+22) CompileReflect 585ms ± 5% 582ms ± 3% ~ (p=0.365 n=25+25) CompileTar 211ms ± 1% 211ms ± 3% ~ (p=0.592 n=20+22) CompileXML 282ms ± 3% 281ms ± 2% ~ (p=0.937 n=22+23) CompileStdCmd 13.7s ± 3% 13.6s ± 2% ~ (p=0.700 n=25+25) FoglemanFauxGLRenderRotateBoat 8.67s ± 1% 8.78s ± 1% +1.30% (p=0.000 n=25+25) FoglemanPathTraceRenderGopherIter1 20.5s ± 2% 20.9s ± 2% +1.85% (p=0.000 n=25+25) GopherLuaKNucleotide 30.1s ± 2% 31.1s ± 2% +3.38% (p=0.000 n=25+25) MarkdownRenderXHTML 246ms ± 5% 250ms ± 1% +1.42% (p=0.002 n=25+23) Tile38WithinCircle100kmRequest 828µs ± 6% 885µs ± 6% +6.85% (p=0.000 n=23+25) Tile38IntersectsCircle100kmRequest 1.04ms ± 5% 1.10ms ± 7% +5.63% (p=0.000 n=25+25) Tile38KNearestLimit100Request 974µs ± 4% 972µs ± 4% ~ (p=0.356 n=25+24) [Geo mean] 588ms 595ms +1.24% (https://perf.golang.org/search?q=upload:20210328.5) And after this change: name old time/op new time/op delta BiogoIgor 15.9s ± 1% 15.8s ± 1% -0.48% (p=0.008 n=22+25) BiogoKrishna 18.4s ± 6% 17.8s ± 6% -3.55% (p=0.008 n=25+25) BleveIndexBatch100 5.86s ± 3% 5.97s ± 4% +1.88% (p=0.001 n=25+25) BleveQuery 6.42s ± 1% 6.75s ± 1% +5.14% (p=0.000 n=25+25) CompileTemplate 246ms ± 5% 245ms ± 2% ~ (p=0.472 n=23+23) CompileUnicode 93.7ms ± 3% 93.5ms ± 2% ~ (p=0.813 n=22+23) CompileGoTypes 1.60s ± 2% 1.60s ± 2% ~ (p=0.108 n=25+23) CompileCompiler 104ms ± 3% 104ms ± 2% ~ (p=0.845 n=23+23) CompileSSA 11.0s ± 2% 11.0s ± 2% ~ (p=0.525 n=25+25) CompileFlate 152ms ± 1% 153ms ± 2% ~ (p=0.408 n=22+22) CompileGoParser 230ms ± 1% 230ms ± 1% ~ (p=0.363 n=21+23) CompileReflect 582ms ± 3% 584ms ± 4% ~ (p=0.658 n=25+25) CompileTar 212ms ± 2% 211ms ± 2% ~ (p=0.315 n=23+24) CompileXML 282ms ± 1% 282ms ± 1% ~ (p=0.991 n=23+22) CompileStdCmd 13.6s ± 2% 13.6s ± 2% ~ (p=0.699 n=25+24) FoglemanFauxGLRenderRotateBoat 8.66s ± 1% 8.69s ± 1% +0.28% (p=0.002 n=25+24) FoglemanPathTraceRenderGopherIter1 20.5s ± 3% 20.5s ± 2% ~ (p=0.407 n=25+25) GopherLuaKNucleotide 30.1s ± 2% 31.2s ± 2% +3.82% (p=0.000 n=25+25) MarkdownRenderXHTML 246ms ± 3% 245ms ± 1% ~ (p=0.478 n=23+22) Tile38WithinCircle100kmRequest 820µs ± 4% 856µs ± 5% +4.39% (p=0.000 n=24+25) Tile38IntersectsCircle100kmRequest 1.05ms ± 6% 1.07ms ± 6% +1.91% (p=0.014 n=25+25) Tile38KNearestLimit100Request 970µs ± 4% 970µs ± 3% ~ (p=0.819 n=22+24) [Geo mean] 588ms 591ms +0.52% (https://perf.golang.org/search?q=upload:20210328.6) For #40724. Change-Id: I1c374e32d4bbc88efed062a1b360017d3642140d Reviewed-on: https://go-review.googlesource.com/c/go/+/305274 Trust: Austin Clements <austin@google.com> Run-TryBot: Austin Clements <austin@google.com> Reviewed-by: Cherry Zhang <cherryyz@google.com> TryBot-Result: Go Bot <gobot@golang.org>
2021-03-25 19:50:08 -04:00
func (f *Func) SetABIWrapper(b bool) { f.flags.set(funcABIWrapper, b) }
func (f *Func) SetNeedctxt(b bool) { f.flags.set(funcNeedctxt, b) }
func (f *Func) SetIsHiddenClosure(b bool) { f.flags.set(funcIsHiddenClosure, b) }
func (f *Func) SetIsDeadcodeClosure(b bool) { f.flags.set(funcIsDeadcodeClosure, b) }
func (f *Func) SetHasDefer(b bool) { f.flags.set(funcHasDefer, b) }
func (f *Func) SetNilCheckDisabled(b bool) { f.flags.set(funcNilCheckDisabled, b) }
func (f *Func) SetInlinabilityChecked(b bool) { f.flags.set(funcInlinabilityChecked, b) }
func (f *Func) SetNeverReturns(b bool) { f.flags.set(funcNeverReturns, b) }
func (f *Func) SetOpenCodedDeferDisallowed(b bool) { f.flags.set(funcOpenCodedDeferDisallowed, b) }
func (f *Func) SetClosureResultsLost(b bool) { f.flags.set(funcClosureResultsLost, b) }
func (f *Func) SetIsPackageInit(b bool) { f.flags.set(funcPackageInit, b) }
func (f *Func) SetWBPos(pos src.XPos) {
if base.Debug.WB != 0 {
base.WarnfAt(pos, "write barrier")
}
if !f.WBPos.IsKnown() {
f.WBPos = pos
}
}
// FuncName returns the name (without the package) of the function f.
func FuncName(f *Func) string {
if f == nil || f.Nname == nil {
return "<nil>"
}
return f.Sym().Name
}
// PkgFuncName returns the name of the function referenced by f, with package
// prepended.
//
// This differs from the compiler's internal convention where local functions
// lack a package. This is primarily useful when the ultimate consumer of this
// is a human looking at message.
func PkgFuncName(f *Func) string {
if f == nil || f.Nname == nil {
return "<nil>"
}
s := f.Sym()
pkg := s.Pkg
return pkg.Path + "." + s.Name
}
[dev.regabi] cmd/compile: move helpers into package ir [generated] [git-generate] cd src/cmd/compile/internal/gc sed -i '' 's/TestBuiltin.*/& t.Skip("mkbuiltin needs fixing")/' builtin_test.go gofmt -w builtin_test.go rf ' # Inline a few little-used constructors to avoid bringing them. ex { import "cmd/compile/internal/base" import "cmd/compile/internal/ir" import "cmd/compile/internal/types" import "cmd/internal/src" var typ *types.Type var sym *types.Sym var str string symfield(sym, typ) -> ir.NewField(base.Pos, sym, nil, typ) anonfield(typ) -> ir.NewField(base.Pos, nil, nil, typ) namedfield(str, typ) -> ir.NewField(base.Pos, lookup(str), nil, typ) var cp *ir.CallPartExpr callpartMethod(cp) -> cp.Method var n ir.Node callpartMethod(n) -> n.(*ir.CallPartExpr).Method var ns []ir.Node liststmt(ns) -> ir.NewBlockStmt(src.NoXPos, ns) } rm symfield anonfield namedfield liststmt callpartMethod mv maxStackVarSize MaxStackVarSize mv maxImplicitStackVarSize MaxImplicitStackVarSize mv smallArrayBytes MaxSmallArraySize mv MaxStackVarSize cfg.go mv nodbool NewBool mv nodintconst NewInt mv nodstr NewString mv NewBool NewInt NewString const.go mv Mpprec ConstPrec mv bigFloatVal BigFloat mv doesoverflow ConstOverflow mv isGoConst IsConstNode mv smallintconst IsSmallIntConst mv isZero IsZero mv islvalue IsAssignable mv staticValue StaticValue mv samesafeexpr SameSafeExpr mv checkPtr ShouldCheckPtr mv isReflectHeaderDataField IsReflectHeaderDataField mv paramNnames ParamNames mv methodSym MethodSym mv methodSymSuffix MethodSymSuffix mv methodExprFunc MethodExprFunc mv methodExprName MethodExprName mv IsZero IsAssignable StaticValue staticValue1 reassigned \ IsIntrinsicCall \ SameSafeExpr ShouldCheckPtr IsReflectHeaderDataField \ ParamNames MethodSym MethodSymSuffix \ MethodExprName MethodExprFunc \ expr.go mv Curfn CurFunc mv funcsymname FuncSymName mv newFuncNameAt NewFuncNameAt mv setNodeNameFunc MarkFunc mv CurFunc FuncSymName NewFuncNameAt MarkFunc func.go mv isParamStackCopy IsParamStackCopy mv isParamHeapCopy IsParamHeapCopy mv nodfp RegFP mv IsParamStackCopy IsParamHeapCopy RegFP name.go mv hasUniquePos HasUniquePos mv setlineno SetPos mv initExpr InitExpr mv hasNamedResults HasNamedResults mv outervalue OuterValue mv HasNamedResults HasUniquePos SetPos InitExpr OuterValue EscNever node.go mv visitBottomUp VisitFuncsBottomUp # scc.go mv cfg.go \ NewBool NewInt NewString \ # parts of const.go ConstPrec BigFloat ConstOverflow IsConstNode IsSmallIntConst \ expr.go func.go name.go node.go scc.go \ cmd/compile/internal/ir ' Change-Id: I13402c5a2cedbf78d993a1eae2940718f23ac166 Reviewed-on: https://go-review.googlesource.com/c/go/+/279421 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>
2020-12-23 00:38:15 -05:00
// LinkFuncName returns the name of the function f, as it will appear in the
// symbol table of the final linked binary.
func LinkFuncName(f *Func) string {
if f == nil || f.Nname == nil {
return "<nil>"
}
s := f.Sym()
pkg := s.Pkg
return objabi.PathToPrefix(pkg.Path) + "." + s.Name
}
// ParseLinkFuncName parsers a symbol name (as returned from LinkFuncName) back
// to the package path and local symbol name.
func ParseLinkFuncName(name string) (pkg, sym string, err error) {
pkg, sym = splitPkg(name)
if pkg == "" {
return "", "", fmt.Errorf("no package path in name")
}
pkg, err = objabi.PrefixToPath(pkg) // unescape
if err != nil {
return "", "", fmt.Errorf("malformed package path: %v", err)
}
return pkg, sym, nil
}
// Borrowed from x/mod.
func modPathOK(r rune) bool {
if r < utf8.RuneSelf {
return r == '-' || r == '.' || r == '_' || r == '~' ||
'0' <= r && r <= '9' ||
'A' <= r && r <= 'Z' ||
'a' <= r && r <= 'z'
}
return false
}
func escapedImportPathOK(r rune) bool {
return modPathOK(r) || r == '+' || r == '/' || r == '%'
}
// splitPkg splits the full linker symbol name into package and local symbol
// name.
func splitPkg(name string) (pkgpath, sym string) {
// package-sym split is at first dot after last the / that comes before
// any characters illegal in a package path.
lastSlashIdx := 0
for i, r := range name {
// Catches cases like:
// * example.foo[sync/atomic.Uint64].
// * example%2ecom.foo[sync/atomic.Uint64].
//
// Note that name is still escaped; unescape occurs after splitPkg.
if !escapedImportPathOK(r) {
break
}
if r == '/' {
lastSlashIdx = i
}
}
for i := lastSlashIdx; i < len(name); i++ {
r := name[i]
if r == '.' {
return name[:i], name[i+1:]
}
}
return "", name
}
[dev.regabi] cmd/compile: move helpers into package ir [generated] [git-generate] cd src/cmd/compile/internal/gc sed -i '' 's/TestBuiltin.*/& t.Skip("mkbuiltin needs fixing")/' builtin_test.go gofmt -w builtin_test.go rf ' # Inline a few little-used constructors to avoid bringing them. ex { import "cmd/compile/internal/base" import "cmd/compile/internal/ir" import "cmd/compile/internal/types" import "cmd/internal/src" var typ *types.Type var sym *types.Sym var str string symfield(sym, typ) -> ir.NewField(base.Pos, sym, nil, typ) anonfield(typ) -> ir.NewField(base.Pos, nil, nil, typ) namedfield(str, typ) -> ir.NewField(base.Pos, lookup(str), nil, typ) var cp *ir.CallPartExpr callpartMethod(cp) -> cp.Method var n ir.Node callpartMethod(n) -> n.(*ir.CallPartExpr).Method var ns []ir.Node liststmt(ns) -> ir.NewBlockStmt(src.NoXPos, ns) } rm symfield anonfield namedfield liststmt callpartMethod mv maxStackVarSize MaxStackVarSize mv maxImplicitStackVarSize MaxImplicitStackVarSize mv smallArrayBytes MaxSmallArraySize mv MaxStackVarSize cfg.go mv nodbool NewBool mv nodintconst NewInt mv nodstr NewString mv NewBool NewInt NewString const.go mv Mpprec ConstPrec mv bigFloatVal BigFloat mv doesoverflow ConstOverflow mv isGoConst IsConstNode mv smallintconst IsSmallIntConst mv isZero IsZero mv islvalue IsAssignable mv staticValue StaticValue mv samesafeexpr SameSafeExpr mv checkPtr ShouldCheckPtr mv isReflectHeaderDataField IsReflectHeaderDataField mv paramNnames ParamNames mv methodSym MethodSym mv methodSymSuffix MethodSymSuffix mv methodExprFunc MethodExprFunc mv methodExprName MethodExprName mv IsZero IsAssignable StaticValue staticValue1 reassigned \ IsIntrinsicCall \ SameSafeExpr ShouldCheckPtr IsReflectHeaderDataField \ ParamNames MethodSym MethodSymSuffix \ MethodExprName MethodExprFunc \ expr.go mv Curfn CurFunc mv funcsymname FuncSymName mv newFuncNameAt NewFuncNameAt mv setNodeNameFunc MarkFunc mv CurFunc FuncSymName NewFuncNameAt MarkFunc func.go mv isParamStackCopy IsParamStackCopy mv isParamHeapCopy IsParamHeapCopy mv nodfp RegFP mv IsParamStackCopy IsParamHeapCopy RegFP name.go mv hasUniquePos HasUniquePos mv setlineno SetPos mv initExpr InitExpr mv hasNamedResults HasNamedResults mv outervalue OuterValue mv HasNamedResults HasUniquePos SetPos InitExpr OuterValue EscNever node.go mv visitBottomUp VisitFuncsBottomUp # scc.go mv cfg.go \ NewBool NewInt NewString \ # parts of const.go ConstPrec BigFloat ConstOverflow IsConstNode IsSmallIntConst \ expr.go func.go name.go node.go scc.go \ cmd/compile/internal/ir ' Change-Id: I13402c5a2cedbf78d993a1eae2940718f23ac166 Reviewed-on: https://go-review.googlesource.com/c/go/+/279421 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>
2020-12-23 00:38:15 -05:00
var CurFunc *Func
// WithFunc invokes do with CurFunc and base.Pos set to curfn and
// curfn.Pos(), respectively, and then restores their previous values
// before returning.
func WithFunc(curfn *Func, do func()) {
oldfn, oldpos := CurFunc, base.Pos
defer func() { CurFunc, base.Pos = oldfn, oldpos }()
CurFunc, base.Pos = curfn, curfn.Pos()
do()
}
[dev.regabi] cmd/compile: move helpers into package ir [generated] [git-generate] cd src/cmd/compile/internal/gc sed -i '' 's/TestBuiltin.*/& t.Skip("mkbuiltin needs fixing")/' builtin_test.go gofmt -w builtin_test.go rf ' # Inline a few little-used constructors to avoid bringing them. ex { import "cmd/compile/internal/base" import "cmd/compile/internal/ir" import "cmd/compile/internal/types" import "cmd/internal/src" var typ *types.Type var sym *types.Sym var str string symfield(sym, typ) -> ir.NewField(base.Pos, sym, nil, typ) anonfield(typ) -> ir.NewField(base.Pos, nil, nil, typ) namedfield(str, typ) -> ir.NewField(base.Pos, lookup(str), nil, typ) var cp *ir.CallPartExpr callpartMethod(cp) -> cp.Method var n ir.Node callpartMethod(n) -> n.(*ir.CallPartExpr).Method var ns []ir.Node liststmt(ns) -> ir.NewBlockStmt(src.NoXPos, ns) } rm symfield anonfield namedfield liststmt callpartMethod mv maxStackVarSize MaxStackVarSize mv maxImplicitStackVarSize MaxImplicitStackVarSize mv smallArrayBytes MaxSmallArraySize mv MaxStackVarSize cfg.go mv nodbool NewBool mv nodintconst NewInt mv nodstr NewString mv NewBool NewInt NewString const.go mv Mpprec ConstPrec mv bigFloatVal BigFloat mv doesoverflow ConstOverflow mv isGoConst IsConstNode mv smallintconst IsSmallIntConst mv isZero IsZero mv islvalue IsAssignable mv staticValue StaticValue mv samesafeexpr SameSafeExpr mv checkPtr ShouldCheckPtr mv isReflectHeaderDataField IsReflectHeaderDataField mv paramNnames ParamNames mv methodSym MethodSym mv methodSymSuffix MethodSymSuffix mv methodExprFunc MethodExprFunc mv methodExprName MethodExprName mv IsZero IsAssignable StaticValue staticValue1 reassigned \ IsIntrinsicCall \ SameSafeExpr ShouldCheckPtr IsReflectHeaderDataField \ ParamNames MethodSym MethodSymSuffix \ MethodExprName MethodExprFunc \ expr.go mv Curfn CurFunc mv funcsymname FuncSymName mv newFuncNameAt NewFuncNameAt mv setNodeNameFunc MarkFunc mv CurFunc FuncSymName NewFuncNameAt MarkFunc func.go mv isParamStackCopy IsParamStackCopy mv isParamHeapCopy IsParamHeapCopy mv nodfp RegFP mv IsParamStackCopy IsParamHeapCopy RegFP name.go mv hasUniquePos HasUniquePos mv setlineno SetPos mv initExpr InitExpr mv hasNamedResults HasNamedResults mv outervalue OuterValue mv HasNamedResults HasUniquePos SetPos InitExpr OuterValue EscNever node.go mv visitBottomUp VisitFuncsBottomUp # scc.go mv cfg.go \ NewBool NewInt NewString \ # parts of const.go ConstPrec BigFloat ConstOverflow IsConstNode IsSmallIntConst \ expr.go func.go name.go node.go scc.go \ cmd/compile/internal/ir ' Change-Id: I13402c5a2cedbf78d993a1eae2940718f23ac166 Reviewed-on: https://go-review.googlesource.com/c/go/+/279421 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>
2020-12-23 00:38:15 -05:00
func FuncSymName(s *types.Sym) string {
return s.Name + "·f"
}
[dev.regabi] cmd/compile: split out package walk [generated] [git-generate] cd src/cmd/compile/internal/gc rf ' # Late addition to package ir. mv closuredebugruntimecheck ClosureDebugRuntimeCheck mv hasemptycvars IsTrivialClosure mv ClosureDebugRuntimeCheck IsTrivialClosure func.go mv func.go cmd/compile/internal/ir # Late addition to package reflectdata. mv markTypeUsedInInterface MarkTypeUsedInInterface mv markUsedIfaceMethod MarkUsedIfaceMethod mv MarkTypeUsedInInterface MarkUsedIfaceMethod reflect.go mv reflect.go cmd/compile/internal/reflectdata # Late addition to package staticdata. mv litsym InitConst mv InitConst data.go mv data.go cmd/compile/internal/staticdata # Extract staticinit out of walk into its own package. mv InitEntry InitPlan InitSchedule InitSchedule.append InitSchedule.staticInit \ InitSchedule.tryStaticInit InitSchedule.staticcopy \ InitSchedule.staticassign InitSchedule.initplan InitSchedule.addvalue \ statuniqgen staticname stataddr anySideEffects getlit isvaluelit \ sched.go mv InitSchedule.initplans InitSchedule.Plans mv InitSchedule.inittemps InitSchedule.Temps mv InitSchedule.out InitSchedule.Out mv InitSchedule.staticInit InitSchedule.StaticInit mv InitSchedule.staticassign InitSchedule.StaticAssign mv InitSchedule Schedule mv InitPlan Plan mv InitEntry Entry mv anySideEffects AnySideEffects mv staticname StaticName mv stataddr StaticLoc mv sched.go cmd/compile/internal/staticinit # Export API and unexport non-API. mv transformclosure Closure mv walk Walk mv Order orderState mv swt.go switch.go mv racewalk.go race.go mv closure.go order.go range.go select.go switch.go race.go \ sinit.go subr.go walk.go \ cmd/compile/internal/walk ' : # Update format test. cd ../../ go install cmd/compile/... cmd/internal/archive go test -u || go test -u rm -rf ../../../pkg/darwin_amd64/cmd Change-Id: I11c7a45f74d4a9e963da15c080e1018caaa99c05 Reviewed-on: https://go-review.googlesource.com/c/go/+/279478 Trust: Russ Cox <rsc@golang.org> Run-TryBot: Russ Cox <rsc@golang.org> Reviewed-by: Matthew Dempsky <mdempsky@google.com>
2020-12-23 01:05:16 -05:00
// ClosureDebugRuntimeCheck applies boilerplate checks for debug flags
// and compiling runtime.
[dev.regabi] cmd/compile: split out package walk [generated] [git-generate] cd src/cmd/compile/internal/gc rf ' # Late addition to package ir. mv closuredebugruntimecheck ClosureDebugRuntimeCheck mv hasemptycvars IsTrivialClosure mv ClosureDebugRuntimeCheck IsTrivialClosure func.go mv func.go cmd/compile/internal/ir # Late addition to package reflectdata. mv markTypeUsedInInterface MarkTypeUsedInInterface mv markUsedIfaceMethod MarkUsedIfaceMethod mv MarkTypeUsedInInterface MarkUsedIfaceMethod reflect.go mv reflect.go cmd/compile/internal/reflectdata # Late addition to package staticdata. mv litsym InitConst mv InitConst data.go mv data.go cmd/compile/internal/staticdata # Extract staticinit out of walk into its own package. mv InitEntry InitPlan InitSchedule InitSchedule.append InitSchedule.staticInit \ InitSchedule.tryStaticInit InitSchedule.staticcopy \ InitSchedule.staticassign InitSchedule.initplan InitSchedule.addvalue \ statuniqgen staticname stataddr anySideEffects getlit isvaluelit \ sched.go mv InitSchedule.initplans InitSchedule.Plans mv InitSchedule.inittemps InitSchedule.Temps mv InitSchedule.out InitSchedule.Out mv InitSchedule.staticInit InitSchedule.StaticInit mv InitSchedule.staticassign InitSchedule.StaticAssign mv InitSchedule Schedule mv InitPlan Plan mv InitEntry Entry mv anySideEffects AnySideEffects mv staticname StaticName mv stataddr StaticLoc mv sched.go cmd/compile/internal/staticinit # Export API and unexport non-API. mv transformclosure Closure mv walk Walk mv Order orderState mv swt.go switch.go mv racewalk.go race.go mv closure.go order.go range.go select.go switch.go race.go \ sinit.go subr.go walk.go \ cmd/compile/internal/walk ' : # Update format test. cd ../../ go install cmd/compile/... cmd/internal/archive go test -u || go test -u rm -rf ../../../pkg/darwin_amd64/cmd Change-Id: I11c7a45f74d4a9e963da15c080e1018caaa99c05 Reviewed-on: https://go-review.googlesource.com/c/go/+/279478 Trust: Russ Cox <rsc@golang.org> Run-TryBot: Russ Cox <rsc@golang.org> Reviewed-by: Matthew Dempsky <mdempsky@google.com>
2020-12-23 01:05:16 -05:00
func ClosureDebugRuntimeCheck(clo *ClosureExpr) {
if base.Debug.Closure > 0 {
if clo.Esc() == EscHeap {
base.WarnfAt(clo.Pos(), "heap closure, captured vars = %v", clo.Func.ClosureVars)
} else {
base.WarnfAt(clo.Pos(), "stack closure, captured vars = %v", clo.Func.ClosureVars)
}
}
if base.Flag.CompilingRuntime && clo.Esc() == EscHeap && !clo.IsGoWrap {
base.ErrorfAt(clo.Pos(), 0, "heap-allocated closure %s, not allowed in runtime", FuncName(clo.Func))
[dev.regabi] cmd/compile: split out package walk [generated] [git-generate] cd src/cmd/compile/internal/gc rf ' # Late addition to package ir. mv closuredebugruntimecheck ClosureDebugRuntimeCheck mv hasemptycvars IsTrivialClosure mv ClosureDebugRuntimeCheck IsTrivialClosure func.go mv func.go cmd/compile/internal/ir # Late addition to package reflectdata. mv markTypeUsedInInterface MarkTypeUsedInInterface mv markUsedIfaceMethod MarkUsedIfaceMethod mv MarkTypeUsedInInterface MarkUsedIfaceMethod reflect.go mv reflect.go cmd/compile/internal/reflectdata # Late addition to package staticdata. mv litsym InitConst mv InitConst data.go mv data.go cmd/compile/internal/staticdata # Extract staticinit out of walk into its own package. mv InitEntry InitPlan InitSchedule InitSchedule.append InitSchedule.staticInit \ InitSchedule.tryStaticInit InitSchedule.staticcopy \ InitSchedule.staticassign InitSchedule.initplan InitSchedule.addvalue \ statuniqgen staticname stataddr anySideEffects getlit isvaluelit \ sched.go mv InitSchedule.initplans InitSchedule.Plans mv InitSchedule.inittemps InitSchedule.Temps mv InitSchedule.out InitSchedule.Out mv InitSchedule.staticInit InitSchedule.StaticInit mv InitSchedule.staticassign InitSchedule.StaticAssign mv InitSchedule Schedule mv InitPlan Plan mv InitEntry Entry mv anySideEffects AnySideEffects mv staticname StaticName mv stataddr StaticLoc mv sched.go cmd/compile/internal/staticinit # Export API and unexport non-API. mv transformclosure Closure mv walk Walk mv Order orderState mv swt.go switch.go mv racewalk.go race.go mv closure.go order.go range.go select.go switch.go race.go \ sinit.go subr.go walk.go \ cmd/compile/internal/walk ' : # Update format test. cd ../../ go install cmd/compile/... cmd/internal/archive go test -u || go test -u rm -rf ../../../pkg/darwin_amd64/cmd Change-Id: I11c7a45f74d4a9e963da15c080e1018caaa99c05 Reviewed-on: https://go-review.googlesource.com/c/go/+/279478 Trust: Russ Cox <rsc@golang.org> Run-TryBot: Russ Cox <rsc@golang.org> Reviewed-by: Matthew Dempsky <mdempsky@google.com>
2020-12-23 01:05:16 -05:00
}
}
// IsTrivialClosure reports whether closure clo has an
// empty list of captured vars.
func IsTrivialClosure(clo *ClosureExpr) bool {
return len(clo.Func.ClosureVars) == 0
}
[dev.typeparams] cmd/compile: refactor closure construction typecheck.tcClosure is complicated with many code flows because all of its callers setup the closure funcs in slightly different ways. E.g., it's non-obvious who's responsible for setting the underlying func's Sym or adding it to target.Decls, or how to write new code that constructs a closure without interfering with existing code. This CL refactors everything to use three common functions in package ir: NewClosureFunc (which handle creating the Func, Name, and ClosureExpr and wiring them together), NameClosure (which generates and assigns its unique Sym), and UseClosure (which handles adding the Func to target.Decls). Most IR builders can actually name the closure right away, but the legacy noder+typecheck path may not yet know the name of the enclosing function. In particular, for methods declared with aliased receiver parameters, we need to wait until after typechecking top-level declarations to know the method's true name. So they're left anonymous until typecheck. UseClosure does relatively little work today, but it serves as a useful spot to check that the code setting up closures got it right. It may also eventually serve as an optimization point for early lifting of trivial closures, which may or may not ultimately be beneficial. Change-Id: I7da1e93c70d268f575b12d6aaeb2336eb910a6f1 Reviewed-on: https://go-review.googlesource.com/c/go/+/327051 Trust: Matthew Dempsky <mdempsky@google.com> Run-TryBot: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
2021-06-11 03:09:26 -07:00
// globClosgen is like Func.Closgen, but for the global scope.
var globClosgen int32
// closureName generates a new unique name for a closure within outerfn at pos.
func closureName(outerfn *Func, pos src.XPos, why Op) *types.Sym {
cmd/compile: for rangefunc, add checks and tests, fix panic interactions Modify rangefunc #next protocol to make it more robust Extra-terrible nests of rangefunc iterators caused the prior implementation to misbehave non-locally (in outer loops). Add more rangefunc exit flag tests, parallel and tricky This tests the assertion that a rangefunc iterator running in parallel can trigger the race detector if any of the parallel goroutines attempts an early exit. It also verifies that if everything else is carefully written, that it does NOT trigger the race detector if all the parts run time completion. Another test tries to rerun a yield function within a loop, so that any per-line shared checking would be fooled. Added all the use-of-body/yield-function checking. These checks handle pathological cases that would cause rangefunc for loops to behave in surprising ways (compared to "regular" for loops). For example, a rangefunc iterator might defer-recover a panic thrown in the syntactic body of a loop; this notices the fault and panics with an explanation Modified closure naming to ID rangefunc bodies Add a "-range<N>" suffix to the name of any closure generated for a rangefunc loop body, as provided in Alessandro Arzilli's CL (which is merged into this one). Fix return values for panicky range functions This removes the delayed implementation of "return x" by ensuring that return values (in rangefunc-return-containing functions) always have names and translating the "return x" into "#rv1 = x" where #rv1 is the synthesized name of the first result. Updates #61405. Change-Id: I933299ecce04ceabcf1c0c2de8e610b2ecd1cfd8 Reviewed-on: https://go-review.googlesource.com/c/go/+/584596 Reviewed-by: Matthew Dempsky <mdempsky@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Tim King <taking@google.com>
2024-01-26 17:49:33 -05:00
if outerfn != nil && outerfn.OClosure != nil && outerfn.OClosure.Func.RangeParent != nil {
outerfn = outerfn.OClosure.Func.RangeParent
}
[dev.typeparams] cmd/compile: refactor closure construction typecheck.tcClosure is complicated with many code flows because all of its callers setup the closure funcs in slightly different ways. E.g., it's non-obvious who's responsible for setting the underlying func's Sym or adding it to target.Decls, or how to write new code that constructs a closure without interfering with existing code. This CL refactors everything to use three common functions in package ir: NewClosureFunc (which handle creating the Func, Name, and ClosureExpr and wiring them together), NameClosure (which generates and assigns its unique Sym), and UseClosure (which handles adding the Func to target.Decls). Most IR builders can actually name the closure right away, but the legacy noder+typecheck path may not yet know the name of the enclosing function. In particular, for methods declared with aliased receiver parameters, we need to wait until after typechecking top-level declarations to know the method's true name. So they're left anonymous until typecheck. UseClosure does relatively little work today, but it serves as a useful spot to check that the code setting up closures got it right. It may also eventually serve as an optimization point for early lifting of trivial closures, which may or may not ultimately be beneficial. Change-Id: I7da1e93c70d268f575b12d6aaeb2336eb910a6f1 Reviewed-on: https://go-review.googlesource.com/c/go/+/327051 Trust: Matthew Dempsky <mdempsky@google.com> Run-TryBot: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
2021-06-11 03:09:26 -07:00
pkg := types.LocalPkg
outer := "glob."
var suffix string = "."
switch why {
default:
base.FatalfAt(pos, "closureName: bad Op: %v", why)
case OCLOSURE:
if outerfn == nil || outerfn.OClosure == nil {
suffix = ".func"
[dev.typeparams] cmd/compile: refactor closure construction typecheck.tcClosure is complicated with many code flows because all of its callers setup the closure funcs in slightly different ways. E.g., it's non-obvious who's responsible for setting the underlying func's Sym or adding it to target.Decls, or how to write new code that constructs a closure without interfering with existing code. This CL refactors everything to use three common functions in package ir: NewClosureFunc (which handle creating the Func, Name, and ClosureExpr and wiring them together), NameClosure (which generates and assigns its unique Sym), and UseClosure (which handles adding the Func to target.Decls). Most IR builders can actually name the closure right away, but the legacy noder+typecheck path may not yet know the name of the enclosing function. In particular, for methods declared with aliased receiver parameters, we need to wait until after typechecking top-level declarations to know the method's true name. So they're left anonymous until typecheck. UseClosure does relatively little work today, but it serves as a useful spot to check that the code setting up closures got it right. It may also eventually serve as an optimization point for early lifting of trivial closures, which may or may not ultimately be beneficial. Change-Id: I7da1e93c70d268f575b12d6aaeb2336eb910a6f1 Reviewed-on: https://go-review.googlesource.com/c/go/+/327051 Trust: Matthew Dempsky <mdempsky@google.com> Run-TryBot: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
2021-06-11 03:09:26 -07:00
}
cmd/compile: for rangefunc, add checks and tests, fix panic interactions Modify rangefunc #next protocol to make it more robust Extra-terrible nests of rangefunc iterators caused the prior implementation to misbehave non-locally (in outer loops). Add more rangefunc exit flag tests, parallel and tricky This tests the assertion that a rangefunc iterator running in parallel can trigger the race detector if any of the parallel goroutines attempts an early exit. It also verifies that if everything else is carefully written, that it does NOT trigger the race detector if all the parts run time completion. Another test tries to rerun a yield function within a loop, so that any per-line shared checking would be fooled. Added all the use-of-body/yield-function checking. These checks handle pathological cases that would cause rangefunc for loops to behave in surprising ways (compared to "regular" for loops). For example, a rangefunc iterator might defer-recover a panic thrown in the syntactic body of a loop; this notices the fault and panics with an explanation Modified closure naming to ID rangefunc bodies Add a "-range<N>" suffix to the name of any closure generated for a rangefunc loop body, as provided in Alessandro Arzilli's CL (which is merged into this one). Fix return values for panicky range functions This removes the delayed implementation of "return x" by ensuring that return values (in rangefunc-return-containing functions) always have names and translating the "return x" into "#rv1 = x" where #rv1 is the synthesized name of the first result. Updates #61405. Change-Id: I933299ecce04ceabcf1c0c2de8e610b2ecd1cfd8 Reviewed-on: https://go-review.googlesource.com/c/go/+/584596 Reviewed-by: Matthew Dempsky <mdempsky@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Tim King <taking@google.com>
2024-01-26 17:49:33 -05:00
case ORANGE:
suffix = "-range"
case OGO:
suffix = ".gowrap"
case ODEFER:
suffix = ".deferwrap"
}
gen := &globClosgen
[dev.typeparams] cmd/compile: refactor closure construction typecheck.tcClosure is complicated with many code flows because all of its callers setup the closure funcs in slightly different ways. E.g., it's non-obvious who's responsible for setting the underlying func's Sym or adding it to target.Decls, or how to write new code that constructs a closure without interfering with existing code. This CL refactors everything to use three common functions in package ir: NewClosureFunc (which handle creating the Func, Name, and ClosureExpr and wiring them together), NameClosure (which generates and assigns its unique Sym), and UseClosure (which handles adding the Func to target.Decls). Most IR builders can actually name the closure right away, but the legacy noder+typecheck path may not yet know the name of the enclosing function. In particular, for methods declared with aliased receiver parameters, we need to wait until after typechecking top-level declarations to know the method's true name. So they're left anonymous until typecheck. UseClosure does relatively little work today, but it serves as a useful spot to check that the code setting up closures got it right. It may also eventually serve as an optimization point for early lifting of trivial closures, which may or may not ultimately be beneficial. Change-Id: I7da1e93c70d268f575b12d6aaeb2336eb910a6f1 Reviewed-on: https://go-review.googlesource.com/c/go/+/327051 Trust: Matthew Dempsky <mdempsky@google.com> Run-TryBot: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
2021-06-11 03:09:26 -07:00
// There may be multiple functions named "_". In those
// cases, we can't use their individual Closgens as it
// would lead to name clashes.
if outerfn != nil && !IsBlank(outerfn.Nname) {
[dev.typeparams] cmd/compile: refactor closure construction typecheck.tcClosure is complicated with many code flows because all of its callers setup the closure funcs in slightly different ways. E.g., it's non-obvious who's responsible for setting the underlying func's Sym or adding it to target.Decls, or how to write new code that constructs a closure without interfering with existing code. This CL refactors everything to use three common functions in package ir: NewClosureFunc (which handle creating the Func, Name, and ClosureExpr and wiring them together), NameClosure (which generates and assigns its unique Sym), and UseClosure (which handles adding the Func to target.Decls). Most IR builders can actually name the closure right away, but the legacy noder+typecheck path may not yet know the name of the enclosing function. In particular, for methods declared with aliased receiver parameters, we need to wait until after typechecking top-level declarations to know the method's true name. So they're left anonymous until typecheck. UseClosure does relatively little work today, but it serves as a useful spot to check that the code setting up closures got it right. It may also eventually serve as an optimization point for early lifting of trivial closures, which may or may not ultimately be beneficial. Change-Id: I7da1e93c70d268f575b12d6aaeb2336eb910a6f1 Reviewed-on: https://go-review.googlesource.com/c/go/+/327051 Trust: Matthew Dempsky <mdempsky@google.com> Run-TryBot: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
2021-06-11 03:09:26 -07:00
pkg = outerfn.Sym().Pkg
outer = FuncName(outerfn)
cmd/compile: for rangefunc, add checks and tests, fix panic interactions Modify rangefunc #next protocol to make it more robust Extra-terrible nests of rangefunc iterators caused the prior implementation to misbehave non-locally (in outer loops). Add more rangefunc exit flag tests, parallel and tricky This tests the assertion that a rangefunc iterator running in parallel can trigger the race detector if any of the parallel goroutines attempts an early exit. It also verifies that if everything else is carefully written, that it does NOT trigger the race detector if all the parts run time completion. Another test tries to rerun a yield function within a loop, so that any per-line shared checking would be fooled. Added all the use-of-body/yield-function checking. These checks handle pathological cases that would cause rangefunc for loops to behave in surprising ways (compared to "regular" for loops). For example, a rangefunc iterator might defer-recover a panic thrown in the syntactic body of a loop; this notices the fault and panics with an explanation Modified closure naming to ID rangefunc bodies Add a "-range<N>" suffix to the name of any closure generated for a rangefunc loop body, as provided in Alessandro Arzilli's CL (which is merged into this one). Fix return values for panicky range functions This removes the delayed implementation of "return x" by ensuring that return values (in rangefunc-return-containing functions) always have names and translating the "return x" into "#rv1 = x" where #rv1 is the synthesized name of the first result. Updates #61405. Change-Id: I933299ecce04ceabcf1c0c2de8e610b2ecd1cfd8 Reviewed-on: https://go-review.googlesource.com/c/go/+/584596 Reviewed-by: Matthew Dempsky <mdempsky@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Tim King <taking@google.com>
2024-01-26 17:49:33 -05:00
switch why {
case OCLOSURE:
gen = &outerfn.funcLitGen
cmd/compile: for rangefunc, add checks and tests, fix panic interactions Modify rangefunc #next protocol to make it more robust Extra-terrible nests of rangefunc iterators caused the prior implementation to misbehave non-locally (in outer loops). Add more rangefunc exit flag tests, parallel and tricky This tests the assertion that a rangefunc iterator running in parallel can trigger the race detector if any of the parallel goroutines attempts an early exit. It also verifies that if everything else is carefully written, that it does NOT trigger the race detector if all the parts run time completion. Another test tries to rerun a yield function within a loop, so that any per-line shared checking would be fooled. Added all the use-of-body/yield-function checking. These checks handle pathological cases that would cause rangefunc for loops to behave in surprising ways (compared to "regular" for loops). For example, a rangefunc iterator might defer-recover a panic thrown in the syntactic body of a loop; this notices the fault and panics with an explanation Modified closure naming to ID rangefunc bodies Add a "-range<N>" suffix to the name of any closure generated for a rangefunc loop body, as provided in Alessandro Arzilli's CL (which is merged into this one). Fix return values for panicky range functions This removes the delayed implementation of "return x" by ensuring that return values (in rangefunc-return-containing functions) always have names and translating the "return x" into "#rv1 = x" where #rv1 is the synthesized name of the first result. Updates #61405. Change-Id: I933299ecce04ceabcf1c0c2de8e610b2ecd1cfd8 Reviewed-on: https://go-review.googlesource.com/c/go/+/584596 Reviewed-by: Matthew Dempsky <mdempsky@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Tim King <taking@google.com>
2024-01-26 17:49:33 -05:00
case ORANGE:
gen = &outerfn.rangeLitGen
default:
gen = &outerfn.goDeferGen
[dev.typeparams] cmd/compile: refactor closure construction typecheck.tcClosure is complicated with many code flows because all of its callers setup the closure funcs in slightly different ways. E.g., it's non-obvious who's responsible for setting the underlying func's Sym or adding it to target.Decls, or how to write new code that constructs a closure without interfering with existing code. This CL refactors everything to use three common functions in package ir: NewClosureFunc (which handle creating the Func, Name, and ClosureExpr and wiring them together), NameClosure (which generates and assigns its unique Sym), and UseClosure (which handles adding the Func to target.Decls). Most IR builders can actually name the closure right away, but the legacy noder+typecheck path may not yet know the name of the enclosing function. In particular, for methods declared with aliased receiver parameters, we need to wait until after typechecking top-level declarations to know the method's true name. So they're left anonymous until typecheck. UseClosure does relatively little work today, but it serves as a useful spot to check that the code setting up closures got it right. It may also eventually serve as an optimization point for early lifting of trivial closures, which may or may not ultimately be beneficial. Change-Id: I7da1e93c70d268f575b12d6aaeb2336eb910a6f1 Reviewed-on: https://go-review.googlesource.com/c/go/+/327051 Trust: Matthew Dempsky <mdempsky@google.com> Run-TryBot: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
2021-06-11 03:09:26 -07:00
}
}
// If this closure was created due to inlining, then incorporate any
// inlined functions' names into the closure's linker symbol name
// too (#60324).
if inlIndex := base.Ctxt.InnermostPos(pos).Base().InliningIndex(); inlIndex >= 0 {
names := []string{outer}
base.Ctxt.InlTree.AllParents(inlIndex, func(call obj.InlinedCall) {
names = append(names, call.Name)
})
outer = strings.Join(names, ".")
}
[dev.typeparams] cmd/compile: refactor closure construction typecheck.tcClosure is complicated with many code flows because all of its callers setup the closure funcs in slightly different ways. E.g., it's non-obvious who's responsible for setting the underlying func's Sym or adding it to target.Decls, or how to write new code that constructs a closure without interfering with existing code. This CL refactors everything to use three common functions in package ir: NewClosureFunc (which handle creating the Func, Name, and ClosureExpr and wiring them together), NameClosure (which generates and assigns its unique Sym), and UseClosure (which handles adding the Func to target.Decls). Most IR builders can actually name the closure right away, but the legacy noder+typecheck path may not yet know the name of the enclosing function. In particular, for methods declared with aliased receiver parameters, we need to wait until after typechecking top-level declarations to know the method's true name. So they're left anonymous until typecheck. UseClosure does relatively little work today, but it serves as a useful spot to check that the code setting up closures got it right. It may also eventually serve as an optimization point for early lifting of trivial closures, which may or may not ultimately be beneficial. Change-Id: I7da1e93c70d268f575b12d6aaeb2336eb910a6f1 Reviewed-on: https://go-review.googlesource.com/c/go/+/327051 Trust: Matthew Dempsky <mdempsky@google.com> Run-TryBot: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
2021-06-11 03:09:26 -07:00
*gen++
return pkg.Lookup(fmt.Sprintf("%s%s%d", outer, suffix, *gen))
[dev.typeparams] cmd/compile: refactor closure construction typecheck.tcClosure is complicated with many code flows because all of its callers setup the closure funcs in slightly different ways. E.g., it's non-obvious who's responsible for setting the underlying func's Sym or adding it to target.Decls, or how to write new code that constructs a closure without interfering with existing code. This CL refactors everything to use three common functions in package ir: NewClosureFunc (which handle creating the Func, Name, and ClosureExpr and wiring them together), NameClosure (which generates and assigns its unique Sym), and UseClosure (which handles adding the Func to target.Decls). Most IR builders can actually name the closure right away, but the legacy noder+typecheck path may not yet know the name of the enclosing function. In particular, for methods declared with aliased receiver parameters, we need to wait until after typechecking top-level declarations to know the method's true name. So they're left anonymous until typecheck. UseClosure does relatively little work today, but it serves as a useful spot to check that the code setting up closures got it right. It may also eventually serve as an optimization point for early lifting of trivial closures, which may or may not ultimately be beneficial. Change-Id: I7da1e93c70d268f575b12d6aaeb2336eb910a6f1 Reviewed-on: https://go-review.googlesource.com/c/go/+/327051 Trust: Matthew Dempsky <mdempsky@google.com> Run-TryBot: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
2021-06-11 03:09:26 -07:00
}
// NewClosureFunc creates a new Func to represent a function literal
// with the given type.
//
// fpos the position used for the underlying ODCLFUNC and ONAME,
// whereas cpos is the position used for the OCLOSURE. They're
// separate because in the presence of inlining, the OCLOSURE node
// should have an inline-adjusted position, whereas the ODCLFUNC and
// ONAME must not.
//
// outerfn is the enclosing function, if any. The returned function is
// appending to pkg.Funcs.
//
// why is the reason we're generating this Func. It can be OCLOSURE
// (for a normal function literal) or OGO or ODEFER (for wrapping a
// call expression that has parameters or results).
func NewClosureFunc(fpos, cpos src.XPos, why Op, typ *types.Type, outerfn *Func, pkg *Package) *Func {
fn := NewFunc(fpos, fpos, closureName(outerfn, cpos, why), typ)
fn.SetIsHiddenClosure(outerfn != nil)
if outerfn != nil {
fn.SetDupok(outerfn.Dupok()) // if the outer function is dupok, so is the closure
}
[dev.typeparams] cmd/compile: refactor closure construction typecheck.tcClosure is complicated with many code flows because all of its callers setup the closure funcs in slightly different ways. E.g., it's non-obvious who's responsible for setting the underlying func's Sym or adding it to target.Decls, or how to write new code that constructs a closure without interfering with existing code. This CL refactors everything to use three common functions in package ir: NewClosureFunc (which handle creating the Func, Name, and ClosureExpr and wiring them together), NameClosure (which generates and assigns its unique Sym), and UseClosure (which handles adding the Func to target.Decls). Most IR builders can actually name the closure right away, but the legacy noder+typecheck path may not yet know the name of the enclosing function. In particular, for methods declared with aliased receiver parameters, we need to wait until after typechecking top-level declarations to know the method's true name. So they're left anonymous until typecheck. UseClosure does relatively little work today, but it serves as a useful spot to check that the code setting up closures got it right. It may also eventually serve as an optimization point for early lifting of trivial closures, which may or may not ultimately be beneficial. Change-Id: I7da1e93c70d268f575b12d6aaeb2336eb910a6f1 Reviewed-on: https://go-review.googlesource.com/c/go/+/327051 Trust: Matthew Dempsky <mdempsky@google.com> Run-TryBot: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
2021-06-11 03:09:26 -07:00
clo := &ClosureExpr{Func: fn}
clo.op = OCLOSURE
clo.pos = cpos
clo.SetType(typ)
clo.SetTypecheck(1)
cmd/compile: for rangefunc, add checks and tests, fix panic interactions Modify rangefunc #next protocol to make it more robust Extra-terrible nests of rangefunc iterators caused the prior implementation to misbehave non-locally (in outer loops). Add more rangefunc exit flag tests, parallel and tricky This tests the assertion that a rangefunc iterator running in parallel can trigger the race detector if any of the parallel goroutines attempts an early exit. It also verifies that if everything else is carefully written, that it does NOT trigger the race detector if all the parts run time completion. Another test tries to rerun a yield function within a loop, so that any per-line shared checking would be fooled. Added all the use-of-body/yield-function checking. These checks handle pathological cases that would cause rangefunc for loops to behave in surprising ways (compared to "regular" for loops). For example, a rangefunc iterator might defer-recover a panic thrown in the syntactic body of a loop; this notices the fault and panics with an explanation Modified closure naming to ID rangefunc bodies Add a "-range<N>" suffix to the name of any closure generated for a rangefunc loop body, as provided in Alessandro Arzilli's CL (which is merged into this one). Fix return values for panicky range functions This removes the delayed implementation of "return x" by ensuring that return values (in rangefunc-return-containing functions) always have names and translating the "return x" into "#rv1 = x" where #rv1 is the synthesized name of the first result. Updates #61405. Change-Id: I933299ecce04ceabcf1c0c2de8e610b2ecd1cfd8 Reviewed-on: https://go-review.googlesource.com/c/go/+/584596 Reviewed-by: Matthew Dempsky <mdempsky@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Tim King <taking@google.com>
2024-01-26 17:49:33 -05:00
if why == ORANGE {
clo.Func.RangeParent = outerfn
if outerfn.OClosure != nil && outerfn.OClosure.Func.RangeParent != nil {
clo.Func.RangeParent = outerfn.OClosure.Func.RangeParent
}
}
fn.OClosure = clo
[dev.typeparams] cmd/compile: refactor closure construction typecheck.tcClosure is complicated with many code flows because all of its callers setup the closure funcs in slightly different ways. E.g., it's non-obvious who's responsible for setting the underlying func's Sym or adding it to target.Decls, or how to write new code that constructs a closure without interfering with existing code. This CL refactors everything to use three common functions in package ir: NewClosureFunc (which handle creating the Func, Name, and ClosureExpr and wiring them together), NameClosure (which generates and assigns its unique Sym), and UseClosure (which handles adding the Func to target.Decls). Most IR builders can actually name the closure right away, but the legacy noder+typecheck path may not yet know the name of the enclosing function. In particular, for methods declared with aliased receiver parameters, we need to wait until after typechecking top-level declarations to know the method's true name. So they're left anonymous until typecheck. UseClosure does relatively little work today, but it serves as a useful spot to check that the code setting up closures got it right. It may also eventually serve as an optimization point for early lifting of trivial closures, which may or may not ultimately be beneficial. Change-Id: I7da1e93c70d268f575b12d6aaeb2336eb910a6f1 Reviewed-on: https://go-review.googlesource.com/c/go/+/327051 Trust: Matthew Dempsky <mdempsky@google.com> Run-TryBot: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
2021-06-11 03:09:26 -07:00
fn.Nname.Defn = fn
pkg.Funcs = append(pkg.Funcs, fn)
[dev.typeparams] cmd/compile: refactor closure construction typecheck.tcClosure is complicated with many code flows because all of its callers setup the closure funcs in slightly different ways. E.g., it's non-obvious who's responsible for setting the underlying func's Sym or adding it to target.Decls, or how to write new code that constructs a closure without interfering with existing code. This CL refactors everything to use three common functions in package ir: NewClosureFunc (which handle creating the Func, Name, and ClosureExpr and wiring them together), NameClosure (which generates and assigns its unique Sym), and UseClosure (which handles adding the Func to target.Decls). Most IR builders can actually name the closure right away, but the legacy noder+typecheck path may not yet know the name of the enclosing function. In particular, for methods declared with aliased receiver parameters, we need to wait until after typechecking top-level declarations to know the method's true name. So they're left anonymous until typecheck. UseClosure does relatively little work today, but it serves as a useful spot to check that the code setting up closures got it right. It may also eventually serve as an optimization point for early lifting of trivial closures, which may or may not ultimately be beneficial. Change-Id: I7da1e93c70d268f575b12d6aaeb2336eb910a6f1 Reviewed-on: https://go-review.googlesource.com/c/go/+/327051 Trust: Matthew Dempsky <mdempsky@google.com> Run-TryBot: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
2021-06-11 03:09:26 -07:00
return fn
[dev.typeparams] cmd/compile: refactor closure construction typecheck.tcClosure is complicated with many code flows because all of its callers setup the closure funcs in slightly different ways. E.g., it's non-obvious who's responsible for setting the underlying func's Sym or adding it to target.Decls, or how to write new code that constructs a closure without interfering with existing code. This CL refactors everything to use three common functions in package ir: NewClosureFunc (which handle creating the Func, Name, and ClosureExpr and wiring them together), NameClosure (which generates and assigns its unique Sym), and UseClosure (which handles adding the Func to target.Decls). Most IR builders can actually name the closure right away, but the legacy noder+typecheck path may not yet know the name of the enclosing function. In particular, for methods declared with aliased receiver parameters, we need to wait until after typechecking top-level declarations to know the method's true name. So they're left anonymous until typecheck. UseClosure does relatively little work today, but it serves as a useful spot to check that the code setting up closures got it right. It may also eventually serve as an optimization point for early lifting of trivial closures, which may or may not ultimately be beneficial. Change-Id: I7da1e93c70d268f575b12d6aaeb2336eb910a6f1 Reviewed-on: https://go-review.googlesource.com/c/go/+/327051 Trust: Matthew Dempsky <mdempsky@google.com> Run-TryBot: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
2021-06-11 03:09:26 -07:00
}
cmd/compile/internal/staticinit: make staticopy safe Currently, cmd/compile optimizes `var a = true; var b = a` into `var a = true; var b = true`. But this may not be safe if we need to initialize any other global variables between `a` and `b`, and the initialization involves calling a user-defined function that reassigns `a`. This CL changes staticinit to keep track of the initialization expressions that we've seen so far, and to stop applying the staticcopy optimization once we've seen an initialization expression that might have modified another global variable within this package. To help identify affected initializers, this CL adds a -d=staticcopy flag to warn when a staticcopy is suppressed and turned into a dynamic copy. Currently, `go build -gcflags=all=-d=staticcopy std` reports only four instances: ``` encoding/xml/xml.go:1600:5: skipping static copy of HTMLEntity+0 with map[string]string{...} encoding/xml/xml.go:1869:5: skipping static copy of HTMLAutoClose+0 with []string{...} net/net.go:661:5: skipping static copy of .stmp_31+0 with poll.ErrNetClosing net/http/transport.go:2566:5: skipping static copy of errRequestCanceled+0 with ~R0 ``` Fixes #51913. Change-Id: Iab41cf6f84c44f7f960e4e62c28a8aeaade4fbcf Reviewed-on: https://go-review.googlesource.com/c/go/+/395541 Auto-Submit: Matthew Dempsky <mdempsky@google.com> Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com> Reviewed-by: David Chase <drchase@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Heschi Kreinick <heschi@google.com>
2022-03-24 12:27:39 -07:00
// IsFuncPCIntrinsic returns whether n is a direct call of internal/abi.FuncPCABIxxx functions.
func IsFuncPCIntrinsic(n *CallExpr) bool {
if n.Op() != OCALLFUNC || n.Fun.Op() != ONAME {
cmd/compile/internal/staticinit: make staticopy safe Currently, cmd/compile optimizes `var a = true; var b = a` into `var a = true; var b = true`. But this may not be safe if we need to initialize any other global variables between `a` and `b`, and the initialization involves calling a user-defined function that reassigns `a`. This CL changes staticinit to keep track of the initialization expressions that we've seen so far, and to stop applying the staticcopy optimization once we've seen an initialization expression that might have modified another global variable within this package. To help identify affected initializers, this CL adds a -d=staticcopy flag to warn when a staticcopy is suppressed and turned into a dynamic copy. Currently, `go build -gcflags=all=-d=staticcopy std` reports only four instances: ``` encoding/xml/xml.go:1600:5: skipping static copy of HTMLEntity+0 with map[string]string{...} encoding/xml/xml.go:1869:5: skipping static copy of HTMLAutoClose+0 with []string{...} net/net.go:661:5: skipping static copy of .stmp_31+0 with poll.ErrNetClosing net/http/transport.go:2566:5: skipping static copy of errRequestCanceled+0 with ~R0 ``` Fixes #51913. Change-Id: Iab41cf6f84c44f7f960e4e62c28a8aeaade4fbcf Reviewed-on: https://go-review.googlesource.com/c/go/+/395541 Auto-Submit: Matthew Dempsky <mdempsky@google.com> Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com> Reviewed-by: David Chase <drchase@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Heschi Kreinick <heschi@google.com>
2022-03-24 12:27:39 -07:00
return false
}
fn := n.Fun.(*Name).Sym()
cmd/compile/internal/staticinit: make staticopy safe Currently, cmd/compile optimizes `var a = true; var b = a` into `var a = true; var b = true`. But this may not be safe if we need to initialize any other global variables between `a` and `b`, and the initialization involves calling a user-defined function that reassigns `a`. This CL changes staticinit to keep track of the initialization expressions that we've seen so far, and to stop applying the staticcopy optimization once we've seen an initialization expression that might have modified another global variable within this package. To help identify affected initializers, this CL adds a -d=staticcopy flag to warn when a staticcopy is suppressed and turned into a dynamic copy. Currently, `go build -gcflags=all=-d=staticcopy std` reports only four instances: ``` encoding/xml/xml.go:1600:5: skipping static copy of HTMLEntity+0 with map[string]string{...} encoding/xml/xml.go:1869:5: skipping static copy of HTMLAutoClose+0 with []string{...} net/net.go:661:5: skipping static copy of .stmp_31+0 with poll.ErrNetClosing net/http/transport.go:2566:5: skipping static copy of errRequestCanceled+0 with ~R0 ``` Fixes #51913. Change-Id: Iab41cf6f84c44f7f960e4e62c28a8aeaade4fbcf Reviewed-on: https://go-review.googlesource.com/c/go/+/395541 Auto-Submit: Matthew Dempsky <mdempsky@google.com> Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com> Reviewed-by: David Chase <drchase@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Heschi Kreinick <heschi@google.com>
2022-03-24 12:27:39 -07:00
return (fn.Name == "FuncPCABI0" || fn.Name == "FuncPCABIInternal") &&
fn.Pkg.Path == "internal/abi"
}
// IsIfaceOfFunc inspects whether n is an interface conversion from a direct
// reference of a func. If so, it returns referenced Func; otherwise nil.
//
// This is only usable before walk.walkConvertInterface, which converts to an
// OMAKEFACE.
func IsIfaceOfFunc(n Node) *Func {
if n, ok := n.(*ConvExpr); ok && n.Op() == OCONVIFACE {
if name, ok := n.X.(*Name); ok && name.Op() == ONAME && name.Class == PFUNC {
return name.Func
}
}
return nil
}
// FuncPC returns a uintptr-typed expression that evaluates to the PC of a
// function as uintptr, as returned by internal/abi.FuncPC{ABI0,ABIInternal}.
//
// n should be a Node of an interface type, as is passed to
// internal/abi.FuncPC{ABI0,ABIInternal}.
//
// TODO(prattmic): Since n is simply an interface{} there is no assertion that
// it is actually a function at all. Perhaps we should emit a runtime type
// assertion?
func FuncPC(pos src.XPos, n Node, wantABI obj.ABI) Node {
if !n.Type().IsInterface() {
base.ErrorfAt(pos, 0, "internal/abi.FuncPC%s expects an interface value, got %v", wantABI, n.Type())
}
if fn := IsIfaceOfFunc(n); fn != nil {
name := fn.Nname
abi := fn.ABI
if abi != wantABI {
base.ErrorfAt(pos, 0, "internal/abi.FuncPC%s expects an %v function, %s is defined as %v", wantABI, wantABI, name.Sym().Name, abi)
}
var e Node = NewLinksymExpr(pos, name.LinksymABI(abi), types.Types[types.TUINTPTR])
e = NewAddrExpr(pos, e)
e.SetType(types.Types[types.TUINTPTR].PtrTo())
e = NewConvExpr(pos, OCONVNOP, types.Types[types.TUINTPTR], e)
e.SetTypecheck(1)
return e
}
// fn is not a defined function. It must be ABIInternal.
// Read the address from func value, i.e. *(*uintptr)(idata(fn)).
if wantABI != obj.ABIInternal {
base.ErrorfAt(pos, 0, "internal/abi.FuncPC%s does not accept func expression, which is ABIInternal", wantABI)
}
var e Node = NewUnaryExpr(pos, OIDATA, n)
e.SetType(types.Types[types.TUINTPTR].PtrTo())
e.SetTypecheck(1)
e = NewStarExpr(pos, e)
e.SetType(types.Types[types.TUINTPTR])
e.SetTypecheck(1)
return e
}
// DeclareParams creates Names for all of the parameters in fn's
// signature and adds them to fn.Dcl.
//
// If setNname is true, then it also sets types.Field.Nname for each
// parameter.
func (fn *Func) DeclareParams(setNname bool) {
if fn.Dcl != nil {
base.FatalfAt(fn.Pos(), "%v already has Dcl", fn)
}
declareParams := func(params []*types.Field, ctxt Class, prefix string, offset int) {
for i, param := range params {
sym := param.Sym
if sym == nil || sym.IsBlank() {
sym = fn.Sym().Pkg.LookupNum(prefix, i)
}
name := NewNameAt(param.Pos, sym, param.Type)
name.Class = ctxt
name.Curfn = fn
fn.Dcl[offset+i] = name
if setNname {
param.Nname = name
}
}
}
sig := fn.Type()
params := sig.RecvParams()
results := sig.Results()
fn.Dcl = make([]*Name, len(params)+len(results))
declareParams(params, PPARAM, "~p", 0)
declareParams(results, PPARAMOUT, "~r", len(params))
}