func getParam(n *ir.CallExpr, i int) *types.Field {
t := n.X.Type()
if n.Op() == ir.OCALLMETH {
- if i == 0 {
- return t.Recv()
- }
- return t.Params().Field(i - 1)
+ base.Fatalf("OCALLMETH missed by walkCall")
}
return t.Params().Field(i)
}
}
fallthrough
- case ir.OCALLMETH, ir.OCALLINTER:
+ case ir.OCALLINTER:
n := n.(*ir.CallExpr)
s.callResult(n, callNormal)
if n.Op() == ir.OCALLFUNC && n.X.Op() == ir.ONAME && n.X.(*ir.Name).Class_ == ir.PFUNC {
opendefer.closure = closure
}
} else if n.Op() == ir.OCALLMETH {
- if fn.Op() != ir.ODOTMETH {
- base.Fatalf("OCALLMETH: n.Left not an ODOTMETH: %v", fn)
- }
- fn := fn.(*ir.SelectorExpr)
- closureVal := s.getMethodClosure(fn)
- // We must always store the function value in a stack slot for the
- // runtime panic code to use. But in the defer exit code, we will
- // call the method directly.
- closure := s.openDeferSave(nil, fn.Type(), closureVal)
- opendefer.closureNode = closure.Aux.(*ir.Name)
+ base.Fatalf("OCALLMETH missed by walkCall")
} else {
if fn.Op() != ir.ODOTINTER {
base.Fatalf("OCALLINTER: n.Left not an ODOTINTER: %v", fn.Op())
s.maybeNilCheckClosure(closure, k)
}
case ir.OCALLMETH:
- if fn.Op() != ir.ODOTMETH {
- s.Fatalf("OCALLMETH: n.Left not an ODOTMETH: %v", fn)
- }
- fn := fn.(*ir.SelectorExpr)
- testLateExpansion = k != callDeferStack && ssa.LateCallExpansionEnabledWithin(s.f)
- if k == callNormal {
- sym = fn.Sel
- break
- }
- closure = s.getMethodClosure(fn)
- // Note: receiver is already present in n.Rlist, so we don't
- // want to set it here.
+ base.Fatalf("OCALLMETH missed by walkCall")
case ir.OCALLINTER:
if fn.Op() != ir.ODOTINTER {
s.Fatalf("OCALLINTER: n.Left not an ODOTINTER: %v", fn.Op())
}
// Set receiver (for method calls).
if n.Op() == ir.OCALLMETH {
- f := ft.Recv()
- s.storeArgWithBase(args[0], f.Type, addr, off+f.Offset)
- args = args[1:]
+ base.Fatalf("OCALLMETH missed by walkCall")
}
// Set other args.
for _, f := range ft.Params().Fields().Slice() {
t := n.X.Type()
args := n.Rargs
if n.Op() == ir.OCALLMETH {
- f := t.Recv()
- ACArg, arg := s.putArg(args[0], f.Type, argStart+f.Offset, testLateExpansion)
- ACArgs = append(ACArgs, ACArg)
- callArgs = append(callArgs, arg)
- args = args[1:]
+ base.Fatalf("OCALLMETH missed by walkCall")
}
for i, n := range args {
f := t.Params().Field(i)
}
}
-// getMethodClosure returns a value representing the closure for a method call
-func (s *state) getMethodClosure(fn *ir.SelectorExpr) *ssa.Value {
- // Make a name n2 for the function.
- // fn.Sym might be sync.(*Mutex).Unlock.
- // Make a PFUNC node out of that, then evaluate it.
- // We get back an SSA value representing &sync.(*Mutex).UnlockĀ·f.
- // We can then pass that to defer or go.
- n2 := ir.NewNameAt(fn.Pos(), fn.Sel)
- n2.Curfn = s.curfn
- n2.Class_ = ir.PFUNC
- // n2.Sym already existed, so it's already marked as a function.
- n2.SetPos(fn.Pos())
- n2.SetType(types.Types[types.TUINT8]) // fake type for a static closure. Could use runtime.funcval if we had it.
- return s.expr(n2)
-}
-
// getClosureAndRcvr returns values for the appropriate closure and receiver of an
// interface call
func (s *state) getClosureAndRcvr(fn *ir.SelectorExpr) (*ssa.Value, *ssa.Value) {
}
addr := s.addr(n.X)
return s.newValue1(ssa.OpCopy, t, addr) // ensure that addr has the right type
- case ir.OCALLFUNC, ir.OCALLINTER, ir.OCALLMETH:
+ case ir.OCALLFUNC, ir.OCALLINTER:
n := n.(*ir.CallExpr)
return s.callAddr(n, callNormal)
case ir.ODOTTYPE:
return // already walked
}
- params := n.X.Type().Params()
args := n.Args
n.X = walkExpr(n.X, init)
walkExprList(args, init)
- // If this is a method call, add the receiver at the beginning of the args.
+ // If this is a method call t.M(...),
+ // rewrite into a function call T.M(t, ...).
+ // TODO(mdempsky): Do this right after type checking.
if n.Op() == ir.OCALLMETH {
withRecv := make([]ir.Node, len(args)+1)
dot := n.X.(*ir.SelectorExpr)
withRecv[0] = dot.X
- dot.X = nil
copy(withRecv[1:], args)
args = withRecv
+
+ dot = ir.NewSelectorExpr(dot.Pos(), ir.OXDOT, ir.TypeNode(dot.X.Type()), dot.Selection.Sym)
+ fn := typecheck.Expr(dot).(*ir.MethodExpr).FuncName()
+ fn.Type().Size()
+
+ n.SetOp(ir.OCALLFUNC)
+ n.X = fn
}
+ params := n.X.Type().Params()
+
// For any argument whose evaluation might require a function call,
// store that argument into a temporary variable,
// to prevent that calls from clobbering arguments already on the stack.
for i, arg := range args {
updateHasCall(arg)
// Determine param type.
- var t *types.Type
- if n.Op() == ir.OCALLMETH {
- if i == 0 {
- t = n.X.Type().Recv().Type
- } else {
- t = params.Field(i - 1).Type
- }
- } else {
- t = params.Field(i).Type
- }
+ t := params.Field(i).Type
if base.Flag.Cfg.Instrumenting || fncall(arg, t) {
// make assignment of fncall to tempAt
tmp := typecheck.Temp(t)