mirror of
https://github.com/danbulant/Cosmos
synced 2026-05-19 20:39:01 +00:00
520 lines
No EOL
18 KiB
C#
520 lines
No EOL
18 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using SR = System.Reflection;
|
|
|
|
namespace Cosmos.IL2CPU
|
|
{
|
|
// ILOpcode represents the opcode during for scanning.
|
|
// Do not:
|
|
// Include reference to ILOp, the scanner should do that
|
|
// Include referense to System.Reflection.Emit, this is metadata
|
|
// only needed by reader and not ILOpCode
|
|
public abstract class ILOpCode
|
|
{
|
|
public enum Code : ushort
|
|
{
|
|
#region Values
|
|
|
|
Nop = 0x0000,
|
|
Break = 0x0001,
|
|
Ldarg_0 = 0x0002,
|
|
Ldarg_1 = 0x0003,
|
|
Ldarg_2 = 0x0004,
|
|
Ldarg_3 = 0x0005,
|
|
Ldloc_0 = 0x0006,
|
|
Ldloc_1 = 0x0007,
|
|
Ldloc_2 = 0x0008,
|
|
Ldloc_3 = 0x0009,
|
|
Stloc_0 = 0x000A,
|
|
Stloc_1 = 0x000B,
|
|
Stloc_2 = 0x000C,
|
|
Stloc_3 = 0x000D,
|
|
Ldarg_S = 0x000E,
|
|
Ldarga_S = 0x000F,
|
|
Starg_S = 0x0010,
|
|
Ldloc_S = 0x0011,
|
|
Ldloca_S = 0x0012,
|
|
Stloc_S = 0x0013,
|
|
Ldnull = 0x0014,
|
|
Ldc_I4_M1 = 0x0015,
|
|
Ldc_I4_0 = 0x0016,
|
|
Ldc_I4_1 = 0x0017,
|
|
Ldc_I4_2 = 0x0018,
|
|
Ldc_I4_3 = 0x0019,
|
|
Ldc_I4_4 = 0x001A,
|
|
Ldc_I4_5 = 0x001B,
|
|
Ldc_I4_6 = 0x001C,
|
|
Ldc_I4_7 = 0x001D,
|
|
Ldc_I4_8 = 0x001E,
|
|
Ldc_I4_S = 0x001F,
|
|
Ldc_I4 = 0x0020,
|
|
Ldc_I8 = 0x0021,
|
|
Ldc_R4 = 0x0022,
|
|
Ldc_R8 = 0x0023,
|
|
Dup = 0x0025,
|
|
Pop = 0x0026,
|
|
Jmp = 0x0027,
|
|
Call = 0x0028,
|
|
Calli = 0x0029,
|
|
Ret = 0x002A,
|
|
Br_S = 0x002B,
|
|
Brfalse_S = 0x002C,
|
|
Brtrue_S = 0x002D,
|
|
Beq_S = 0x002E,
|
|
Bge_S = 0x002F,
|
|
Bgt_S = 0x0030,
|
|
Ble_S = 0x0031,
|
|
Blt_S = 0x0032,
|
|
Bne_Un_S = 0x0033,
|
|
Bge_Un_S = 0x0034,
|
|
Bgt_Un_S = 0x0035,
|
|
Ble_Un_S = 0x0036,
|
|
Blt_Un_S = 0x0037,
|
|
Br = 0x0038,
|
|
Brfalse = 0x0039,
|
|
Brtrue = 0x003A,
|
|
Beq = 0x003B,
|
|
Bge = 0x003C,
|
|
Bgt = 0x003D,
|
|
Ble = 0x003E,
|
|
Blt = 0x003F,
|
|
Bne_Un = 0x0040,
|
|
Bge_Un = 0x0041,
|
|
Bgt_Un = 0x0042,
|
|
Ble_Un = 0x0043,
|
|
Blt_Un = 0x0044,
|
|
Switch = 0x0045,
|
|
Ldind_I1 = 0x0046,
|
|
Ldind_U1 = 0x0047,
|
|
Ldind_I2 = 0x0048,
|
|
Ldind_U2 = 0x0049,
|
|
Ldind_I4 = 0x004A,
|
|
Ldind_U4 = 0x004B,
|
|
Ldind_I8 = 0x004C,
|
|
Ldind_I = 0x004D,
|
|
Ldind_R4 = 0x004E,
|
|
Ldind_R8 = 0x004F,
|
|
Ldind_Ref = 0x0050,
|
|
Stind_Ref = 0x0051,
|
|
Stind_I1 = 0x0052,
|
|
Stind_I2 = 0x0053,
|
|
Stind_I4 = 0x0054,
|
|
Stind_I8 = 0x0055,
|
|
Stind_R4 = 0x0056,
|
|
Stind_R8 = 0x0057,
|
|
Add = 0x0058,
|
|
Sub = 0x0059,
|
|
Mul = 0x005A,
|
|
Div = 0x005B,
|
|
Div_Un = 0x005C,
|
|
Rem = 0x005D,
|
|
Rem_Un = 0x005E,
|
|
And = 0x005F,
|
|
Or = 0x0060,
|
|
Xor = 0x0061,
|
|
Shl = 0x0062,
|
|
Shr = 0x0063,
|
|
Shr_Un = 0x0064,
|
|
Neg = 0x0065,
|
|
Not = 0x0066,
|
|
Conv_I1 = 0x0067,
|
|
Conv_I2 = 0x0068,
|
|
Conv_I4 = 0x0069,
|
|
Conv_I8 = 0x006A,
|
|
Conv_R4 = 0x006B,
|
|
Conv_R8 = 0x006C,
|
|
Conv_U4 = 0x006D,
|
|
Conv_U8 = 0x006E,
|
|
Callvirt = 0x006F,
|
|
Cpobj = 0x0070,
|
|
Ldobj = 0x0071,
|
|
Ldstr = 0x0072,
|
|
Newobj = 0x0073,
|
|
Castclass = 0x0074,
|
|
Isinst = 0x0075,
|
|
Conv_R_Un = 0x0076,
|
|
Unbox = 0x0079,
|
|
Throw = 0x007A,
|
|
Ldfld = 0x007B,
|
|
Ldflda = 0x007C,
|
|
Stfld = 0x007D,
|
|
Ldsfld = 0x007E,
|
|
Ldsflda = 0x007F,
|
|
Stsfld = 0x0080,
|
|
Stobj = 0x0081,
|
|
Conv_Ovf_I1_Un = 0x0082,
|
|
Conv_Ovf_I2_Un = 0x0083,
|
|
Conv_Ovf_I4_Un = 0x0084,
|
|
Conv_Ovf_I8_Un = 0x0085,
|
|
Conv_Ovf_U1_Un = 0x0086,
|
|
Conv_Ovf_U2_Un = 0x0087,
|
|
Conv_Ovf_U4_Un = 0x0088,
|
|
Conv_Ovf_U8_Un = 0x0089,
|
|
Conv_Ovf_I_Un = 0x008A,
|
|
Conv_Ovf_U_Un = 0x008B,
|
|
Box = 0x008C,
|
|
Newarr = 0x008D,
|
|
Ldlen = 0x008E,
|
|
Ldelema = 0x008F,
|
|
Ldelem_I1 = 0x0090,
|
|
Ldelem_U1 = 0x0091,
|
|
Ldelem_I2 = 0x0092,
|
|
Ldelem_U2 = 0x0093,
|
|
Ldelem_I4 = 0x0094,
|
|
Ldelem_U4 = 0x0095,
|
|
Ldelem_I8 = 0x0096,
|
|
Ldelem_I = 0x0097,
|
|
Ldelem_R4 = 0x0098,
|
|
Ldelem_R8 = 0x0099,
|
|
Ldelem_Ref = 0x009A,
|
|
Stelem_I = 0x009B,
|
|
Stelem_I1 = 0x009C,
|
|
Stelem_I2 = 0x009D,
|
|
Stelem_I4 = 0x009E,
|
|
Stelem_I8 = 0x009F,
|
|
Stelem_R4 = 0x00A0,
|
|
Stelem_R8 = 0x00A1,
|
|
Stelem_Ref = 0x00A2,
|
|
Ldelem = 0x00A3,
|
|
Stelem = 0x00A4,
|
|
Unbox_Any = 0x00A5,
|
|
Conv_Ovf_I1 = 0x00B3,
|
|
Conv_Ovf_U1 = 0x00B4,
|
|
Conv_Ovf_I2 = 0x00B5,
|
|
Conv_Ovf_U2 = 0x00B6,
|
|
Conv_Ovf_I4 = 0x00B7,
|
|
Conv_Ovf_U4 = 0x00B8,
|
|
Conv_Ovf_I8 = 0x00B9,
|
|
Conv_Ovf_U8 = 0x00BA,
|
|
Refanyval = 0x00C2,
|
|
Ckfinite = 0x00C3,
|
|
Mkrefany = 0x00C6,
|
|
Ldtoken = 0x00D0,
|
|
Conv_U2 = 0x00D1,
|
|
Conv_U1 = 0x00D2,
|
|
Conv_I = 0x00D3,
|
|
Conv_Ovf_I = 0x00D4,
|
|
Conv_Ovf_U = 0x00D5,
|
|
Add_Ovf = 0x00D6,
|
|
Add_Ovf_Un = 0x00D7,
|
|
Mul_Ovf = 0x00D8,
|
|
Mul_Ovf_Un = 0x00D9,
|
|
Sub_Ovf = 0x00DA,
|
|
Sub_Ovf_Un = 0x00DB,
|
|
Endfinally = 0x00DC,
|
|
Leave = 0x00DD,
|
|
Leave_S = 0x00DE,
|
|
Stind_I = 0x00DF,
|
|
Conv_U = 0x00E0,
|
|
Prefix7 = 0x00F8,
|
|
Prefix6 = 0x00F9,
|
|
Prefix5 = 0x00FA,
|
|
Prefix4 = 0x00FB,
|
|
Prefix3 = 0x00FC,
|
|
Prefix2 = 0x00FD,
|
|
Prefix1 = 0x00FE,
|
|
Prefixref = 0x00FF,
|
|
Arglist = 0xFE00,
|
|
Ceq = 0xFE01,
|
|
Cgt = 0xFE02,
|
|
Cgt_Un = 0xFE03,
|
|
Clt = 0xFE04,
|
|
Clt_Un = 0xFE05,
|
|
Ldftn = 0xFE06,
|
|
Ldvirtftn = 0xFE07,
|
|
Ldarg = 0xFE09,
|
|
Ldarga = 0xFE0A,
|
|
Starg = 0xFE0B,
|
|
Ldloc = 0xFE0C,
|
|
Ldloca = 0xFE0D,
|
|
Stloc = 0xFE0E,
|
|
Localloc = 0xFE0F,
|
|
Endfilter = 0xFE11,
|
|
Unaligned = 0xFE12,
|
|
Volatile = 0xFE13,
|
|
Tailcall = 0xFE14,
|
|
Initobj = 0xFE15,
|
|
Constrained = 0xFE16,
|
|
Cpblk = 0xFE17,
|
|
Initblk = 0xFE18,
|
|
Rethrow = 0xFE1A,
|
|
Sizeof = 0xFE1C,
|
|
Refanytype = 0xFE1D,
|
|
Readonly = 0xFE1E
|
|
|
|
#endregion
|
|
}
|
|
|
|
public readonly Code OpCode;
|
|
|
|
// Op offset within method. Used for labels etc in assembly.
|
|
public readonly int Position;
|
|
|
|
// position of the next instruction
|
|
public readonly int NextPosition;
|
|
|
|
public readonly SR.ExceptionHandlingClause CurrentExceptionHandler;
|
|
|
|
protected ILOpCode(Code aOpCode, int aPos, int aNextPos, SR.ExceptionHandlingClause aCurrentExceptionHandler)
|
|
{
|
|
OpCode = aOpCode;
|
|
Position = aPos;
|
|
NextPosition = aNextPos;
|
|
CurrentExceptionHandler = aCurrentExceptionHandler;
|
|
}
|
|
|
|
public override string ToString()
|
|
{
|
|
// leave here, makes easier debugging the compiler. Compiler will
|
|
// show for example "IL_0001: ldstr" instead of just ILOpCode
|
|
return String.Format("IL_{0}: {1}", Position.ToString("X4"), OpCode);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns the number of items popped from the stack. This is the logical stack, not physical items.
|
|
/// So a 100byte struct is 1 pop, even though it might be multiple 32-bit or 64-bit words on the stack.
|
|
/// </summary>
|
|
/// <param name="aMethod"></param>
|
|
public abstract int GetNumberOfStackPops(SR.MethodBase aMethod);
|
|
|
|
/// <summary>
|
|
/// Returns the number of items pushed to the stack. This is the logical stack, not physical items.
|
|
/// So a 100byte struct is 1 pop, even though it might be multiple 32-bit or 64-bit words on the stack.
|
|
/// </summary>
|
|
/// <param name="aMethod"></param>
|
|
public abstract int GetNumberOfStackPushes(SR.MethodBase aMethod);
|
|
|
|
public Type[] StackPopTypes { get; private set; }
|
|
|
|
public Type[] StackPushTypes { get; private set; }
|
|
|
|
internal void InitStackAnalysis(SR.MethodBase aMethod)
|
|
{
|
|
StackPopTypes = new Type[GetNumberOfStackPops(aMethod)];
|
|
StackPushTypes = new Type[GetNumberOfStackPushes(aMethod)];
|
|
DoInitStackAnalysis(aMethod);
|
|
}
|
|
|
|
protected virtual void DoInitStackAnalysis(SR.MethodBase aMethod)
|
|
{
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Gets set to true on first interpreter processing. Is used for loop detection
|
|
/// </summary>
|
|
internal bool Processed = false;
|
|
|
|
public uint? StackOffsetBeforeExecution = null;
|
|
|
|
public void InterpretStackTypes(
|
|
IDictionary<int, ILOpCode> aOpCodes,
|
|
Stack<Type> aStack,
|
|
ref bool aSituationChanged,
|
|
int aMaxRecursionDepth)
|
|
{
|
|
if (Processed)
|
|
{
|
|
ILInterpretationDebugLine(() => String.Format("{0} skipped for reinterpretation", this));
|
|
return;
|
|
}
|
|
Processed = true;
|
|
ILInterpretationDebugLine(
|
|
() =>
|
|
{
|
|
var sb = new StringBuilder();
|
|
sb.AppendFormat("Interpreting {0}. StackCount = {1}. Contents: ", this, aStack.Count);
|
|
foreach (var item in aStack)
|
|
{
|
|
if (item == null)
|
|
{
|
|
sb.Append("**NULL**, ");
|
|
}
|
|
else
|
|
{
|
|
sb.AppendFormat("{0}, ", item.FullName);
|
|
}
|
|
}
|
|
return sb.ToString().Trim(',', ' ');
|
|
});
|
|
if (aMaxRecursionDepth == 0)
|
|
{
|
|
throw new Exception("Safety Error: MaxRecursionDepth reached!");
|
|
}
|
|
|
|
if (StackOffsetBeforeExecution == null)
|
|
{
|
|
StackOffsetBeforeExecution = 0;
|
|
foreach (var item in aStack)
|
|
{
|
|
if (item == null)
|
|
{
|
|
StackOffsetBeforeExecution = null;
|
|
break;
|
|
}
|
|
StackOffsetBeforeExecution += ILOp.Align(ILOp.SizeOfType(item), 4);
|
|
}
|
|
}
|
|
|
|
// if current instruction is the first instruction of a catch statement, "push" the exception type now
|
|
if (CurrentExceptionHandler != null && CurrentExceptionHandler.HandlerOffset == Position)
|
|
{
|
|
if (CurrentExceptionHandler.Flags != SR.ExceptionHandlingClauseOptions.Finally)
|
|
{
|
|
aStack.Push(CurrentExceptionHandler.CatchType);
|
|
}
|
|
}
|
|
|
|
if (StackPopTypes.Length > aStack.Count)
|
|
{
|
|
throw new Exception(
|
|
String.Format("OpCode {0} tries to pop more stuff from analytical stack than there is!", this));
|
|
}
|
|
|
|
for (int i = 0; i < StackPopTypes.Length; i++)
|
|
{
|
|
var xActualStackItem = aStack.ElementAt(i);
|
|
if (xActualStackItem == null)
|
|
{
|
|
continue;
|
|
}
|
|
if (StackPopTypes[i] == null)
|
|
{
|
|
StackPopTypes[i] = xActualStackItem;
|
|
aSituationChanged = true;
|
|
}
|
|
if ((StackPopTypes[i] != xActualStackItem)
|
|
&& (((StackPopTypes[i] == typeof(Byte)) || (StackPopTypes[i] == typeof(SByte)))
|
|
|| ((StackPopTypes[i] == typeof(UInt16)) || (StackPopTypes[i] == typeof(Int16)))
|
|
|| ((StackPopTypes[i] == typeof(UInt32)) || (StackPopTypes[i] == typeof(Int32)))
|
|
|| ((StackPopTypes[i] == typeof(UInt64)) || (StackPopTypes[i] == typeof(Int64)))
|
|
|| ((StackPopTypes[i] == typeof(UIntPtr)) || (StackPopTypes[i] == typeof(IntPtr)))))
|
|
{
|
|
StackPopTypes[i] = xActualStackItem;
|
|
aSituationChanged = true;
|
|
}
|
|
if (StackPopTypes[i] != xActualStackItem && !StackPopTypes[i].IsAssignableFrom(xActualStackItem)
|
|
&& !((StackPopTypes[i].IsPointer || StackPopTypes[i].IsByRef)
|
|
&& (xActualStackItem.IsPointer || xActualStackItem.IsByRef)))
|
|
{
|
|
throw new Exception($"OpCode {this} tries to pop item at stack position {i} with type {StackPopTypes[i]}, but actual type is {xActualStackItem}");
|
|
}
|
|
}
|
|
|
|
foreach (var xPopItem in StackPopTypes)
|
|
{
|
|
aStack.Pop();
|
|
}
|
|
try
|
|
{
|
|
DoInterpretStackTypes(ref aSituationChanged);
|
|
}
|
|
catch (Exception E)
|
|
{
|
|
throw new Exception("Error interpreting stacktypes for " + this, E);
|
|
}
|
|
foreach (var xPushItem in StackPushTypes)
|
|
{
|
|
aStack.Push(xPushItem);
|
|
}
|
|
DoInterpretNextInstructionStackTypes(aOpCodes, aStack, ref aSituationChanged, aMaxRecursionDepth);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Based on updated StackPopTypes, try to update
|
|
/// </summary>
|
|
protected virtual void DoInterpretStackTypes(ref bool aSituationChanged)
|
|
{
|
|
//
|
|
}
|
|
|
|
protected virtual void DoInterpretNextInstructionStackTypesIfNotYetProcessed(
|
|
IDictionary<int, ILOpCode> aOpCodes,
|
|
Stack<Type> aStack,
|
|
ref bool aSituationChanged,
|
|
int aMaxRecursionDepth)
|
|
{
|
|
ILOpCode xNextOpCode;
|
|
if (aOpCodes.TryGetValue(NextPosition, out xNextOpCode))
|
|
{
|
|
ILInterpretationDebugLine(() => String.Format("- Branching from {0} to {1}", this, xNextOpCode));
|
|
InterpretInstruction(xNextOpCode, aOpCodes, aStack, ref aSituationChanged, aMaxRecursionDepth);
|
|
}
|
|
}
|
|
|
|
protected virtual void DoInterpretNextInstructionStackTypes(
|
|
IDictionary<int, ILOpCode> aOpCodes,
|
|
Stack<Type> aStack,
|
|
ref bool aSituationChanged,
|
|
int aMaxRecursionDepth)
|
|
{
|
|
InterpretInstruction(NextPosition, aOpCodes, aStack, ref aSituationChanged, aMaxRecursionDepth);
|
|
}
|
|
|
|
protected void InterpretInstructionIfNotYetProcessed(
|
|
int aPosition,
|
|
IDictionary<int, ILOpCode> aOpCodes,
|
|
Stack<Type> aStack,
|
|
ref bool aSituationChanged,
|
|
int aMaxRecursionDepth)
|
|
{
|
|
ILOpCode xNextOpCode;
|
|
if (aOpCodes.TryGetValue(aPosition, out xNextOpCode))
|
|
{
|
|
ILInterpretationDebugLine(() => String.Format("- Branching from {0} to {1}", this, xNextOpCode));
|
|
InterpretInstruction(xNextOpCode, aOpCodes, aStack, ref aSituationChanged, aMaxRecursionDepth);
|
|
}
|
|
}
|
|
|
|
protected void InterpretInstruction(
|
|
int aPosition,
|
|
IDictionary<int, ILOpCode> aOpCodes,
|
|
Stack<Type> aStack,
|
|
ref bool aSituationChanged,
|
|
int aMaxRecursionDepth)
|
|
{
|
|
ILOpCode xNextOpCode;
|
|
if (aOpCodes.TryGetValue(aPosition, out xNextOpCode))
|
|
{
|
|
InterpretInstruction(xNextOpCode, aOpCodes, aStack, ref aSituationChanged, aMaxRecursionDepth);
|
|
}
|
|
}
|
|
|
|
protected void InterpretInstruction(
|
|
ILOpCode xNextOpCode,
|
|
IDictionary<int, ILOpCode> aOpCodes,
|
|
Stack<Type> aStack,
|
|
ref bool aSituationChanged,
|
|
int aMaxRecursionDepth)
|
|
{
|
|
xNextOpCode.InterpretStackTypes(aOpCodes, aStack, ref aSituationChanged, aMaxRecursionDepth - 1);
|
|
}
|
|
|
|
protected static bool IsIntegralType(Type type)
|
|
{
|
|
return type == typeof(byte) || type == typeof(sbyte) || type == typeof(ushort) || type == typeof(short)
|
|
|| type == typeof(int) || type == typeof(uint) || type == typeof(long) || type == typeof(ulong)
|
|
|| type == typeof(char) || type == typeof(IntPtr) || type == typeof(UIntPtr);
|
|
}
|
|
|
|
protected static bool IsIntegralTypeOrPointer(Type type)
|
|
{
|
|
return IsIntegralType(type) || type.IsPointer || type.IsByRef;
|
|
}
|
|
|
|
|
|
protected static bool IsPointer(Type aPointer)
|
|
{
|
|
return aPointer.IsPointer || aPointer.IsByRef || aPointer == typeof(IntPtr) || aPointer == typeof(UIntPtr);
|
|
}
|
|
|
|
[Conditional("DISABLED")]
|
|
public static void ILInterpretationDebugLine(Func<string> message)
|
|
{
|
|
//Console.WriteLine(message());
|
|
}
|
|
}
|
|
} |