private void ExecuteMethodCore(out ObjectInstance retVal, out bool doJmpCall, out MemberReference jmpCallToken)
{
jmpCallToken = null;
doJmpCall = false;
retVal = null;
for (; _instructions.Length > _instructionPtr; _instructionPtr++)
{
var inst = _instructions[_instructionPtr];
if (inst.OpCode == OpCodes.Nop)
{
continue;
}
else if (inst.OpCode == OpCodes.Break)
{
continue;
}
else if (inst.OpCode == OpCodes.Ldarg_0)
{
LdArg(0);
continue;
}
else if (inst.OpCode == OpCodes.Ldarg_1)
{
LdArg(1);
continue;
}
else if (inst.OpCode == OpCodes.Ldarg_2)
{
LdArg(2);
continue;
}
else if (inst.OpCode == OpCodes.Ldarg_3)
{
LdArg(3);
continue;
}
else if (inst.OpCode == OpCodes.Ldloc_0)
{
LdLoc(0);
continue;
}
else if (inst.OpCode == OpCodes.Ldloc_1)
{
LdLoc(1);
continue;
}
else if (inst.OpCode == OpCodes.Ldloc_2)
{
LdLoc(2);
continue;
}
else if (inst.OpCode == OpCodes.Ldloc_3)
{
LdLoc(3);
continue;
}
else if (inst.OpCode == OpCodes.Stloc_0)
{
StLoc(0);
continue;
}
else if (inst.OpCode == OpCodes.Stloc_1)
{
StLoc(1);
continue;
}
else if (inst.OpCode == OpCodes.Stloc_2)
{
StLoc(2);
continue;
}
else if (inst.OpCode == OpCodes.Stloc_3)
{
StLoc(3);
continue;
}
else if (inst.OpCode == OpCodes.Ldarg_S)
{
// TODO: get index directly
var index = (inst.Operand is ParameterReference) ? ((ParameterReference)inst.Operand).Index : ((VariableReference)inst.Operand).Index;
LdArg(index);
continue;
}
else if (inst.OpCode == OpCodes.Ldarga_S)
{
// TODO: get index directly
var index = (inst.Operand is ParameterReference) ? ((ParameterReference)inst.Operand).Index : ((VariableReference)inst.Operand).Index;
LdArgA(index);
continue;
}
else if (inst.OpCode == OpCodes.Starg_S)
{
// TODO: get index directly
var index = (inst.Operand is ParameterReference) ? ((ParameterReference)inst.Operand).Index : ((VariableReference)inst.Operand).Index;
StArg(index);
continue;
}
else if (inst.OpCode == OpCodes.Ldloc_S)
{
// TODO: get index directly
var index = (inst.Operand is ParameterReference) ? ((ParameterReference)inst.Operand).Index : ((VariableReference)inst.Operand).Index;
LdLoc(index);
continue;
}
else if (inst.OpCode == OpCodes.Ldloca_S)
{
// TODO: get index directly
var index = (inst.Operand is ParameterReference) ? ((ParameterReference)inst.Operand).Index : ((VariableReference)inst.Operand).Index;
LdLocA(index);
continue;
}
else if (inst.OpCode == OpCodes.Stloc_S)
{
// TODO: get index directly
var index = (inst.Operand is ParameterReference) ? ((ParameterReference)inst.Operand).Index : ((VariableReference)inst.Operand).Index;
StLoc(index);
continue;
}
else if (inst.OpCode == OpCodes.Ldnull)
{
Ldnull();
continue;
}
else if (inst.OpCode == OpCodes.Ldc_I4_M1)
{
LdIcon(-1);
continue;
}
else if (inst.OpCode == OpCodes.Ldc_I4_0)
{
LdIcon(0);
continue;
}
else if (inst.OpCode == OpCodes.Ldc_I4_1)
{
LdIcon(1);
continue;
}
else if (inst.OpCode == OpCodes.Ldc_I4_2)
{
LdIcon(2);
continue;
}
else if (inst.OpCode == OpCodes.Ldc_I4_3)
{
LdIcon(3);
continue;
}
else if (inst.OpCode == OpCodes.Ldc_I4_4)
{
LdIcon(4);
continue;
}
else if (inst.OpCode == OpCodes.Ldc_I4_5)
{
LdIcon(5);
continue;
}
else if (inst.OpCode == OpCodes.Ldc_I4_6)
{
LdIcon(6);
continue;
}
else if (inst.OpCode == OpCodes.Ldc_I4_7)
{
LdIcon(7);
continue;
}
else if (inst.OpCode == OpCodes.Ldc_I4_8)
{
LdIcon(8);
continue;
}
else if (inst.OpCode == OpCodes.Ldc_I4_S)
{
LdIcon(inst.Operand);
continue;
}
else if (inst.OpCode == OpCodes.Ldc_I4)
{
LdIcon(inst.Operand);
continue;
}
else if (inst.OpCode == OpCodes.Ldstr)
{
LdStr();
continue;
}
else if (inst.OpCode == OpCodes.Ldfld)
{
LdFld();
continue;
}
else if (inst.OpCode == OpCodes.Ldflda)
{
LdFldA();
continue;
}
else if (inst.OpCode == OpCodes.Stfld)
{
StFld();
continue;
}
else if (inst.OpCode == OpCodes.Ldsfld)
{
LdSFld();
continue;
}
else if (inst.OpCode == OpCodes.Ldsflda)
{
LdSFldA();
continue;
}
else if (inst.OpCode == OpCodes.Stsfld)
{
StSFld();
continue;
}
else if (inst.OpCode == OpCodes.Stobj)
{
StObj();
continue;
}
// ...
else if (inst.OpCode == OpCodes.Add)
{
Add(checkOverflow: false, unsigned: false);
continue;
}
else if (inst.OpCode == OpCodes.Add_Ovf)
{
Add(checkOverflow: true, unsigned: false);
continue;
}
else if (inst.OpCode == OpCodes.Add_Ovf_Un)
{
Add(checkOverflow: true, unsigned: true);
continue;
}
else if (inst.OpCode == OpCodes.Sub)
{
Sub(checkOverflow: false, unsigned: false);
continue;
}
else if (inst.OpCode == OpCodes.Sub_Ovf)
{
Sub(checkOverflow: true, unsigned: false);
continue;
}
else if (inst.OpCode == OpCodes.Sub_Ovf_Un)
{
Sub(checkOverflow: true, unsigned: true);
continue;
}
else if (inst.OpCode == OpCodes.Mul)
{
Mul(checkOverflow: false, unsigned: false);
continue;
}
else if (inst.OpCode == OpCodes.Mul_Ovf)
{
Mul(checkOverflow: true, unsigned: false);
continue;
}
else if (inst.OpCode == OpCodes.Mul_Ovf_Un)
{
Mul(checkOverflow: true, unsigned: true);
continue;
}
else if (inst.OpCode == OpCodes.Div)
{
Div(checkOverflow: true, unsigned: false);
continue;
}
else if (inst.OpCode == OpCodes.Div_Un)
{
Div(checkOverflow: true, unsigned: true);
continue;
}
else if (inst.OpCode == OpCodes.Rem)
{
Rem(checkOverflow: true, unsigned: false);
continue;
}
else if (inst.OpCode == OpCodes.Rem_Un)
{
Rem(checkOverflow: true, unsigned: true);
continue;
}
else if (inst.OpCode == OpCodes.Newobj)
{
NewObj();
continue;
}
else if (inst.OpCode == OpCodes.Box)
{
// TODO: not implemented yet
continue;
}
else if (inst.OpCode == OpCodes.Call)
{
Call(virtualCall: false);
continue;
}
else if (inst.OpCode == OpCodes.Callvirt)
{
Call(virtualCall: true);
continue;
}
else if (inst.OpCode == OpCodes.Ret)
{
// TODO: use reference or type
if (_methInfo2.ReturnType.Namespace == "System" && _methInfo2.ReturnType.Name == "Void")
{
Debug.Assert(_opStack.Count == 0);
}
else
{
Debug.Assert(_opStack.Count != 0);
retVal = _opStack.Pop();
}
return; // goto ExitEvalLoop;
}
else if (inst.OpCode == OpCodes.Br_S)
{
// TODO: below code is too slow
_instructionPtr = _instructions.Select((x, i) => new { Index = i, IsMatched = x == inst.Operand }).First(x => x.IsMatched).Index - 1; // increments ops ptr after "continue;". ptr must be subtracted here.
continue;
}
else if (inst.OpCode == OpCodes.Leave_S)
{
_opStack.Clear();
throw ThrowHelper.NotImplementedYet;
}
else if (inst.OpCode == OpCodes.Brfalse_S)
{
// TODO: below code is too slow
var value = _opStack.Pop();
if ((value.IsReference && value.IsNull) || value.I == 0)
{
_instructionPtr = _instructions.Select((x, i) => new { Index = i, IsMatched = x == inst.Operand }).First(x => x.IsMatched).Index - 1; // increments ops ptr after "continue;". ptr must be subtracted here.
}
continue;
}
else if (inst.OpCode == OpCodes.Brtrue_S)
{
// TODO: below code is too slow
var value = _opStack.Pop();
if ((value.IsReference && !value.IsNull) || value.I != 0)
{
_instructionPtr = _instructions.Select((x, i) => new { Index = i, IsMatched = x == inst.Operand }).First(x => x.IsMatched).Index - 1; // increments ops ptr after "continue;". ptr must be subtracted here.
}
continue;
}
// case CEE_PREFIX1:
else if (inst.OpCode == OpCodes.Arglist)
{
throw ThrowHelper.NotImplementedYet;
}
else if (inst.OpCode == OpCodes.Ceq)
{
var value2 = _opStack.Pop();
var value1 = _opStack.Pop();
if (value1.Type == CorInfoType.Class)
{
_opStack.Push(ObjectInstance.FromClrObject((value1 == value2) ? 1 : 0));
}
else if (value1.Type == CorInfoType.String)
{
_opStack.Push(ObjectInstance.FromClrObject((value1.ObjectRef == value2.ObjectRef) ? 1 : 0));
}
else
{
_opStack.Push(ObjectInstance.FromClrObject((value1.I == value2.I) ? 1 : 0));
}
continue;
}
else if (inst.OpCode == OpCodes.Cgt)
{
var value2 = _opStack.Pop().I;
var value1 = _opStack.Pop().I;
_opStack.Push(ObjectInstance.FromClrObject((value1 > value2) ? 1 : 0));
continue;
}
else if (inst.OpCode == OpCodes.Cgt_Un)
{
var value2 = _opStack.Pop();
var value1 = _opStack.Pop();
if (value1.Type == CorInfoType.Class)
{
_opStack.Push(ObjectInstance.FromClrObject((value1 != value2) ? 1 : 0));
}
else if (value1.Type == CorInfoType.String)
{
_opStack.Push(ObjectInstance.FromClrObject((value1.ObjectRef != value2.ObjectRef) ? 1 : 0));
}
else
{
_opStack.Push(ObjectInstance.FromClrObject(((ulong)value1.I > (ulong)value2.I) ? 1 : 0));
}
continue;
}
else if (inst.OpCode == OpCodes.Clt)
{
var value2 = _opStack.Pop().I;
var value1 = _opStack.Pop().I;
_opStack.Push(ObjectInstance.FromClrObject((value1 < value2) ? 1 : 0));
continue;
}
else if (inst.OpCode == OpCodes.Clt_Un)
{
var value2 = (ulong)_opStack.Pop().I;
var value1 = (ulong)_opStack.Pop().I;
_opStack.Push(ObjectInstance.FromClrObject((value1 < value2) ? 1 : 0));
continue;
}
else if (inst.OpCode == OpCodes.Throw)
{
Throw();
continue;
}
throw new InazumaExecutionException("Unknown OpCode: " + inst.OpCode.ToString());
}
}