Jo Shields 3c1f479b9d Imported Upstream version 4.0.0~alpha1
Former-commit-id: 806294f5ded97629b74c85c09952f2a74fe182d9
2015-04-07 09:35:12 +01:00

370 lines
12 KiB
C#

using System;
using Mono.Cecil.Cil;
using Mono.Cecil.Metadata;
namespace Mono.Debugger.Soft
{
internal class ILInterpreter
{
MethodMirror method;
public ILInterpreter (MethodMirror method) {
this.method = method;
}
public Value Evaluate (Value this_val, Value[] args) {
var body = method.GetMethodBody ();
// Implement only the IL opcodes required to evaluate mcs compiled property accessors:
// IL_0000: nop
// IL_0001: ldarg.0
// IL_0002: ldfld int32 Tests::field_i
// IL_0007: stloc.0
// IL_0008: br IL_000d
// IL_000d: ldloc.0
// IL_000e: ret
// ... or returns a simple constant:
// IL_0000: ldc.i4 1024
// IL_0005: conv.i8
// IL_0006: ret
if (args != null && args.Length != 0)
throw new NotSupportedException ();
if (method.IsStatic || method.DeclaringType.IsValueType || this_val == null || !(this_val is ObjectMirror))
throw new NotSupportedException ();
var instructions = body.Instructions;
if (instructions.Count < 1 || instructions.Count > 16)
throw new NotSupportedException ();
var stack = new Value [16];
var ins = instructions [0];
Value locals_0 = null;
int ins_count = 0;
int sp = 0;
while (ins != null) {
if (ins_count > 16)
throw new NotImplementedException ();
var next = ins.Next;
ins_count++;
var op = ins.OpCode;
if (op == OpCodes.Nop) {
} else if (op == OpCodes.Ldarg_0) {
if (sp != 0)
throw new NotSupportedException ();
stack [sp++] = this_val;
} else if (op == OpCodes.Ldfld) {
if (sp != 1)
throw new NotSupportedException ();
var obj = (ObjectMirror) stack [--sp];
var field = (FieldInfoMirror) ins.Operand;
try {
stack [sp++] = obj.GetValue (field);
} catch (ArgumentException) {
throw new NotSupportedException ();
}
} else if (op == OpCodes.Ldc_I4_0) {
if (sp != 0)
throw new NotSupportedException ();
try {
stack [sp++] = new PrimitiveValue (method.VirtualMachine, 0);
} catch (ArgumentException) {
throw new NotSupportedException ();
}
} else if (op == OpCodes.Ldc_I4_1) {
if (sp != 0)
throw new NotSupportedException ();
try {
stack [sp++] = new PrimitiveValue (method.VirtualMachine, 1);
} catch (ArgumentException) {
throw new NotSupportedException ();
}
} else if (op == OpCodes.Ldc_I4_2) {
if (sp != 0)
throw new NotSupportedException ();
try {
stack [sp++] = new PrimitiveValue (method.VirtualMachine, 2);
} catch (ArgumentException) {
throw new NotSupportedException ();
}
} else if (op == OpCodes.Ldc_I4_3) {
if (sp != 0)
throw new NotSupportedException ();
try {
stack [sp++] = new PrimitiveValue (method.VirtualMachine, 3);
} catch (ArgumentException) {
throw new NotSupportedException ();
}
} else if (op == OpCodes.Ldc_I4_4) {
if (sp != 0)
throw new NotSupportedException ();
try {
stack [sp++] = new PrimitiveValue (method.VirtualMachine, 4);
} catch (ArgumentException) {
throw new NotSupportedException ();
}
} else if (op == OpCodes.Ldc_I4_5) {
if (sp != 0)
throw new NotSupportedException ();
try {
stack [sp++] = new PrimitiveValue (method.VirtualMachine, 5);
} catch (ArgumentException) {
throw new NotSupportedException ();
}
} else if (op == OpCodes.Ldc_I4_6) {
if (sp != 0)
throw new NotSupportedException ();
try {
stack [sp++] = new PrimitiveValue (method.VirtualMachine, 6);
} catch (ArgumentException) {
throw new NotSupportedException ();
}
} else if (op == OpCodes.Ldc_I4_7) {
if (sp != 0)
throw new NotSupportedException ();
try {
stack [sp++] = new PrimitiveValue (method.VirtualMachine, 7);
} catch (ArgumentException) {
throw new NotSupportedException ();
}
} else if (op == OpCodes.Ldc_I4_8) {
if (sp != 0)
throw new NotSupportedException ();
try {
stack [sp++] = new PrimitiveValue (method.VirtualMachine, 8);
} catch (ArgumentException) {
throw new NotSupportedException ();
}
} else if (op == OpCodes.Ldc_I4_M1) {
if (sp != 0)
throw new NotSupportedException ();
try {
stack [sp++] = new PrimitiveValue (method.VirtualMachine, -1);
} catch (ArgumentException) {
throw new NotSupportedException ();
}
} else if (op == OpCodes.Ldc_I4) {
if (sp != 0)
throw new NotSupportedException ();
try {
stack [sp++] = new PrimitiveValue (method.VirtualMachine, ins.Operand);
} catch (ArgumentException) {
throw new NotSupportedException ();
}
} else if (op == OpCodes.Ldc_I4_S) {
if (sp != 0)
throw new NotSupportedException ();
try {
stack [sp++] = new PrimitiveValue (method.VirtualMachine, ins.Operand);
} catch (ArgumentException) {
throw new NotSupportedException ();
}
} else if (op == OpCodes.Ldc_I8) {
if (sp != 0)
throw new NotSupportedException ();
try {
stack [sp++] = new PrimitiveValue (method.VirtualMachine, ins.Operand);
} catch (ArgumentException) {
throw new NotSupportedException ();
}
} else if (op == OpCodes.Ldc_R4) {
if (sp != 0)
throw new NotSupportedException ();
try {
stack [sp++] = new PrimitiveValue (method.VirtualMachine, ins.Operand);
} catch (ArgumentException) {
throw new NotSupportedException ();
}
} else if (op == OpCodes.Ldc_R8) {
if (sp != 0)
throw new NotSupportedException ();
try {
stack [sp++] = new PrimitiveValue (method.VirtualMachine, ins.Operand);
} catch (ArgumentException) {
throw new NotSupportedException ();
}
} else if (op == OpCodes.Conv_I) {
if (sp != 1)
throw new NotSupportedException ();
try {
var primitive = (PrimitiveValue) stack [--sp];
stack [sp++] = new PrimitiveValue (method.VirtualMachine, Convert.ToInt32 (primitive.Value));
} catch {
throw new NotSupportedException ();
}
} else if (op == OpCodes.Conv_I1) {
if (sp != 1)
throw new NotSupportedException ();
try {
var primitive = (PrimitiveValue) stack [--sp];
stack [sp++] = new PrimitiveValue (method.VirtualMachine, Convert.ToSByte (primitive.Value));
} catch {
throw new NotSupportedException ();
}
} else if (op == OpCodes.Conv_U1) {
if (sp != 1)
throw new NotSupportedException ();
try {
var primitive = (PrimitiveValue) stack [--sp];
stack [sp++] = new PrimitiveValue (method.VirtualMachine, Convert.ToByte (primitive.Value));
} catch {
throw new NotSupportedException ();
}
} else if (op == OpCodes.Conv_I2) {
if (sp != 1)
throw new NotSupportedException ();
try {
var primitive = (PrimitiveValue) stack [--sp];
stack [sp++] = new PrimitiveValue (method.VirtualMachine, Convert.ToInt16 (primitive.Value));
} catch {
throw new NotSupportedException ();
}
} else if (op == OpCodes.Conv_U2) {
if (sp != 1)
throw new NotSupportedException ();
try {
var primitive = (PrimitiveValue) stack [--sp];
stack [sp++] = new PrimitiveValue (method.VirtualMachine, Convert.ToUInt16 (primitive.Value));
} catch {
throw new NotSupportedException ();
}
} else if (op == OpCodes.Conv_I4) {
if (sp != 1)
throw new NotSupportedException ();
try {
var primitive = (PrimitiveValue) stack [--sp];
stack [sp++] = new PrimitiveValue (method.VirtualMachine, Convert.ToInt32 (primitive.Value));
} catch {
throw new NotSupportedException ();
}
} else if (op == OpCodes.Conv_U4) {
if (sp != 1)
throw new NotSupportedException ();
try {
var primitive = (PrimitiveValue) stack [--sp];
stack [sp++] = new PrimitiveValue (method.VirtualMachine, Convert.ToUInt32 (primitive.Value));
} catch {
throw new NotSupportedException ();
}
} else if (op == OpCodes.Conv_I8) {
if (sp != 1)
throw new NotSupportedException ();
try {
var primitive = (PrimitiveValue) stack [--sp];
stack [sp++] = new PrimitiveValue (method.VirtualMachine, Convert.ToInt64 (primitive.Value));
} catch {
throw new NotSupportedException ();
}
} else if (op == OpCodes.Conv_U8) {
if (sp != 1)
throw new NotSupportedException ();
try {
var primitive = (PrimitiveValue) stack [--sp];
stack [sp++] = new PrimitiveValue (method.VirtualMachine, Convert.ToUInt64 (primitive.Value));
} catch {
throw new NotSupportedException ();
}
} else if (op == OpCodes.Conv_R4) {
if (sp != 1)
throw new NotSupportedException ();
try {
var primitive = (PrimitiveValue) stack [--sp];
stack [sp++] = new PrimitiveValue (method.VirtualMachine, Convert.ToSingle (primitive.Value));
} catch {
throw new NotSupportedException ();
}
} else if (op == OpCodes.Conv_R8) {
if (sp != 1)
throw new NotSupportedException ();
try {
var primitive = (PrimitiveValue) stack [--sp];
stack [sp++] = new PrimitiveValue (method.VirtualMachine, Convert.ToDouble (primitive.Value));
} catch {
throw new NotSupportedException ();
}
} else if (op == OpCodes.Stloc_0) {
if (sp != 1)
throw new NotSupportedException ();
locals_0 = stack [--sp];
} else if (op == OpCodes.Br || op == OpCodes.Br_S) {
next = (ILInstruction) ins.Operand;
} else if (op == OpCodes.Ldloc_0) {
if (sp != 0)
throw new NotSupportedException ();
stack [sp++] = locals_0;
} else if (op == OpCodes.Ret) {
if (sp > 0) {
var res = stack [--sp];
var primitive = res as PrimitiveValue;
if (method.ReturnType.IsPrimitive && primitive != null) {
// cast the primitive value to the return type
try {
switch (method.ReturnType.CSharpName) {
case "double": res = new PrimitiveValue (method.VirtualMachine, Convert.ToDouble (primitive.Value)); break;
case "float": res = new PrimitiveValue (method.VirtualMachine, Convert.ToSingle (primitive.Value)); break;
case "ulong": res = new PrimitiveValue (method.VirtualMachine, Convert.ToUInt64 (primitive.Value)); break;
case "long": res = new PrimitiveValue (method.VirtualMachine, Convert.ToInt64 (primitive.Value)); break;
case "uint": res = new PrimitiveValue (method.VirtualMachine, Convert.ToUInt32 (primitive.Value)); break;
case "int": res = new PrimitiveValue (method.VirtualMachine, Convert.ToInt32 (primitive.Value)); break;
case "ushort": res = new PrimitiveValue (method.VirtualMachine, Convert.ToUInt16 (primitive.Value)); break;
case "short": res = new PrimitiveValue (method.VirtualMachine, Convert.ToInt16 (primitive.Value)); break;
case "sbyte": res = new PrimitiveValue (method.VirtualMachine, Convert.ToSByte (primitive.Value)); break;
case "byte": res = new PrimitiveValue (method.VirtualMachine, Convert.ToByte (primitive.Value)); break;
case "char": res = new PrimitiveValue (method.VirtualMachine, Convert.ToChar (primitive.Value)); break;
case "bool": res = new PrimitiveValue (method.VirtualMachine, Convert.ToBoolean (primitive.Value)); break;
}
} catch {
throw new NotSupportedException ();
}
}
return res;
}
return null;
} else {
throw new NotSupportedException ();
}
ins = next;
}
return null;
}
}
}