mirror of
https://github.com/golang/go
synced 2024-11-26 07:38:00 -07:00
[dev.regabi] cmd/compile: bind closure vars during SSA constructions
For function literals that aren't inlined or directly called, we need to pass their arguments via a closure struct. This also means we need to rewrite uses of closure variables to access from this closure struct. Currently we do this rewrite in a pass before walking begins. This CL moves the code to SSA construction instead, alongside binding other input parameters. Change-Id: I13538ef3394e2d6f75d5b7b2d0adbb00db812dc2 Reviewed-on: https://go-review.googlesource.com/c/go/+/281352 Run-TryBot: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Go Bot <gobot@golang.org> Trust: Matthew Dempsky <mdempsky@google.com> Reviewed-by: Keith Randall <khr@golang.org>
This commit is contained in:
parent
8b2efa990b
commit
950cf4d46c
@ -470,6 +470,47 @@ func buildssa(fn *ir.Func, worker int) *ssa.Func {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Populate closure variables.
|
||||||
|
if !fn.ClosureCalled() {
|
||||||
|
clo := s.entryNewValue0(ssa.OpGetClosurePtr, s.f.Config.Types.BytePtr)
|
||||||
|
offset := int64(types.PtrSize) // PtrSize to skip past function entry PC field
|
||||||
|
for _, n := range fn.ClosureVars {
|
||||||
|
typ := n.Type()
|
||||||
|
if !n.Byval() {
|
||||||
|
typ = types.NewPtr(typ)
|
||||||
|
}
|
||||||
|
|
||||||
|
offset = types.Rnd(offset, typ.Alignment())
|
||||||
|
r := s.newValue1I(ssa.OpOffPtr, types.NewPtr(typ), offset, clo)
|
||||||
|
offset += typ.Size()
|
||||||
|
|
||||||
|
if n.Byval() && TypeOK(n.Type()) {
|
||||||
|
// If it is a small variable captured by value, downgrade it to PAUTO.
|
||||||
|
r = s.load(n.Type(), r)
|
||||||
|
|
||||||
|
n.Class = ir.PAUTO
|
||||||
|
} else {
|
||||||
|
if !n.Byval() {
|
||||||
|
r = s.load(typ, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Declare variable holding address taken from closure.
|
||||||
|
addr := ir.NewNameAt(fn.Pos(), &types.Sym{Name: "&" + n.Sym().Name, Pkg: types.LocalPkg})
|
||||||
|
addr.SetType(types.NewPtr(n.Type()))
|
||||||
|
addr.Class = ir.PAUTO
|
||||||
|
addr.SetUsed(true)
|
||||||
|
addr.Curfn = fn
|
||||||
|
types.CalcSize(addr.Type())
|
||||||
|
|
||||||
|
n.Heapaddr = addr
|
||||||
|
n = addr
|
||||||
|
}
|
||||||
|
|
||||||
|
fn.Dcl = append(fn.Dcl, n)
|
||||||
|
s.assign(n, r, false, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Convert the AST-based IR to the SSA-based IR
|
// Convert the AST-based IR to the SSA-based IR
|
||||||
s.stmtList(fn.Enter)
|
s.stmtList(fn.Enter)
|
||||||
s.stmtList(fn.Body)
|
s.stmtList(fn.Body)
|
||||||
|
@ -15,10 +15,19 @@ import (
|
|||||||
// Closure is called in a separate phase after escape analysis.
|
// Closure is called in a separate phase after escape analysis.
|
||||||
// It transform closure bodies to properly reference captured variables.
|
// It transform closure bodies to properly reference captured variables.
|
||||||
func Closure(fn *ir.Func) {
|
func Closure(fn *ir.Func) {
|
||||||
|
if len(fn.ClosureVars) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !fn.ClosureCalled() {
|
||||||
|
// The closure is not directly called, so it is going to stay as closure.
|
||||||
|
fn.SetNeedctxt(true)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
lno := base.Pos
|
lno := base.Pos
|
||||||
base.Pos = fn.Pos()
|
base.Pos = fn.Pos()
|
||||||
|
|
||||||
if fn.ClosureCalled() {
|
|
||||||
// If the closure is directly called, we transform it to a plain function call
|
// If the closure is directly called, we transform it to a plain function call
|
||||||
// with variables passed as args. This avoids allocation of a closure object.
|
// with variables passed as args. This avoids allocation of a closure object.
|
||||||
// Here we do only a part of the transformation. Walk of OCALLFUNC(OCLOSURE)
|
// Here we do only a part of the transformation. Walk of OCALLFUNC(OCLOSURE)
|
||||||
@ -60,57 +69,9 @@ func Closure(fn *ir.Func) {
|
|||||||
params = append(params, fld)
|
params = append(params, fld)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(params) > 0 {
|
|
||||||
// Prepend params and decls.
|
// Prepend params and decls.
|
||||||
f.Type().Params().SetFields(append(params, f.Type().Params().FieldSlice()...))
|
f.Type().Params().SetFields(append(params, f.Type().Params().FieldSlice()...))
|
||||||
fn.Dcl = append(decls, fn.Dcl...)
|
fn.Dcl = append(decls, fn.Dcl...)
|
||||||
}
|
|
||||||
|
|
||||||
types.CalcSize(f.Type())
|
|
||||||
fn.Nname.SetType(f.Type()) // update type of ODCLFUNC
|
|
||||||
} else {
|
|
||||||
// The closure is not called, so it is going to stay as closure.
|
|
||||||
var body []ir.Node
|
|
||||||
offset := int64(types.PtrSize)
|
|
||||||
for _, v := range fn.ClosureVars {
|
|
||||||
// cv refers to the field inside of closure OSTRUCTLIT.
|
|
||||||
typ := v.Type()
|
|
||||||
if !v.Byval() {
|
|
||||||
typ = types.NewPtr(typ)
|
|
||||||
}
|
|
||||||
offset = types.Rnd(offset, int64(typ.Align))
|
|
||||||
cr := ir.NewClosureRead(typ, offset)
|
|
||||||
offset += typ.Width
|
|
||||||
|
|
||||||
if v.Byval() && v.Type().Width <= int64(2*types.PtrSize) {
|
|
||||||
// If it is a small variable captured by value, downgrade it to PAUTO.
|
|
||||||
v.Class = ir.PAUTO
|
|
||||||
fn.Dcl = append(fn.Dcl, v)
|
|
||||||
body = append(body, ir.NewAssignStmt(base.Pos, v, cr))
|
|
||||||
} else {
|
|
||||||
// Declare variable holding addresses taken from closure
|
|
||||||
// and initialize in entry prologue.
|
|
||||||
addr := typecheck.NewName(typecheck.Lookup("&" + v.Sym().Name))
|
|
||||||
addr.SetType(types.NewPtr(v.Type()))
|
|
||||||
addr.Class = ir.PAUTO
|
|
||||||
addr.SetUsed(true)
|
|
||||||
addr.Curfn = fn
|
|
||||||
fn.Dcl = append(fn.Dcl, addr)
|
|
||||||
v.Heapaddr = addr
|
|
||||||
var src ir.Node = cr
|
|
||||||
if v.Byval() {
|
|
||||||
src = typecheck.NodAddr(cr)
|
|
||||||
}
|
|
||||||
body = append(body, ir.NewAssignStmt(base.Pos, addr, src))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(body) > 0 {
|
|
||||||
typecheck.Stmts(body)
|
|
||||||
fn.Enter = body
|
|
||||||
fn.SetNeedctxt(true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
base.Pos = lno
|
base.Pos = lno
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user