// call evaluates a call expressions, including builtin calls. ks
// should contain the holes representing where the function callee's
-// results flows; where is the OGO/ODEFER context of the call, if any.
-func (e *escape) call(ks []hole, call, where ir.Node) {
- topLevelDefer := where != nil && where.Op() == ir.ODEFER && e.loopDepth == 1
- if topLevelDefer {
- // force stack allocation of defer record, unless
- // open-coded defers are used (see ssa.go)
- where.SetEsc(ir.EscNever)
- }
+// results flows.
+func (e *escape) call(ks []hole, call ir.Node) {
+ e.callCommon(ks, call, nil)
+}
- argument := func(k hole, arg ir.Node) {
- if topLevelDefer {
- // Top level defers arguments don't escape to
- // heap, but they do need to last until end of
- // function.
- k = e.later(k)
- } else if where != nil {
- k = e.heapHole()
+func (e *escape) callCommon(ks []hole, call ir.Node, where *ir.GoDeferStmt) {
+ argument := func(k hole, argp *ir.Node) {
+ if where != nil {
+ if where.Esc() == ir.EscNever {
+ // Top-level defers arguments don't escape to heap,
+ // but they do need to last until end of function.
+ k = e.later(k)
+ } else {
+ k = e.heapHole()
+ }
}
- e.expr(k.note(call, "call parameter"), arg)
+ e.expr(k.note(call, "call parameter"), *argp)
}
switch call.Op() {
}
if r := fntype.Recv(); r != nil {
- argument(e.tagHole(ks, fn, r), call.X.(*ir.SelectorExpr).X)
+ argument(e.tagHole(ks, fn, r), &call.X.(*ir.SelectorExpr).X)
} else {
// Evaluate callee function expression.
- argument(e.discardHole(), call.X)
+ argument(e.discardHole(), &call.X)
}
args := call.Args
for i, param := range fntype.Params().FieldSlice() {
- argument(e.tagHole(ks, fn, param), args[i])
+ argument(e.tagHole(ks, fn, param), &args[i])
}
case ir.OAPPEND:
if args[0].Type().Elem().HasPointers() {
appendeeK = e.teeHole(appendeeK, e.heapHole().deref(call, "appendee slice"))
}
- argument(appendeeK, args[0])
+ argument(appendeeK, &args[0])
if call.IsDDD {
appendedK := e.discardHole()
if args[1].Type().IsSlice() && args[1].Type().Elem().HasPointers() {
appendedK = e.heapHole().deref(call, "appended slice...")
}
- argument(appendedK, args[1])
+ argument(appendedK, &args[1])
} else {
- for _, arg := range args[1:] {
- argument(e.heapHole(), arg)
+ for i := 1; i < len(args); i++ {
+ argument(e.heapHole(), &args[i])
}
}
case ir.OCOPY:
call := call.(*ir.BinaryExpr)
- argument(e.discardHole(), call.X)
+ argument(e.discardHole(), &call.X)
copiedK := e.discardHole()
if call.Y.Type().IsSlice() && call.Y.Type().Elem().HasPointers() {
copiedK = e.heapHole().deref(call, "copied slice")
}
- argument(copiedK, call.Y)
+ argument(copiedK, &call.Y)
case ir.OPANIC:
call := call.(*ir.UnaryExpr)
- argument(e.heapHole(), call.X)
+ argument(e.heapHole(), &call.X)
case ir.OCOMPLEX:
call := call.(*ir.BinaryExpr)
- argument(e.discardHole(), call.X)
- argument(e.discardHole(), call.Y)
+ argument(e.discardHole(), &call.X)
+ argument(e.discardHole(), &call.Y)
case ir.ODELETE, ir.OPRINT, ir.OPRINTN, ir.ORECOVER:
call := call.(*ir.CallExpr)
- for _, arg := range call.Args {
- argument(e.discardHole(), arg)
+ for i := range call.Args {
+ argument(e.discardHole(), &call.Args[i])
}
case ir.OLEN, ir.OCAP, ir.OREAL, ir.OIMAG, ir.OCLOSE:
call := call.(*ir.UnaryExpr)
- argument(e.discardHole(), call.X)
+ argument(e.discardHole(), &call.X)
case ir.OUNSAFEADD, ir.OUNSAFESLICE:
call := call.(*ir.BinaryExpr)
- argument(ks[0], call.X)
- argument(e.discardHole(), call.Y)
+ argument(ks[0], &call.X)
+ argument(e.discardHole(), &call.Y)
}
}
+func (e *escape) goDeferStmt(n *ir.GoDeferStmt) {
+ topLevelDefer := n.Op() == ir.ODEFER && e.loopDepth == 1
+ if topLevelDefer {
+ // force stack allocation of defer record, unless
+ // open-coded defers are used (see ssa.go)
+ n.SetEsc(ir.EscNever)
+ }
+
+ e.stmts(n.Call.Init())
+ e.callCommon(nil, n.Call, n)
+}
+
// tagHole returns a hole for evaluating an argument passed to param.
// ks should contain the holes representing where the function
// callee's results flows. fn is the statically-known callee function,