public void EmitPredefined(EmitContext ec, MethodSpec method, Arguments Arguments, bool statement = false, Location?loc = null)
{
Expression instance_copy = null;
if (!HasAwaitArguments && ec.HasSet(BuilderContext.Options.AsyncBody))
{
HasAwaitArguments = Arguments != null && Arguments.ContainsEmitWithAwait();
if (HasAwaitArguments && InstanceExpressionOnStack)
{
throw new NotSupportedException();
}
}
OpCode call_op;
LocalTemporary lt = null;
if (method.IsStatic)
{
call_op = OpCodes.Call;
}
else
{
call_op = IsVirtualCallRequired(InstanceExpression, method) ? OpCodes.Callvirt : OpCodes.Call;
if (HasAwaitArguments)
{
instance_copy = InstanceExpression.EmitToField(ec);
var ie = new InstanceEmitter(instance_copy, IsAddressCall(instance_copy, call_op, method.DeclaringType));
if (Arguments == null)
{
ie.EmitLoad(ec, true);
}
}
else if (!InstanceExpressionOnStack)
{
var ie = new InstanceEmitter(InstanceExpression, IsAddressCall(InstanceExpression, call_op, method.DeclaringType));
ie.Emit(ec, ConditionalAccess);
if (DuplicateArguments)
{
ec.Emit(OpCodes.Dup);
if (Arguments != null && Arguments.Count != 0)
{
lt = new LocalTemporary(ie.GetStackType(ec));
lt.Store(ec);
instance_copy = lt;
}
}
}
}
if (Arguments != null && !InstanceExpressionOnStack)
{
EmittedArguments = Arguments.Emit(ec, DuplicateArguments, HasAwaitArguments);
if (EmittedArguments != null)
{
if (instance_copy != null)
{
var ie = new InstanceEmitter(instance_copy, IsAddressCall(instance_copy, call_op, method.DeclaringType));
ie.Emit(ec, ConditionalAccess);
if (lt != null)
{
lt.Release(ec);
}
}
EmittedArguments.Emit(ec);
}
}
if (call_op == OpCodes.Callvirt && (InstanceExpression.Type.IsGenericParameter || InstanceExpression.Type.IsStructOrEnum))
{
ec.Emit(OpCodes.Constrained, InstanceExpression.Type);
}
if (loc != null)
{
//
// Emit explicit sequence point for expressions like Foo.Bar () to help debugger to
// break at right place when LHS expression can be stepped-into
//
ec.MarkCallEntry(loc.Value);
}
//
// Set instance expression to actual result expression. When it contains await it can be
// picked up by caller
//
InstanceExpression = instance_copy;
if (method.Parameters.HasArglist)
{
var varargs_types = GetVarargsTypes(method, Arguments);
ec.Emit(call_op, method, varargs_types);
}
else
{
//
// If you have:
// this.DoFoo ();
// and DoFoo is not virtual, you can omit the callvirt,
// because you don't need the null checking behavior.
//
ec.Emit(call_op, method);
}
//
// Pop the return value if there is one and stack should be empty
//
if (statement && method.ReturnType.Kind != MemberKind.Void)
{
ec.Emit(OpCodes.Pop);
}
}