Cosmos/source2/IL2PCU/Cosmos.IL2CPU/ILReader.cs
kudzu_cp 6010ecce83
2009-07-23 05:00:47 +00:00

277 lines
No EOL
10 KiB
C#

using System;
using System.IO;
using System.Reflection;
namespace Cosmos.IL2CPU {
public class ILReader {
private byte[] mBody;
private MethodBase mMethod;
private Module mModule;
public ILReader(MethodBase aMethod):this(aMethod, aMethod.GetMethodBody()) {
}
public ILReader(MethodBase aMethod, MethodBody aBody) {
mMethod = aMethod;
mModule = mMethod.Module;
mBody = aBody.GetILAsByteArray();
}
private ILOp.Code mOpCode;
private byte[] mOperand;
protected int mPosition = 0;
public ILOp.Code OpCode {
get {
return mOpCode;
}
}
public byte[] Operand {
get {
return mOperand;
}
}
private string mOperandValueStr;
public string OperandValueStr {
get {
if (mOperandValueStr == null) {
mOperandValueStr = mModule.ResolveString(OperandValueInt32);
}
return mOperandValueStr;
}
}
private MethodBase mOperandValueMethod;
public MethodBase OperandValueMethod {
get {
if (mOperandValueMethod == null) {
var xValue = OperandValueInt32;
if (((xValue & 0x6000000) == 0x6000000)
|| ((xValue & 0x2b000000) == 0x2b000000)
|| ((xValue & 0xa000000) == 0xA000000)) {
try {
Type[] xTypeGenArgs = null;
Type[] xMethodGenArgs = null;
if (mMethod.DeclaringType.IsGenericType) {
xTypeGenArgs = mMethod.DeclaringType.GetGenericArguments();
}
if (mMethod.IsGenericMethod) {
xMethodGenArgs = mMethod.GetGenericArguments();
}
// http://msdn.microsoft.com/en-us/library/ms145421(VS.85).aspx
mOperandValueMethod = mModule.ResolveMethod(OperandValueInt32, xTypeGenArgs, xMethodGenArgs);
} catch { }
}
}
return mOperandValueMethod;
}
}
private bool mIsShortcut;
private FieldInfo mOperandValueField;
public FieldInfo OperandValueField {
get {
if (mOperandValueField == null) {
try
{
Type[] xTypeGenArgs = null;
Type[] xMethodGenArgs = null;
if (mMethod.DeclaringType.IsGenericType)
{
xTypeGenArgs = mMethod.DeclaringType.GetGenericArguments();
}
if (mMethod.IsGenericMethod)
{
xMethodGenArgs = mMethod.GetGenericArguments();
}
mOperandValueField = mModule.ResolveField(OperandValueInt32,
xTypeGenArgs,
xMethodGenArgs);
}
catch {
}
}
return mOperandValueField;
}
}
private Type mOperandValueType;
public Type OperandValueType {
get {
if (mOperandValueType == null) {
try{
Type[] xTypeGenArgs = null;
Type[] xMethodGenArgs = null;
if (mMethod.DeclaringType.IsGenericType) {
xTypeGenArgs = mMethod.DeclaringType.GetGenericArguments();
}
if (mMethod.IsGenericMethod) {
xMethodGenArgs = mMethod.GetGenericArguments();
}
mOperandValueType = mModule.ResolveType(OperandValueInt32,
xTypeGenArgs,
xMethodGenArgs);
}catch {
}
}
return mOperandValueType;
}
}
public uint[] OperandValueBranchLocations {
get;
private set;
}
private int? mOperandValueInt32;
public int OperandValueInt32 {
get
{
if (mOperandValueInt32 == null)
{
if(Operand == null)
{
return 0;
}
if (!mIsShortcut)
{
byte[] xData = new byte[4];
Array.Copy(Operand, xData, Math.Min(4, Operand.Length));
mOperandValueInt32 = BitConverter.ToInt32(xData, 0);
}
else
{
sbyte xShortValue = (sbyte) Operand[0];
mOperandValueInt32 = xShortValue;
}
}
return mOperandValueInt32.Value;
}
}
private Single? mOperandValueSingle;
public Single OperandValueSingle {
get {
if (mOperandValueSingle == null) {
mOperandValueSingle = BitConverter.ToSingle(Operand, 0);
}
return mOperandValueSingle.Value;
}
}
private Double? mOperandValueDouble;
public Double OperandValueDouble {
get {
if (mOperandValueDouble == null) {
mOperandValueDouble = BitConverter.ToDouble(Operand, 0);
}
return mOperandValueDouble.Value;
}
}
protected byte ReadByte() {
var xResult = mBody[mPosition];
mPosition++;
return xResult;
}
public bool Read() {
// End of stream
if (mPosition == mBody.Length) {
return false;
}
// Get OpCode
ILOp.Code xOpCode;
if (mBody[mPosition] == 0xFE) {
xOpCode = (ILOp.Code)(mBody[mPosition] << 8 | mBody[mPosition + 1]);
// TODO: Eliminate this and use indexing below for data, and increment all at once
mPosition = mPosition + 2;
} else {
xOpCode = (ILOp.Code)mBody[mPosition];
mPosition++;
}
byte xOperandSize = ILOp.GetOperandSize(xOpCode);
mOpCode = ILOp.ExpandShortcut(xOpCode);
mOperand = null;
mOperandValueStr = null;
mOperandValueMethod = null;
mOperandValueField = null;
mOperandValueSingle = null;
mOperandValueType = null;
mOperandValueInt32 = null;
//mOperandValueBranchPosition = null;
OperandValueBranchLocations = null;
mOperandValueDouble = null;
mIsShortcut = mOpCode != xOpCode;
if (xOperandSize > 0) {
//TODO: Will we always use the Int32 result? Copying to array and then again seems wasteful
// Probably better to make typed reads for each type
mOperand = ReadOperand(xOperandSize);
mOperandValueInt32 = GetInt32FromOperandByteArray(mOperand);
} else {
if (mOpCode != xOpCode) {
long? xTempOperand = ILOp.GetShortcutOperand(xOpCode);
if (xTempOperand != null) {
mOperand = BitConverter.GetBytes(xTempOperand.Value);
}
}
if (mOpCode == ILOp.Code.Switch) {
int[] xBranchLocations1 = new int[ReadInt32()];
for (int i = 0; i < xBranchLocations1.Length; i++) {
xBranchLocations1[i] = ReadInt32();
}
uint[] xResult = new uint[xBranchLocations1.Length];
for (int i = 0; i < xBranchLocations1.Length; i++) {
if ((mPosition + xBranchLocations1[i]) < 0) {
xResult[i] = (uint)xBranchLocations1[i];
} else {
xResult[i] = (uint)(mPosition + xBranchLocations1[i]);
}
}
OperandValueBranchLocations = xResult;
}
}
return true;
}
private Int64 ReadInt64() {
long xResult = (mBody[mPosition + 7] << 56 | mBody[mPosition + 6] << 48 | mBody[mPosition + 5] << 40 | mBody[mPosition + 4] << 32
| mBody[mPosition + 3] << 24 | mBody[mPosition + 2] << 16 | mBody[mPosition + 1] << 8 | mBody[mPosition]);
mPosition = mPosition + 8;
return xResult;
}
private byte[] mOperandBuff = new byte[8];
//TODO: If we need further peformance, this function is one of the bigger users of time
// We can load more data at a time, and use an index into larger buffers
private byte[] ReadOperand(byte aOperandSize) {
for (int i = 0; i < aOperandSize; i++) {
//TODO: can do better than readbyte, can do locally
mOperandBuff[i] = ReadByte();
}
return mOperandBuff;
}
private static Int32 GetInt32FromOperandByteArray(byte[] aData) {
Int32 xResult = 0;
for (int i = 3; i >= 0; i--) {
xResult = xResult << 8 | aData[i];
}
return xResult;
}
private Int32 ReadInt32() {
Int32 xResult = (mBody[mPosition + 3] << 24 | mBody[mPosition + 2] << 16 | mBody[mPosition + 1] << 8 | mBody[mPosition]);
mPosition = mPosition + 4;
return xResult;
}
}
}