private void DoCallWork(bool virtualCall, ObjectInstance thisArg = null, MethodReference methTok = null, object callInfo = null)
{
var op = (methTok ?? _instructions[_instructionPtr].Operand) as MethodReference;
var methDef = op.Resolve();
{
if (methDef.IsInternalCall)
{
InvokeInternalCall(methDef);
return;
}
}
_callThisArg = thisArg; // for .ctor
var totalSigArgs = 0;
if (false)
{
}
else
{
totalSigArgs = methDef.Parameters.Count + (methDef.HasThis ? 1 : 0);
}
// Note that "totalNativeArgs()" includes space for ret buff arg.
var nSlots = totalSigArgs + 1;
if (methDef.HasGenericParameters) nSlots++;
if (methDef.IsVarArg()) nSlots++;
// Make sure that the operand stack has the required number of arguments.
// (Note that this is IL args, not native.)
//
// The total number of arguments on the IL stack. Initially we assume that all the IL arguments
// the callee expects are on the stack, but may be adjusted downwards if the "this" argument
// is provided by an allocation (the call is to a constructor).
var totalArgsOnILStack = totalSigArgs;
if (_callThisArg != null)
{
Debug.Assert(totalArgsOnILStack > 0);
totalArgsOnILStack--;
}
var totalArgs = nSlots;
var LOCAL_ARG_SLOTS = 8;
var localArgs = new ObjectInstance[(totalArgs > LOCAL_ARG_SLOTS) ? totalArgs : LOCAL_ARG_SLOTS];
// Current on-stack argument index.
var arg = 0;
// FIXME: stack (mayuki)
var tmpArgsStack = _opStack.ToArray();
var curArgSlot = 0;
if (methDef.HasThis)
{
if (_callThisArg != null)
{
localArgs[curArgSlot] = _callThisArg;
}
else
{
localArgs[curArgSlot] = tmpArgsStack[tmpArgsStack.Length - (arg+1)];
arg++;
}
curArgSlot++;
}
// Now we do the non-this arguments.
for (; arg < totalArgsOnILStack; arg++)
{
localArgs[curArgSlot] = tmpArgsStack[tmpArgsStack.Length - (arg + 1)];
curArgSlot++;
}
if (methDef.HasThis)
{
if (thisArg == null)
{
thisArg = tmpArgsStack[0];
}
else
{
thisArg = _callThisArg;
}
}
ObjectInstance retVal;
MethodDefinition exactMethToCall = methDef;
if (methDef.DeclaringType.IsInterface)
{
var slot = thisArg.MethodTable.InterfaceMethodSlotMap[methDef];
exactMethToCall = thisArg.MethodTable.MethodSlots[slot].Definition;
}
else
{
if (virtualCall && methDef.IsVirtual)
{
var methodDesc = _classLoader.LookupMethodDescFromMethodDef(methDef);
exactMethToCall = thisArg.MethodTable.MethodSlots[methodDesc.Slot].Definition;
}
}
retVal = InterpretMethodBody(exactMethToCall, true, localArgs, null);
// retval
for (var i = 0; i < totalArgsOnILStack; i++)
{
_opStack.Pop();
}
if (methDef.ReturnType.FullName != "System.Void") // TODO: should refer typevalue enum
{
_opStack.Push(retVal);
}
}