Cosmos/source/Indy.IL2CPU/Engine2.cs
Xenni_cp 9fc6a518c7 Changes to Engine.cs, Engine2.cs to fix bugs which caused compilation of anything using DynamicMethodEmit to fail.
The error appeared to be caused by improperly updating the GUI, so it should be able to be fixed later...
2009-05-19 03:34:12 +00:00

2947 lines
138 KiB
C#

#define VERBOSE_DEBUG
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Xml;
using Indy.IL2CPU.Assembler;
using Indy.IL2CPU.Assembler.X86;
using Indy.IL2CPU.IL;
using Indy.IL2CPU.Plugs;
using System.Runtime.InteropServices;
using System.Xml.Serialization;
using System.Collections.ObjectModel;
using System.Diagnostics.SymbolStore;
using Microsoft.Samples.Debugging.CorSymbolStore;
using System.Threading;
using System.Diagnostics;
namespace Indy.IL2CPU
{
public class Engine2
{
protected DebugLogHandler mDebugLog;
protected OpCodeMap mMap;
protected Assembler.Assembler mAssembler;
public TraceAssemblies TraceAssemblies { get; set; }
private SortedList<string, MethodBase> mPlugMethods;
private SortedList<Type, Dictionary<string, PlugFieldAttribute>> mPlugFields;
/// <summary>
/// Contains a list of all methods. This includes methods to be processed and already processed.
/// </summary>
protected IDictionary<MethodBase, QueuedMethodInformation> mMethods = new SortedList<MethodBase, QueuedMethodInformation>(new MethodBaseComparer());
protected ReaderWriterLocker mMethodsLocker = new ReaderWriterLocker();
/// <summary>
/// Contains a list of all static fields. This includes static fields to be processed and already processed.
/// </summary>
protected IDictionary<FieldInfo, QueuedStaticFieldInformation> mStaticFields = new SortedList<FieldInfo, QueuedStaticFieldInformation>(new FieldInfoComparer());
protected ReaderWriterLocker mStaticFieldsLocker = new ReaderWriterLocker();
protected IList<Type> mTypes = new List<Type>();
protected ReaderWriterLocker mTypesLocker = new ReaderWriterLocker();
protected TypeEqualityComparer mTypesEqualityComparer = new TypeEqualityComparer();
private byte mDebugComport;
private DebugMode mDebugMode;
private List<MLDebugSymbol> mSymbols = new List<MLDebugSymbol>();
private ReaderWriterLocker mSymbolsLocker = new ReaderWriterLocker();
private string mOutputDir;
public event Action<string> ChangingCurrentMethod;
public event Action<string> ChangingInnerMethod;
public event Action<int, int> CompilingMethods;
public event Action<int, int> CompilingStaticFields;
/// <summary>
/// Compiles an assembly to CPU-specific code. The entrypoint of the assembly will be
/// crawled to see what is neccessary, same goes for all dependencies.
/// </summary>
/// <remarks>For now, only entrypoints without params are supported!</remarks>
/// <param name="aAssembly">The assembly of which to crawl the entry-point method.</param>
/// <param name="aTargetPlatform">The platform to target when assembling the code.</param>
/// <param name="aOutput"></param>
public void Simulate(IEnumerable<string> aPlugs)
{
mMap = new Indy.IL2CPU.IL.X86.X86OpCodeMap();
mAssembler = new Assembler.X86.CosmosAssembler((byte)0);
InitializePlugs(aPlugs);
ScanAllMethods();
}
//TODO: Way too many params, these should be properties
public void Execute(string aAssembly,
TargetPlatformEnum aTargetPlatform,
Func<string, string> aGetFileNameForGroup,
IEnumerable<string> aPlugs,
DebugMode aDebugMode,
bool aGDBDebug,
byte aDebugComNumber,
string aOutputDir,
bool aUseBinaryEmission)
{
Assembly mCrawledAssembly;
try
{
if (aGetFileNameForGroup == null)
{
throw new ArgumentNullException("aGetFileNameForGroup");
}
mCrawledAssembly = Assembly.LoadFrom(aAssembly);
mDebugMode = aDebugMode;
MethodInfo xEntryPoint = (MethodInfo)mCrawledAssembly.EntryPoint;
if (xEntryPoint == null)
{
throw new NotSupportedException("No EntryPoint found!");
}
mOutputDir = aOutputDir;
Type xEntryPointType = xEntryPoint.DeclaringType;
xEntryPoint = xEntryPointType.GetMethod("Init", new Type[0]);
mDebugComport = aDebugComNumber;
AppDomainSetup xAppDomainSetup = new AppDomainSetup();
//xAppDomainSetup.PrivateBinPath=
//AppDomain.CurrentDomain.AppendPrivatePath(Path.GetDirectoryName(mCrawledAssembly.Location));
//List<string> xSearchDirs = new List<string>(new string[] { Path.GetDirectoryName(aAssembly), aAssemblyDir });
//xSearchDirs.AddRange((from item in aPlugs
// select Path.GetDirectoryName(item)).Distinct());
switch (aTargetPlatform)
{
case TargetPlatformEnum.X86:
{
mMap = new Indy.IL2CPU.IL.X86.X86OpCodeMap();
mAssembler = new Assembler.X86.CosmosAssembler(((aDebugMode != DebugMode.None) && (aDebugMode != DebugMode.MLUsingGDB))
? aDebugComNumber
: (byte)0);
break;
}
default:
throw new NotSupportedException("TargetPlatform '" + aTargetPlatform + "' not supported!");
}
InitializePlugs(aPlugs);
using (mAssembler)
{
mAssembler.Initialize();
//mAssembler.OutputType = Assembler.Win32.Assembler.OutputTypeEnum.Console;
//foreach (string xPlug in aPlugs) {
//this.I
List<Assembly> xAppDefs = new List<Assembly>();
xAppDefs.Add(mCrawledAssembly);
// AssemblyEqualityComparer xComparer = new AssemblyEqualityComparer();
foreach (Assembly xAsm in AppDomain.CurrentDomain.GetAssemblies())
{
Assembly xAssemblyDef = Assembly.LoadFrom(xAsm.Location);
if (!xAppDefs.Contains(xAssemblyDef))
{
xAppDefs.Add(xAssemblyDef);
}
}
mMap.Initialize(mAssembler, xAppDefs);
//!String.IsNullOrEmpty(aDebugSymbols);
IL.Op.QueueMethod += QueueMethod;
IL.Op.QueueStaticField += QueueStaticField;
try
{
using (mTypesLocker.AcquireWriterLock())
{
mTypes.Add(typeof(object));
}
using (mMethodsLocker.AcquireWriterLock())
{
mMethods.Add(RuntimeEngineRefs.InitializeApplicationRef,
new QueuedMethodInformation()
{
Processed = false,
Index = mMethods.Count
});
mMethods.Add(RuntimeEngineRefs.FinalizeApplicationRef,
new QueuedMethodInformation()
{
Processed = false,
Index = mMethods.Count
});
mMethods.Add(typeof(Assembler.Assembler).GetMethod("PrintException"),
new QueuedMethodInformation()
{
Index = mMethods.Count
});
mMethods.Add(VTablesImplRefs.LoadTypeTableRef,
new QueuedMethodInformation()
{
Processed = false,
Index = mMethods.Count
});
mMethods.Add(VTablesImplRefs.SetMethodInfoRef,
new QueuedMethodInformation()
{
Processed = false,
Index = mMethods.Count
});
mMethods.Add(VTablesImplRefs.IsInstanceRef,
new QueuedMethodInformation()
{
Processed = false,
Index = mMethods.Count
});
mMethods.Add(VTablesImplRefs.SetTypeInfoRef,
new QueuedMethodInformation()
{
Processed = false,
Index = mMethods.Count
});
mMethods.Add(VTablesImplRefs.GetMethodAddressForTypeRef,
new QueuedMethodInformation()
{
Processed = false,
Index = mMethods.Count
});
mMethods.Add(GCImplementationRefs.IncRefCountRef,
new QueuedMethodInformation()
{
Processed = false,
Index = mMethods.Count
});
mMethods.Add(GCImplementationRefs.DecRefCountRef,
new QueuedMethodInformation()
{
Processed = false,
Index = mMethods.Count
});
mMethods.Add(GCImplementationRefs.AllocNewObjectRef,
new QueuedMethodInformation()
{
Processed = false,
Index = mMethods.Count
});
mMethods.Add(xEntryPoint,
new QueuedMethodInformation()
{
Processed = false,
Index = mMethods.Count
});
}
ScanAllMethods();
ScanAllStaticFields();
mMap.PreProcess(mAssembler);
do
{
int xOldCount;
using (mMethodsLocker.AcquireReaderLock())
{
xOldCount = mMethods.Count;
}
ScanAllMethods();
ScanAllStaticFields();
ScanForMethodsToIncludeForVMT();
int xNewCount;
using (mMethodsLocker.AcquireReaderLock())
{
xNewCount = mMethods.Count;
}
if (xOldCount == xNewCount)
{
break;
}
} while (true);
// initialize the runtime engine
MainEntryPointOp xEntryPointOp = (MainEntryPointOp)GetOpFromType(mMap.MainEntryPointOp,
null,
null);
xEntryPointOp.Assembler = mAssembler;
xEntryPointOp.Enter(Assembler.Assembler.EntryPointName);
xEntryPointOp.Call(RuntimeEngineRefs.InitializeApplicationRef);
xEntryPointOp.Call("____INIT__VMT____");
using (mTypesLocker.AcquireWriterLock())
{
foreach (Type xType in mTypes)
{
foreach (MethodBase xMethod in xType.GetConstructors(BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public))
{
if (xMethod.IsStatic)
{
xEntryPointOp.Call(xMethod);
}
}
}
}
xEntryPointOp.Call(xEntryPoint);
if (xEntryPoint.ReturnType == typeof(void))
{
xEntryPointOp.Push(0);
}
// todo: implement support for returncodes?
xEntryPointOp.Call(RuntimeEngineRefs.FinalizeApplicationRef);
xEntryPointOp.Exit();
using (mMethodsLocker.AcquireWriterLock())
{
mMethods = new ReadOnlyDictionary<MethodBase, QueuedMethodInformation>(mMethods);
}
using (mStaticFieldsLocker.AcquireWriterLock())
{
mStaticFields = new ReadOnlyDictionary<FieldInfo, QueuedStaticFieldInformation>(mStaticFields);
}
ProcessAllMethods();
mMap.PostProcess(mAssembler);
ProcessAllStaticFields();
GenerateVMT(mDebugMode != DebugMode.None);
using (mSymbolsLocker.AcquireReaderLock())
{
if (mSymbols != null)
{
string xOutputFile = Path.Combine(mOutputDir, "debug.cxdb");
MLDebugSymbol.WriteSymbolsListToFile(mSymbols, xOutputFile);
}
}
}
finally
{
if (aUseBinaryEmission)
{
using (Stream xOutStream = new FileStream(Path.Combine(aOutputDir, "output.bin"), FileMode.Create))
{
Stopwatch xSW = new Stopwatch();
xSW.Start();
try
{
mAssembler.FlushBinary(xOutStream, 0x200000);
}
finally
{
xSW.Stop();
Debug.WriteLine(String.Format("Binary Emission took: {0}", xSW.Elapsed));
}
}
}
else // use external build
{
using (StreamWriter xOutput = new StreamWriter(aGetFileNameForGroup("main")))
{
mAssembler.FlushText(xOutput);
}
}
IL.Op.QueueMethod -= QueueMethod;
IL.Op.QueueStaticField -= QueueStaticField;
}
}
}
finally
{
}
}
// EDIT BELOW TO CHANGE THREAD COUNT:
private int mThreadCount = 1;// Environment.ProcessorCount;
private AutoResetEvent[] mThreadEvents = new AutoResetEvent[1];//new AutoResetEvent[mThreadCount];
private void ScanAllMethods()
{
if (mThreadCount == 1)
{
DoScanMethodsNoThreading();
return;
}
//Doku: work with a thread if someone is monitoring
if (ChangingCurrentMethod != null && ChangingInnerMethod != null)
{
DoScanMethods(0);
}
else
{
for (int i = 0; i < mThreadCount; i++)
{
mThreadEvents[i] = new AutoResetEvent(false);
var xThread = new Thread(DoScanMethods);
xThread.Start(i);
}
int xFinishedThreads = 0;
while (xFinishedThreads < mThreadCount)
{
for (int i = 0; i < mThreadCount; i++)
{
if (mThreadEvents[i] != null)
{
//HACK takes a while
// if (mThreadEvents[i].WaitOne(10, false))
{
mThreadEvents[i].Close();
mThreadEvents[i] = null;
xFinishedThreads++;
}
}
}
}
}
}
//UNThreaded
private void DoScanMethodsNoThreading()
{
//ProgressChanged.Invoke("Scanning methods");
int xIndex = -1;
MethodBase xCurrentMethod;
while (true)
{
xIndex++;
// using (mMethodsLocker.AcquireReaderLock())
{
xCurrentMethod = (from item in mMethods.Keys
where !mMethods[item].PreProcessed
select item).FirstOrDefault();
}
if (xCurrentMethod == null)
{
break;
}
if (ChangingCurrentMethod != null)
ChangingCurrentMethod.Invoke(xCurrentMethod.GetFullName());
//ProgressChanged.Invoke(String.Format("Scanning method: {0}", xCurrentMethod.GetFullName()));
EmitDependencyGraphLine(true, xCurrentMethod.GetFullName());
try
{
RegisterType(xCurrentMethod.DeclaringType);
// using (mMethodsLocker.AcquireReaderLock())
{
mMethods[xCurrentMethod].PreProcessed = true;
}
if (xCurrentMethod.IsAbstract)
{
continue;
}
string xMethodName = Label.GenerateLabelName(xCurrentMethod);
TypeInformation xTypeInfo = null;
if (!xCurrentMethod.IsStatic)
{
xTypeInfo = GetTypeInfo(xCurrentMethod.DeclaringType);
}
MethodInformation xMethodInfo;
// using (mMethodsLocker.AcquireReaderLock())
{
xMethodInfo = GetMethodInfo(xCurrentMethod,
xCurrentMethod,
xMethodName,
xTypeInfo,
mDebugMode != DebugMode.None,
mMethods[xCurrentMethod].Info);
}
MethodBase xCustomImplementation = GetCustomMethodImplementation(xMethodName);
if (xCustomImplementation != null)
{
try
{
QueueMethod(xCustomImplementation);
}
catch (Exception e)
{
throw new Exception("Method " + xCurrentMethod.GetFullName() + " has called " + e.Message + "! Probably it needs to be plugged");
}
// using (mMethodsLocker.AcquireReaderLock())
{
mMethods[xCurrentMethod].Implementation = xCustomImplementation;
}
continue;
}
Type xOpType = mMap.GetOpForCustomMethodImplementation(xMethodName);
if (xOpType != null)
{
Op xMethodOp = GetOpFromType(xOpType, null, xMethodInfo);
if (xMethodOp != null)
{
continue;
}
}
if (mMap.HasCustomAssembleImplementation(xMethodInfo))
{
mMap.ScanCustomAssembleImplementation(xMethodInfo);
continue;
}
//xCurrentMethod.GetMethodImplementationFlags() == MethodImplAttributes.
ILReader xReader = new ILReader(xCurrentMethod);
MethodBody xBody = xCurrentMethod.GetMethodBody();
// todo: add better detection of implementation state
if (xBody != null)
{
mInstructionsToSkip = 0;
mAssembler.StackContents.Clear();
var xInstructionInfos = new List<DebugSymbolsAssemblyTypeMethodInstruction>();
while (xReader.Read())
{
SortedList<string, object> xInfo = null;
// using (mMethodsLocker.AcquireReaderLock())
{
xInfo = mMethods[xCurrentMethod].Info;
}
mMap.ScanILCode(xReader, xMethodInfo, xInfo);
}
}
}
catch (Exception e)
{
OnDebugLog(LogSeverityEnum.Error, xCurrentMethod.GetFullName());
OnDebugLog(LogSeverityEnum.Warning, e.ToString());
throw;
}
}
foreach (Type xType in mTypes)
{
foreach (MethodBase xMethod in xType.GetConstructors(BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public))
{
if (xMethod.IsStatic)
{
try
{
QueueMethod(xMethod);
}
catch (Exception e)
{
throw new Exception("Method " + xCurrentMethod.GetFullName() + " has called " + e.Message + "! Probably it needs to be plugged");
}
}
}
}
}
private void DoScanMethods(object data)
{
//ProgressChanged.Invoke("Scanning methods");
int xThreadIndex = (int)data;
try
{
int xIndex = -1;
MethodBase xCurrentMethod;
while (true)
{
xIndex++;
if ((xIndex % mThreadCount) != xThreadIndex)
{
continue;
}
using (mMethodsLocker.AcquireReaderLock())
{
xCurrentMethod = (from item in mMethods.Keys
where !mMethods[item].PreProcessed
select item).FirstOrDefault();
}
if (xCurrentMethod == null)
{
break;
}
if (ChangingCurrentMethod != null)
ChangingCurrentMethod.Invoke(xCurrentMethod.GetFullName());
//ProgressChanged.Invoke(String.Format("Scanning method: {0}", xCurrentMethod.GetFullName()));
EmitDependencyGraphLine(true, xCurrentMethod.GetFullName());
try
{
RegisterType(xCurrentMethod.DeclaringType);
using (mMethodsLocker.AcquireReaderLock())
{
mMethods[xCurrentMethod].PreProcessed = true;
}
if (xCurrentMethod.IsAbstract)
{
continue;
}
string xMethodName = Label.GenerateLabelName(xCurrentMethod);
TypeInformation xTypeInfo = null;
if (!xCurrentMethod.IsStatic)
{
xTypeInfo = GetTypeInfo(xCurrentMethod.DeclaringType);
}
MethodInformation xMethodInfo;
using (mMethodsLocker.AcquireReaderLock())
{
xMethodInfo = GetMethodInfo(xCurrentMethod,
xCurrentMethod,
xMethodName,
xTypeInfo,
mDebugMode != DebugMode.None,
mMethods[xCurrentMethod].Info);
}
MethodBase xCustomImplementation = GetCustomMethodImplementation(xMethodName);
if (xCustomImplementation != null)
{
try
{
QueueMethod(xCustomImplementation);
}
catch (Exception e)
{
throw new Exception("Method " + xCurrentMethod.GetFullName() + " has called " + e.Message + "! Probably it needs to be plugged");
}
using (mMethodsLocker.AcquireReaderLock())
{
mMethods[xCurrentMethod].Implementation = xCustomImplementation;
}
continue;
}
Type xOpType = mMap.GetOpForCustomMethodImplementation(xMethodName);
if (xOpType != null)
{
Op xMethodOp = GetOpFromType(xOpType, null, xMethodInfo);
if (xMethodOp != null)
{
continue;
}
}
if (mMap.HasCustomAssembleImplementation(xMethodInfo))
{
mMap.ScanCustomAssembleImplementation(xMethodInfo);
continue;
}
//xCurrentMethod.GetMethodImplementationFlags() == MethodImplAttributes.
MethodBody xBody = xCurrentMethod.GetMethodBody();
// todo: add better detection of implementation state
if (xBody != null)
{
mInstructionsToSkip = 0;
mAssembler.StackContents.Clear();
ILReader xReader = new ILReader(xCurrentMethod);
var xInstructionInfos = new List<DebugSymbolsAssemblyTypeMethodInstruction>();
while (xReader.Read())
{
SortedList<string, object> xInfo = null;
using (mMethodsLocker.AcquireReaderLock())
{
xInfo = mMethods[xCurrentMethod].Info;
}
mMap.ScanILCode(xReader, xMethodInfo, xInfo);
}
}
}
catch (Exception e)
{
OnDebugLog(LogSeverityEnum.Error, xCurrentMethod.GetFullName());
OnDebugLog(LogSeverityEnum.Warning, e.ToString());
throw;
}
}
using (mTypesLocker.AcquireReaderLock())
{
foreach (Type xType in mTypes)
{
foreach (MethodBase xMethod in xType.GetConstructors(BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public))
{
if (xMethod.IsStatic)
{
try
{
QueueMethod(xMethod);
}
catch (Exception e)
{
throw new Exception("Method " + xCurrentMethod.GetFullName() + " has called " + e.Message + "! Probably it needs to be plugged");
}
}
}
}
}
}
finally
{
mThreadEvents[xThreadIndex].Set();
}
}
private void ScanAllStaticFields()
{
}
private void GenerateDebugSymbols()
{
/*var xAssemblyComparer = new AssemblyEqualityComparer();
var xTypeComparer = new TypeEqualityComparer();
var xDbgAssemblies = new List<DebugSymbolsAssembly>();
int xTypeCount = mTypes.Count;
try {
foreach (var xAssembly in (from item in mTypes
select item.Assembly).Distinct(xAssemblyComparer)) {
var xDbgAssembly = new DebugSymbolsAssembly();
var xDbgAssemblyTypes = new List<DebugSymbolsAssemblyType>();
xDbgAssembly.FileName = xAssembly.Location;
xDbgAssembly.FullName = xAssembly.GetName().FullName;
//if (xDbgAssembly.FullName == "Cosmos.Hardware, Version=1.0.0.0, Culture=neutral, PublicKeyToken=5ae71220097cb983") {
// System.Diagnostics.Debugger.Break();
//}
for (int xIdxTypes = 0; xIdxTypes < mTypes.Count; xIdxTypes++) {
var xType = mTypes[xIdxTypes];
if (!xAssemblyComparer.Equals(xAssembly, xType.Assembly)) {
continue;
}
var xDbgType = new DebugSymbolsAssemblyType();
//if (xType.FullName == "Cosmos.Hardware.Screen.Text") {
// System.Diagnostics.Debugger.Break();
//}
if (xType.BaseType != null) {
xDbgType.BaseTypeId = GetTypeId(xType.BaseType);
}
xDbgType.TypeId = xIdxTypes;
xDbgType.FullName = xType.FullName;
var xTypeFields = new List<DebugSymbolsAssemblyTypeField>();
var xTypeInfo = GetTypeInfo(xType);
xDbgType.StorageSize = GetFieldStorageSize(xType);
foreach (var xField in xType.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.buildPath)) {
var xDbgField = new DebugSymbolsAssemblyTypeField();
xDbgField.Name = xField.Name;
xDbgField.IsStatic = xField.IsStatic;
if (xField.IsPublic) {
xDbgField.Visibility = "Public";
} else {
if (xField.IsPrivate) {
xDbgField.Visibility = "Private";
} else {
if (xField.IsFamily) {
xDbgField.Visibility = "Protected";
} else {
xDbgField.Visibility = "Internal";
}
}
}
xDbgField.FieldType = GetTypeId(xField.FieldType);
if (xDbgField.IsStatic) {
xDbgField.Address = DataMember.GetStaticFieldName(xField);
} else {
xDbgField.Address = "+" + xTypeInfo.Fields[xField.GetFullName()].Offset;
}
xTypeFields.Add(xDbgField);
}
xDbgType.Field = xTypeFields.ToArray();
var xTypeMethods = new List<DebugSymbolsAssemblyTypeMethod>();
foreach (var xMethod in xType.GetMethods(BindingFlags.ExactBinding | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.buildPath | BindingFlags.Instance).Cast<MethodBase>().Union(xType.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.buildPath | BindingFlags.Instance))) {
var xIdxMethods = mMethods.IndexOfKey(xMethod);
if (xIdxMethods == -1) {
continue;
}
//var xMethod = mMethods.Keys[xIdxMethods];
//if (!xTypeComparer.Equals(xMethod.DeclaringType, xType)) {
// continue;
//}
var xDbgMethod = new DebugSymbolsAssemblyTypeMethod();
xDbgMethod.Name = xMethod.Name;
xDbgMethod.MethodId = xIdxMethods;
xDbgMethod.Address = Label.GenerateLabelName(xMethod);
if (xMethod is ConstructorInfo) {
xDbgMethod.ReturnTypeId = GetTypeId(typeof(void));
} else {
var xTheMethod = xMethod as MethodInfo;
if (xTheMethod != null) {
xDbgMethod.ReturnTypeId = GetTypeId(xTheMethod.ReturnType);
} else {
xDbgMethod.ReturnTypeId = GetTypeId(typeof(void));
}
}
if (xMethod.IsPublic) {
xDbgMethod.Visibility = "Public";
} else {
if (xMethod.IsPrivate) {
xDbgMethod.Visibility = "Private";
} else {
if (xMethod.IsFamily) {
xDbgMethod.Visibility = "Protected";
} else {
xDbgMethod.Visibility = "Internal";
}
}
}
xTypeMethods.Add(xDbgMethod);
MethodBody xBody = xMethod.GetMethodBody();
if (xBody != null) {
var xDbgLocals = new List<DebugSymbolsAssemblyTypeMethodLocal>();
var xMethodInfo = GetMethodInfo(xMethod, xMethod, Label.GenerateLabelName(xMethod), xTypeInfo);
if (xBody.LocalVariables != null) {
foreach (var xLocal in xBody.LocalVariables) {
var xDbgLocal = new DebugSymbolsAssemblyTypeMethodLocal();
xDbgLocal.Name = xLocal.LocalIndex.ToString();
xDbgLocal.LocalTypeId = GetTypeId(xLocal.LocalType);
xDbgLocal.RelativeStartAddress = xMethodInfo.Locals[xLocal.LocalIndex].VirtualAddresses.First();
xDbgLocals.Add(xDbgLocal);
}
}
xDbgMethod.Local = xDbgLocals.ToArray();
}
xDbgMethod.Body = mMethods.Values[xIdxMethods].Instructions;
}
xDbgType.Method = xTypeMethods.ToArray();
xDbgAssemblyTypes.Add(xDbgType);
}
xDbgAssembly.Type = xDbgAssemblyTypes.ToArray();
xDbgAssemblies.Add(xDbgAssembly);
}
} finally {
if (xTypeCount != mTypes.Count) {
Console.WriteLine("TypeCount changed (was {0}, new {1})", xTypeCount, mTypes.Count);
Console.WriteLine("Last Type: {0}", mTypes.Last().FullName);
}
}*/
}
private void GenerateVMT(bool aDebugMode)
{
Op xOp = GetOpFromType(mMap.MethodHeaderOp,
null,
new MethodInformation("____INIT__VMT____",
new MethodInformation.Variable[0],
new MethodInformation.Argument[0],
0,
false,
null,
null,
typeof(void),
aDebugMode,
new Dictionary<string, object>()));
xOp.Assembler = mAssembler;
xOp.Assemble();
InitVmtImplementationOp xInitVmtOp = (InitVmtImplementationOp)GetOpFromType(mMap.InitVmtImplementationOp,
null,
null);
xInitVmtOp.Assembler = mAssembler;
xInitVmtOp.Types = mTypes;
xInitVmtOp.SetTypeInfoRef = VTablesImplRefs.SetTypeInfoRef;
xInitVmtOp.SetMethodInfoRef = VTablesImplRefs.SetMethodInfoRef;
xInitVmtOp.LoadTypeTableRef = VTablesImplRefs.LoadTypeTableRef;
xInitVmtOp.TypesFieldRef = VTablesImplRefs.VTablesImplDef.GetField("mTypes",
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance);
using (mMethodsLocker.AcquireReaderLock())
{
xInitVmtOp.Methods = mMethods.Keys.ToList();
}
xInitVmtOp.VTableEntrySize = GetFieldStorageSize(GetType("",
typeof(VTable).FullName.Replace('+',
'.')));
xInitVmtOp.GetMethodIdentifier += delegate(MethodBase aMethod)
{
if (aMethod.GetFullName() == "System.Reflection.Cache.InternalCache System.Reflection.MemberInfo.get_Cache()")
{
System.Diagnostics.Debugger.Break();
}
ParameterInfo[] xParams = aMethod.GetParameters();
Type[] xParamTypes = new Type[xParams.Length];
for (int i = 0; i < xParams.Length; i++)
{
xParamTypes[i] = xParams[i].ParameterType;
}
MethodBase xMethod = GetUltimateBaseMethod(aMethod,
xParamTypes,
aMethod.DeclaringType);
return GetMethodIdentifier(xMethod);
};
using (mTypesLocker.AcquireWriterLock())
{
xInitVmtOp.Assemble();
}
xOp = GetOpFromType(mMap.MethodFooterOp,
null,
new MethodInformation("____INIT__VMT____",
new MethodInformation.Variable[0],
new MethodInformation.Argument[0],
0,
false,
null,
null,
typeof(void),
aDebugMode,
new Dictionary<string, object>()));
xOp.Assembler = mAssembler;
xOp.Assemble();
}
private void ScanForMethodsToIncludeForVMT()
{
List<Type> xCheckedTypes = new List<Type>();
int i = -1;
while (true)
{
i++;
MethodBase xMethod;
using (mMethodsLocker.AcquireReaderLock())
{
if (i == mMethods.Count)
{
break;
}
xMethod = mMethods.ElementAt(i).Key;
}
if (xMethod.IsStatic)
{
continue;
}
Type xCurrentType = xMethod.DeclaringType;
if (!xCheckedTypes.Contains(xCurrentType,
mTypesEqualityComparer))
{
xCheckedTypes.Add(xCurrentType);
}
MethodBase toBeQueuedMethod = GetUltimateBaseMethod(xMethod,
(from item in xMethod.GetParameters()
select item.ParameterType).ToArray(),
xCurrentType);
try
{
QueueMethod(toBeQueuedMethod);
}
catch (Exception e)
{
throw new Exception("Method " + xMethod.GetFullName() + " has called " + e.Message + "! Probably it needs to be plugged");
}
}
using (mTypesLocker.AcquireReaderLock())
{
foreach (Type xType in mTypes)
{
if (!xCheckedTypes.Contains(xType,
mTypesEqualityComparer))
{
xCheckedTypes.Add(xType);
}
}
}
for (i = 0; i < xCheckedTypes.Count; i++)
{
Type xCurrentType = xCheckedTypes[i];
while (xCurrentType != null)
{
if (!xCheckedTypes.Contains(xCurrentType,
mTypesEqualityComparer))
{
xCheckedTypes.Add(xCurrentType);
}
if (xCurrentType.FullName == "System.Object")
{
break;
}
if (xCurrentType.BaseType == null)
{
break;
}
xCurrentType = xCurrentType.BaseType;
}
}
foreach (Type xTD in xCheckedTypes)
{
foreach (MethodBase xMethod in xTD.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly))
{
if (!xMethod.IsStatic)
{
if (xTD.BaseType == null)
{
continue;
}
if (xMethod.IsVirtual && !xMethod.IsConstructor)
{
Type xCurrentInspectedType = xTD.BaseType;
ParameterInfo[] xParams = xMethod.GetParameters();
Type[] xMethodParams = new Type[xParams.Length];
for (int k = 0; k < xParams.Length; k++)
{
xMethodParams[k] = xParams[k].ParameterType;
}
MethodBase xBaseMethod = GetUltimateBaseMethod(xMethod,
xMethodParams,
xTD);
if (xBaseMethod != null && xBaseMethod != xMethod)
{
bool xNeedsRegistering = false;
using (mMethodsLocker.AcquireReaderLock())
{
xNeedsRegistering = mMethods.ContainsKey(xBaseMethod);
}
if (xNeedsRegistering)
{
QueueMethod(xMethod);
}
}
}
}
}
}
int j = -1;
while (true)
{
j++;
KeyValuePair<MethodBase, QueuedMethodInformation> xMethod;
using (mMethodsLocker.AcquireReaderLock())
{
if (j == mMethods.Count)
{
break;
}
xMethod = mMethods.Skip(j).First();
}
if (xMethod.Key.DeclaringType.IsInterface)
{
var xInterface = xMethod.Key.DeclaringType;
i = -1;
while (true)
{
Type xImplType;
i++;
using (mTypesLocker.AcquireReaderLock())
{
if (i == mTypes.Count)
{
break;
}
xImplType = mTypes.ElementAt(i);
}
if (xImplType.IsInterface)
{
continue;
}
if (!xInterface.IsAssignableFrom(xImplType))
{
continue;
}
var xActualMethod = xImplType.GetMethod(xInterface.FullName + "." + xMethod.Key.Name,
(from xParam in xMethod.Key.GetParameters()
select xParam.ParameterType).ToArray());
if (xActualMethod == null)
{
// get private implemenation
xActualMethod = xImplType.GetMethod(xMethod.Key.Name,
(from xParam in xMethod.Key.GetParameters()
select xParam.ParameterType).ToArray());
}
if (xActualMethod == null)
{
try
{
var xMap = xImplType.GetInterfaceMap(xInterface);
for (int k = 0; k < xMap.InterfaceMethods.Length; k++)
{
if (xMap.InterfaceMethods[k] == xMethod.Key)
{
xActualMethod = xMap.TargetMethods[k];
break;
}
}
}
catch
{
}
}
if (xActualMethod != null)
{
QueueMethod(xActualMethod);
}
}
}
}
}
private MethodBase GetUltimateBaseMethod(MethodBase aMethod,
Type[] aMethodParams,
Type aCurrentInspectedType)
{
MethodBase xBaseMethod = null;
//try {
while (true)
{
if (aCurrentInspectedType.BaseType == null)
{
break;
}
aCurrentInspectedType = aCurrentInspectedType.BaseType;
MethodBase xFoundMethod = aCurrentInspectedType.GetMethod(aMethod.Name,
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance,
Type.DefaultBinder,
aMethodParams,
new ParameterModifier[0]);
if (xFoundMethod == null)
{
break;
}
ParameterInfo[] xParams = xFoundMethod.GetParameters();
bool xContinue = true;
for (int i = 0; i < xParams.Length; i++)
{
if (xParams[i].ParameterType != aMethodParams[i])
{
xContinue = false;
continue;
}
}
if (!xContinue)
{
continue;
}
if (xFoundMethod != null)
{
xBaseMethod = xFoundMethod;
if (xFoundMethod.IsVirtual == aMethod.IsVirtual && xFoundMethod.IsPrivate == false && xFoundMethod.IsPublic == aMethod.IsPublic && xFoundMethod.IsFamily == aMethod.IsFamily && xFoundMethod.IsFamilyAndAssembly == aMethod.IsFamilyAndAssembly && xFoundMethod.IsFamilyOrAssembly == aMethod.IsFamilyOrAssembly && xFoundMethod.IsFinal == false)
{
var xFoundMethInfo = xFoundMethod as MethodInfo;
var xBaseMethInfo = xBaseMethod as MethodInfo;
if (xFoundMethInfo == null && xBaseMethInfo == null)
{
xBaseMethod = xFoundMethod;
}
if (xFoundMethInfo != null && xBaseMethInfo != null)
{
if (xFoundMethInfo.ReturnType.AssemblyQualifiedName.Equals(xBaseMethInfo.ReturnType.AssemblyQualifiedName))
{
xBaseMethod = xFoundMethod;
}
}
//xBaseMethod = xFoundMethod;
}
}
//else
//{
// xBaseMethod = xFoundMethod;
//}
}
//} catch (Exception) {
// todo: try to get rid of the try..catch
//}
return xBaseMethod ?? aMethod;
}
//todo: remove?
public MethodBase GetDefinitionFromMethodBase2(MethodBase aRef)
{
Type xTypeDef;
bool xIsArray = false;
if (aRef.DeclaringType.FullName.Contains("[]") || aRef.DeclaringType.FullName.Contains("[,]") || aRef.DeclaringType.FullName.Contains("[,,]"))
{
xTypeDef = typeof(Array);
xIsArray = true;
}
else
{
xTypeDef = aRef.DeclaringType;
}
MethodBase xMethod = null;
if (xIsArray)
{
Type[] xParams = (from item in aRef.GetParameters()
select item.ParameterType).ToArray();
if (aRef.Name == "Get")
{
xMethod = xTypeDef.GetMethod("GetValue",
xParams);
}
if (aRef.Name == "Set")
{
xMethod = xTypeDef.GetMethod("SetValue",
xParams);
}
}
if (xMethod == null)
{
foreach (MethodBase xFoundMethod in xTypeDef.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static))
{
if (xFoundMethod.Name != aRef.Name)
{
continue;
}
string[] xRefNameParts = aRef.ToString().Split(' ');
string[] xFoundNameParts = xFoundMethod.ToString().Split(' ');
if (xFoundNameParts[0] != xRefNameParts[0])
{
//if (!(xFoundMethod.ReturnType.ReturnType is GenericParameter && aRef.ReturnType.ReturnType is GenericParameter)) {
// ArrayType xFoundArray = xFoundMethod.ReturnType.ReturnType as ArrayType;
// ArrayType xArray = aRef.ReturnType.ReturnType as ArrayType;
// if (xArray != null && xFoundArray != null) {
// if (xArray.Dimensions.Count != xFoundArray.Dimensions.Count) {
// continue;
// }
// GenericParameter xGenericParam = xArray.ElementType as GenericParameter;
// GenericParameter xFoundGenericParam = xFoundArray.ElementType as GenericParameter;
// if (xGenericParam != null && xFoundGenericParam != null) {
// if (xGenericParam.NextPosition != xFoundGenericParam.NextPosition) {
// continue;
// }
// }
// }
//}
continue;
}
ParameterInfo[] xFoundParams = xFoundMethod.GetParameters();
ParameterInfo[] xRefParams = aRef.GetParameters();
if (xFoundParams.Length != xRefParams.Length)
{
continue;
}
bool xMismatch = false;
for (int i = 0; i < xFoundParams.Length; i++)
{
if (xFoundParams[i].ParameterType.FullName != xRefParams[i].ParameterType.FullName)
{
//if (xFoundMethod.Parameters[i].ParameterType is GenericParameter && aRef.Parameters[i].ParameterType is GenericParameter) {
// continue;
//}
xMismatch = true;
break;
}
}
if (!xMismatch)
{
xMethod = xFoundMethod;
}
}
}
if (xMethod != null)
{
return xMethod;
}
//xMethod = xTypeDef.GetConstructor(aRef.Name == MethodBase.Cctor, aRef.Parameters);
//if (xMethod != null && (aRef.Name == MethodBase.Cctor || aRef.Name == MethodBase.Ctor)) {
// return xMethod;
//}
throw new Exception("Couldn't find Method! ('" + aRef.GetFullName() + "'");
}
/// <summary>
/// Gives the size to store an instance of the <paramref name="aType"/> for use in a field.
/// </summary>
/// <remarks>For classes, this is the pointer size.</remarks>
/// <param name="aType"></param>
/// <returns></returns>
public uint GetFieldStorageSize(Type aType)
{
if (aType.FullName == "System.Void")
{
return 0;
}
if ((!aType.IsValueType && aType.IsClass) || aType.IsInterface)
{
return 4;
}
switch (aType.FullName)
{
case "System.Char":
return 2;
case "System.Byte":
case "System.SByte":
return 1;
case "System.UInt16":
case "System.Int16":
return 2;
case "System.UInt32":
case "System.Int32":
return 4;
case "System.UInt64":
case "System.Int64":
return 8;
// for now hardcode IntPtr and UIntPtr to be 32-bit
case "System.UIntPtr":
case "System.IntPtr":
return 4;
case "System.Boolean":
return 1;
case "System.Single":
return 4;
case "System.Double":
return 8;
case "System.Decimal":
return 16;
case "System.Guid":
return 16;
case "System.DateTime":
return 8; // todo: check for correct size
}
if (aType.FullName.EndsWith("*"))
{
// pointer
return 4;
}
// array
//TypeSpecification xTypeSpec = aType as TypeSpecification;
//if (xTypeSpec != null) {
// return 4;
//}
if (aType.IsEnum)
{
return GetFieldStorageSize(aType.GetField("value__").FieldType);
}
if (aType.IsValueType)
{
StructLayoutAttribute xSLA = aType.StructLayoutAttribute;
if (xSLA != null)
{
if (xSLA.Size > 0)
{
return (uint)xSLA.Size;
}
}
}
uint xResult;
GetTypeFieldInfo(aType,
out xResult);
return xResult;
}
private string GetGroupForType(Type aType)
{
return aType.Module.Assembly.GetName().Name;
}
protected void EmitTracer(Op aOp, string aNamespace, int aPos, int[] aCodeOffsets, string aLabel)
{
// NOTE - These if statemens can be optimized down - but clarity is
// more importnat the optimizations would not offer much benefit
// Determine if a new DebugStub should be emitted
//bool xEmit = false;
// Skip NOOP's so we dont have breakpoints on them
//TODO: Each IL op should exist in IL, and descendants in IL.X86.
// Because of this we have this hack
if (aOp.ToString() == "Indy.IL2CPU.IL.X86.Nop")
{
return;
}
else if (mDebugMode == DebugMode.None)
{
return;
}
else if (mDebugMode == DebugMode.Source)
{
// If the current position equals one of the offsets, then we have
// reached a new atomic C# statement
if (aCodeOffsets != null)
{
if (aCodeOffsets.Contains(aPos) == false)
{
return;
}
}
}
// Check options for Debug Level
// Set based on TracedAssemblies
if (TraceAssemblies == TraceAssemblies.Cosmos || TraceAssemblies == TraceAssemblies.User)
{
if (aNamespace.StartsWith("System.", StringComparison.InvariantCultureIgnoreCase))
{
return;
}
else if (aNamespace.ToLower() == "system")
{
return;
}
else if (aNamespace.StartsWith("Microsoft.", StringComparison.InvariantCultureIgnoreCase))
{
return;
}
}
if (TraceAssemblies == TraceAssemblies.User)
{
//TODO: Maybe an attribute that could be used to turn tracing on and off
//TODO: This doesnt match Cosmos.Kernel exact vs Cosmos.Kernel., so a user
// could do Cosmos.KernelMine and it will fail. Need to fix this
if (aNamespace.StartsWith("Cosmos.Kernel", StringComparison.InvariantCultureIgnoreCase))
{
return;
}
else if (aNamespace.StartsWith("Cosmos.Sys", StringComparison.InvariantCultureIgnoreCase))
{
return;
}
else if (aNamespace.StartsWith("Cosmos.Hardware", StringComparison.InvariantCultureIgnoreCase))
{
return;
}
else if (aNamespace.StartsWith("Indy.IL2CPU", StringComparison.InvariantCultureIgnoreCase))
{
return;
}
}
// If we made it this far, emit the Tracer
mMap.EmitOpDebugHeader(mAssembler, 0, aLabel);
}
private void ProcessAllStaticFields()
{
int i = -1;
int xCount = 0;
while (true)
{
i++;
FieldInfo xCurrentField;
using (mStaticFieldsLocker.AcquireReaderLock())
{
xCount = mStaticFields.Count;
if (i == xCount)
{
break;
}
xCurrentField = mStaticFields.Keys.ElementAt(i);
}
CompilingStaticFields(i, xCount);
//ProgressChanged.Invoke(String.Format("Processing static field: {0}", xCurrentField.GetFullName()));
string xFieldName = xCurrentField.GetFullName();
xFieldName = DataMember.GetStaticFieldName(xCurrentField);
if (mAssembler.DataMembers.Count(x => x.Name == xFieldName) == 0)
{
var xItem = (from item in xCurrentField.GetCustomAttributes(false)
where item.GetType().FullName == "ManifestResourceStreamAttribute"
select item).FirstOrDefault();
string xManifestResourceName = null;
if (xItem != null)
{
var xItemType = xItem.GetType();
xManifestResourceName = (string)xItemType.GetField("ResourceName").GetValue(xItem);
}
if (xManifestResourceName != null)
{
//RegisterType(xCurrentField.FieldType);
//string xFileName = Path.Combine(mOutputDir,
// (xCurrentField.DeclaringType.Assembly.FullName + "__" + xManifestResourceName).Replace(",",
// "_") + ".res");
//using (var xStream = xCurrentField.DeclaringType.Assembly.GetManifestResourceStream(xManifestResourceName)) {
// if (xStream == null) {
// throw new Exception("Resource '" + xManifestResourceName + "' not found!");
// }
// using (var xTarget = File.Create(xFileName)) {
// // todo: abstract this array code out.
// xTarget.Write(BitConverter.GetBytes(Engine.RegisterType(Engine.GetType("mscorlib",
// "System.Array"))),
// 0,
// 4);
// xTarget.Write(BitConverter.GetBytes((uint)InstanceTypeEnum.StaticEmbeddedArray),
// 0,
// 4);
// xTarget.Write(BitConverter.GetBytes((int)xStream.Length), 0, 4);
// xTarget.Write(BitConverter.GetBytes((int)1), 0, 4);
// var xBuff = new byte[128];
// while (xStream.Position < xStream.Length) {
// int xBytesRead = xStream.Read(xBuff, 0, 128);
// xTarget.Write(xBuff, 0, xBytesRead);
// }
// }
//}
//mAssembler.DataMembers.Add(new DataMember("___" + xFieldName + "___Contents",
// "incbin",
// "\"" + xFileName + "\""));
//mAssembler.DataMembers.Add(new DataMember(xFieldName,
// "dd",
// "___" + xFieldName + "___Contents"));
throw new NotImplementedException();
}
else
{
RegisterType(xCurrentField.FieldType);
uint xTheSize;
//string theType = "db";
Type xFieldTypeDef = xCurrentField.FieldType;
if (!xFieldTypeDef.IsClass || xFieldTypeDef.IsValueType)
{
xTheSize = GetFieldStorageSize(xCurrentField.FieldType);
}
else
{
xTheSize = 4;
}
byte[] xData = new byte[xTheSize];
try
{
object xValue = xCurrentField.GetValue(null);
if (xValue != null)
{
try
{
xData = new byte[xTheSize];
if (xValue.GetType().IsValueType)
{
for (int x = 0; x < xTheSize; x++)
{
xData[x] = Marshal.ReadByte(xValue,
x);
}
}
}
catch
{
}
}
}
catch
{
}
mAssembler.DataMembers.Add(new DataMember(xFieldName, xData));
}
}
using (mStaticFieldsLocker.AcquireReaderLock())
{
mStaticFields[xCurrentField].Processed = true;
}
}
CompilingStaticFields(i, xCount);
}
private ISymbolReader GetSymbolReaderForAssembly(Assembly aAssembly)
{
try
{
return SymbolAccess.GetReaderForFile(aAssembly.Location);
}
catch (NotSupportedException)
{
return null;
}
}
private void ProcessAllMethods()
{
int i = -1;
int xCount = 0;
int EMITi = 0;
List<MethodBase> EMITdefs = null;
bool EMITmode = false;
while (true)
{
if (EMITmode)
{
EMITi++;
}
else
{
i++;
}
MethodBase xCurrentMethod;
using (mMethodsLocker.AcquireReaderLock())
{
xCount = mMethods.Count;
EMITmode = (i == xCount);
if (EMITmode)
{
if (EMITdefs == null)
{
EMITdefs = new List<MethodBase>();
Assembly EMITassm = (from assm in AppDomain.CurrentDomain.GetAssemblies() where assm.GetName().Name == "IndyIL2CPU_EmitAssm" select assm).FirstOrDefault<Assembly>();
foreach (Type EMITtype in EMITassm.GetTypes())
{
EMITdefs.AddRange(from method in EMITtype.GetMethods() where method.Name.StartsWith("Emit") select method as MethodBase);
}
}
if (EMITi == EMITdefs.Count)
break;
xCurrentMethod = EMITdefs[EMITi];
//CompilingMethods(EMITi, EMITdefs.Count); //Causes Bug in new Engine ... should be fixed later! -Xenni
}
else
{
xCurrentMethod = mMethods.Keys.ElementAt(i);
if (DynamicMethodEmit.GetHasDynamicMethod(xCurrentMethod))
continue;
CompilingMethods(i, xCount);
}
}
OnDebugLog(LogSeverityEnum.Informational, "Processing method {0}", xCurrentMethod.GetFullName());
try
{
EmitDependencyGraphLine(true, xCurrentMethod.GetFullName());
RegisterType(xCurrentMethod.DeclaringType);
if (xCurrentMethod.IsAbstract)
{
using (mMethodsLocker.AcquireReaderLock())
{
mMethods[xCurrentMethod].Processed = true;
}
continue;
}
string xMethodName = Label.GenerateLabelName(xCurrentMethod);
TypeInformation xTypeInfo = null;
if (!xCurrentMethod.IsStatic)
{
xTypeInfo = GetTypeInfo(xCurrentMethod.DeclaringType);
}
SortedList<string, object> xMethodScanInfo;
using (mMethodsLocker.AcquireReaderLock())
{
if (EMITmode)
{
xMethodScanInfo = new QueuedMethodInformation().Info;
}
else
{
xMethodScanInfo = mMethods[xCurrentMethod].Info;
}
}
MethodInformation xMethodInfo = GetMethodInfo(xCurrentMethod, xCurrentMethod
, xMethodName, xTypeInfo, mDebugMode != DebugMode.None, xMethodScanInfo);
Op xOp = GetOpFromType(mMap.MethodHeaderOp, null, xMethodInfo);
xOp.Assembler = mAssembler;
#if VERBOSE_DEBUG
string comment = "(No Type Info available)";
if (xMethodInfo.TypeInfo != null)
{
comment = "Type Info:\r\n \r\n" + xMethodInfo.TypeInfo;
}
foreach (string s in comment.Trim().Split(new string[] { "\r\n" }
, StringSplitOptions.RemoveEmptyEntries))
{
new Comment(s);
}
comment = xMethodInfo.ToString();
foreach (string s in comment.Trim().Split(new string[] { "\r\n" }
, StringSplitOptions.RemoveEmptyEntries))
{
new Comment(s);
}
#endif
xOp.Assemble();
MethodBase xCustomImplementation = GetCustomMethodImplementation(xMethodName);
bool xIsCustomImplementation = (xCustomImplementation != null);
// what to do if a method doesn't have a body?
bool xContentProduced = false;
if (xIsCustomImplementation)
{
// this is for the support for having extra fields on types, and being able to use
// them in custom implementation methods
CustomMethodImplementationProxyOp xProxyOp
= (CustomMethodImplementationProxyOp)GetOpFromType(
mMap.CustomMethodImplementationProxyOp, null, xMethodInfo);
xProxyOp.Assembler = mAssembler;
xProxyOp.ProxiedMethod = xCustomImplementation;
xProxyOp.Assemble();
xContentProduced = true;
}
if (!xContentProduced)
{
Type xOpType = mMap.GetOpForCustomMethodImplementation(xMethodName);
if (xOpType != null)
{
Op xMethodOp = GetOpFromType(xOpType, null, xMethodInfo);
if (xMethodOp != null)
{
xMethodOp.Assembler = mAssembler;
xMethodOp.Assemble();
xContentProduced = true;
}
}
}
if (!xContentProduced)
{
if (mMap.HasCustomAssembleImplementation(xMethodInfo))
{
mMap.DoCustomAssembleImplementation(mAssembler, xMethodInfo);
// No plugs, we need to compile the IL from the method
}
else
{
MethodBody xBody = xCurrentMethod.GetMethodBody();
// todo: add better detection of implementation state
if (xBody != null)
{
mInstructionsToSkip = 0;
mAssembler.StackContents.Clear();
var xReader = new ILReader(xCurrentMethod);
var xInstructionInfos = new List<DebugSymbolsAssemblyTypeMethodInstruction>();
// Section currently is dead code. Working on matching it up
// with contents from inside the read
int[] xCodeOffsets = null;
if (mDebugMode == DebugMode.Source)
{
var xSymbolReader = GetSymbolReaderForAssembly(xCurrentMethod.DeclaringType.Assembly);
if (xSymbolReader != null)
{
var xSmbMethod = xSymbolReader.GetMethod(new SymbolToken(xCurrentMethod.MetadataToken));
// This gets the Sequence Points.
// Sequence Points are spots that identify what the compiler/debugger says is a spot
// that a breakpoint can occur one. Essentially, an atomic source line in C#
if (xSmbMethod != null)
{
xCodeOffsets = new int[xSmbMethod.SequencePointCount];
var xCodeDocuments = new ISymbolDocument[xSmbMethod.SequencePointCount];
var xCodeLines = new int[xSmbMethod.SequencePointCount];
var xCodeColumns = new int[xSmbMethod.SequencePointCount];
var xCodeEndLines = new int[xSmbMethod.SequencePointCount];
var xCodeEndColumns = new int[xSmbMethod.SequencePointCount];
xSmbMethod.GetSequencePoints(xCodeOffsets, xCodeDocuments
, xCodeLines, xCodeColumns, xCodeEndLines, xCodeEndColumns);
}
}
}
// Scan each IL op in the method
while (xReader.Read())
{
ExceptionHandlingClause xCurrentHandler = null;
#region Exception handling support code
// todo: add support for nested handlers using a stack or so..
foreach (ExceptionHandlingClause xHandler in xBody.ExceptionHandlingClauses)
{
if (xHandler.TryOffset > 0)
{
if (xHandler.TryOffset <= xReader.NextPosition && (xHandler.TryLength + xHandler.TryOffset) > xReader.NextPosition)
{
if (xCurrentHandler == null)
{
xCurrentHandler = xHandler;
continue;
}
else if (xHandler.TryOffset > xCurrentHandler.TryOffset && (xHandler.TryLength + xHandler.TryOffset) < (xCurrentHandler.TryLength + xCurrentHandler.TryOffset))
{
// only replace if the current found handler is narrower
xCurrentHandler = xHandler;
continue;
}
}
}
if (xHandler.HandlerOffset > 0)
{
if (xHandler.HandlerOffset <= xReader.NextPosition && (xHandler.HandlerOffset + xHandler.HandlerLength) > xReader.NextPosition)
{
if (xCurrentHandler == null)
{
xCurrentHandler = xHandler;
continue;
}
else if (xHandler.HandlerOffset > xCurrentHandler.HandlerOffset && (xHandler.HandlerOffset + xHandler.HandlerLength) < (xCurrentHandler.HandlerOffset + xCurrentHandler.HandlerLength))
{
// only replace if the current found handler is narrower
xCurrentHandler = xHandler;
continue;
}
}
}
if ((xHandler.Flags & ExceptionHandlingClauseOptions.Filter) > 0)
{
if (xHandler.FilterOffset > 0)
{
if (xHandler.FilterOffset <= xReader.NextPosition)
{
if (xCurrentHandler == null)
{
xCurrentHandler = xHandler;
continue;
}
else if (xHandler.FilterOffset > xCurrentHandler.FilterOffset)
{
// only replace if the current found handler is narrower
xCurrentHandler = xHandler;
continue;
}
}
}
}
}
#endregion
xMethodInfo.CurrentHandler = xCurrentHandler;
xOp = GetOpFromType(mMap.GetOpForOpCode(xReader.OpCode), xReader, xMethodInfo);
xOp.Assembler = mAssembler;
new Comment("StackItems = " + mAssembler.StackContents.Count);
foreach (var xStackContent in mAssembler.StackContents)
{
new Comment(" " + xStackContent.Size);
}
// Create label for current point
string xLabel = Op.GetInstructionLabel(xReader);
if (xLabel.StartsWith("."))
{
xLabel = DataMember.FilterStringForIncorrectChars(
Label.LastFullLabel + "__DOT__" + xLabel.Substring(1));
}
// Possibly emit Tracer call
EmitTracer(xOp, xCurrentMethod.DeclaringType.Namespace, (int)xReader.Position,
xCodeOffsets, xLabel);
using (mSymbolsLocker.AcquireWriterLock())
{
if (mSymbols != null)
{
var xMLSymbol = new MLDebugSymbol();
xMLSymbol.LabelName = xLabel;
int xStackSize = (from item in mAssembler.StackContents
let xSize = (item.Size % 4 == 0)
? item.Size
: (item.Size + (4 - (item.Size % 4)))
select xSize).Sum();
xMLSymbol.StackDifference = xMethodInfo.LocalsSize + xStackSize;
try
{
xMLSymbol.AssemblyFile = xCurrentMethod.DeclaringType.Assembly.Location;
}
catch (NotSupportedException)
{
xMLSymbol.AssemblyFile = "DYNAMIC: " + xCurrentMethod.DeclaringType.Assembly.FullName;
}
xMLSymbol.MethodToken = xCurrentMethod.MetadataToken;
xMLSymbol.TypeToken = xCurrentMethod.DeclaringType.MetadataToken;
xMLSymbol.ILOffset = (int)xReader.Position;
mSymbols.Add(xMLSymbol);
}
}
xOp.Assemble();
//if (xInstructionInfo != null) {
// int xNewStack = (from item in mAssembler.StackContents
// let xSize = (item.Size % 4 == 0) ? item.Size : (item.Size + (4 - (item.Size % 4)))
// select xSize).Sum();
// xInstructionInfo.StackResult = xNewStack - xCurrentStack;
// xInstructionInfo.StackResultSpecified = true;
// xInstructionInfos.Add(xInstructionInfo);
//}
}
if (mSymbols != null && !EMITmode)
{
MLDebugSymbol[] xSymbols;
using (mSymbolsLocker.AcquireReaderLock())
{
xSymbols = mSymbols.ToArray();
}
using (mMethodsLocker.AcquireReaderLock())
{
mMethods[xCurrentMethod].Instructions = xSymbols;
}
}
}
else
{
if ((xCurrentMethod.Attributes & MethodAttributes.PinvokeImpl) != 0)
{
OnDebugLog(LogSeverityEnum.Error,
"Method '{0}' not generated!",
xCurrentMethod.GetFullName());
new Comment("Method not being generated yet, as it's handled by a PInvoke");
}
else
{
OnDebugLog(LogSeverityEnum.Error,
"Method '{0}' not generated!",
xCurrentMethod.GetFullName());
new Comment("Method not being generated yet, as it's handled by an iCall");
}
}
}
}
xOp = GetOpFromType(mMap.MethodFooterOp, null, xMethodInfo);
xOp.Assembler = mAssembler;
xOp.Assemble();
mAssembler.StackContents.Clear();
if (!EMITmode)
{
using (mMethodsLocker.AcquireReaderLock())
{
mMethods[xCurrentMethod].Processed = true;
}
}
}
catch (Exception e)
{
OnDebugLog(LogSeverityEnum.Error, xCurrentMethod.GetFullName());
OnDebugLog(LogSeverityEnum.Warning, e.ToString());
throw;
}
}
//BUG //HACK
//This should not be a bug, see above comment. -Xenni
//if (EMITmode)
//{
// CompilingMethods(EMITi, EMITdefs.Count); //cant see the point of sending 0,0 prob bug
//}
//else
{
CompilingMethods(i, xCount);
}
}
private IList<Assembly> GetPlugAssemblies()
{
var xResult = this.mMap.GetPlugAssemblies();
xResult.Add(typeof(Engine).Assembly);
return xResult;
}
/// <summary>
/// Gets the full name of a method, without the defining type included
/// </summary>
/// <param name="aMethod"></param>
/// <returns></returns>
private static string GetStrippedMethodBaseFullName(MethodBase aMethod,
MethodBase aRefMethod)
{
StringBuilder xBuilder = new StringBuilder();
string[] xParts = aMethod.ToString().Split(' ');
string[] xParts2 = xParts.Skip(1).ToArray();
MethodInfo xMethodInfo = aMethod as MethodInfo;
if (xMethodInfo != null)
{
xBuilder.Append(xMethodInfo.ReturnType.FullName);
}
else
{
if (aMethod is ConstructorInfo)
{
xBuilder.Append(typeof(void).FullName);
}
else
{
xBuilder.Append(xParts[0]);
}
}
xBuilder.Append(" ");
xBuilder.Append(".");
xBuilder.Append(aMethod.Name);
xBuilder.Append("(");
ParameterInfo[] xParams = aMethod.GetParameters();
bool xParamAdded = false;
for (int i = 0; i < xParams.Length; i++)
{
if (i == 0 && (aRefMethod != null && !aRefMethod.IsStatic))
{
continue;
}
if (xParams[i].IsDefined(typeof(FieldAccessAttribute), true))
{
continue;
}
if (xParamAdded)
{
xBuilder.Append(", ");
}
xBuilder.Append(xParams[i].ParameterType.FullName);
xParamAdded = true;
}
xBuilder.Append(")");
return xBuilder.ToString();
}
private void InitializePlugs(IEnumerable<string> aPlugs)
{
if (mPlugMethods != null)
{
throw new Exception("PlugMethods list already initialized!");
}
if (mPlugFields != null)
{
throw new Exception("PlugFields list already initialized!");
}
mPlugMethods = new SortedList<string, MethodBase>();
mPlugFields = new SortedList<Type, Dictionary<string, PlugFieldAttribute>>(new TypeComparer());
AppDomain.CurrentDomain.AssemblyLoad += CurrentDomain_AssemblyLoad;
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
foreach (var xAsm in AppDomain.CurrentDomain.GetAssemblies())
{
CheckAssemblyForPlugAssemblies(xAsm);
}
List<Assembly> xPlugs = new List<Assembly>();
var xComparer = new AssemblyEqualityComparer();
foreach (string s in aPlugs)
{
Assembly a = Assembly.LoadFrom(s);
a.GetTypes();
if (!xPlugs.Contains(a,
xComparer))
{
xPlugs.Add(a);
}
}
foreach (var item in GetPlugAssemblies())
{
if (!xPlugs.Contains(item,
xComparer))
{
xPlugs.Add(item);
}
}
foreach (Assembly xAssemblyDef in xPlugs)
{
LoadPlugAssembly(xAssemblyDef);
}
}
private Assembly CurrentDomain_AssemblyResolve(object sender,
ResolveEventArgs args)
{
if (File.Exists(Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location),
args.Name + ".dll")))
{
return Assembly.ReflectionOnlyLoadFrom(Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location),
args.Name + ".dll"));
}
return null;
}
private void CurrentDomain_AssemblyLoad(object sender,
AssemblyLoadEventArgs args)
{
CheckAssemblyForPlugAssemblies(args.LoadedAssembly);
}
/// <summary>
/// Load any plug assemblies referred to in this assembly's .config file.
/// </summary>
private void CheckAssemblyForPlugAssemblies(Assembly aAssembly)
{
//If in the GAC, then ignore assembly
if (aAssembly.GlobalAssemblyCache)
{
return;
}
//Search for related .config file
string configFile = aAssembly.Location + ".cosmos-config";
if (System.IO.File.Exists(configFile))
{
//Load and parse all PlugAssemblies referred to in the .config file
foreach (Assembly xAssembly in GetAssembliesFromConfigFile(configFile))
{
LoadPlugAssembly(xAssembly);
}
}
}
/// <summary>
/// Retrieves a list of plug assemblies from the given .config file.
/// </summary>
/// <param name="configFile"></param>
private IEnumerable<Assembly> GetAssembliesFromConfigFile(string configFile)
{
//Parse XML and get all the PlugAssembly names
XmlDocument xml = new XmlDocument();
xml.Load(configFile);
// do version check:
if (xml.DocumentElement.Attributes["version"] == null || xml.DocumentElement.Attributes["version"].Value != "1")
{
throw new Exception(".DLL configuration version mismatch!");
}
string xHintPath = null;
if (xml.DocumentElement.Attributes["hintpath"] != null)
{
xHintPath = xml.DocumentElement.Attributes["hintpath"].Value;
}
foreach (XmlNode assemblyName in xml.GetElementsByTagName("plug-assembly"))
{
string xName = assemblyName.InnerText;
if (xName.EndsWith(".dll",
StringComparison.InvariantCultureIgnoreCase) || xName.EndsWith(".exe",
StringComparison.InvariantCultureIgnoreCase))
{
if (!String.IsNullOrEmpty(xHintPath))
{
yield return Assembly.LoadFile(Path.Combine(xHintPath,
xName));
continue;
}
}
yield return Assembly.Load(assemblyName.InnerText);
}
}
/// <summary>
/// Searches assembly for methods or fields marked with custom attributes PlugMethodAttribute or PlugFieldAttribute.
/// Matches found are inserted in SortedLists mPlugMethods and mPlugFields.
/// </summary>
private void LoadPlugAssembly(Assembly aAssemblyDef)
{
foreach (var xType in (from item in aAssemblyDef.GetTypes()
let xCustomAttribs = item.GetCustomAttributes(typeof(PlugAttribute),
false)
where xCustomAttribs != null && xCustomAttribs.Length > 0
select new KeyValuePair<Type, PlugAttribute>(item,
(PlugAttribute)xCustomAttribs[0])))
{
PlugAttribute xPlugAttrib = xType.Value;
if (xPlugAttrib.IsMonoOnly && !RunningOnMono)
{
continue;
}
if (xPlugAttrib.IsMicrosoftdotNETOnly && RunningOnMono)
{
continue;
}
Type xTypeRef = xPlugAttrib.Target;
if (xTypeRef == null)
{
xTypeRef = Type.GetType(xPlugAttrib.TargetName,
true);
}
PlugFieldAttribute[] xTypePlugFields = xType.Key.GetCustomAttributes(typeof(PlugFieldAttribute),
false) as PlugFieldAttribute[];
if (xTypePlugFields != null && xTypePlugFields.Length > 0)
{
Dictionary<string, PlugFieldAttribute> xPlugFields;
if (mPlugFields.ContainsKey(xTypeRef))
{
xPlugFields = mPlugFields[xTypeRef];
}
else
{
mPlugFields.Add(xTypeRef,
xPlugFields = new Dictionary<string, PlugFieldAttribute>());
}
foreach (var xPlugField in xTypePlugFields)
{
if (xPlugAttrib.IsMonoOnly && !RunningOnMono)
{
continue;
}
if (xPlugAttrib.IsMicrosoftdotNETOnly && RunningOnMono)
{
continue;
}
if (!xPlugFields.ContainsKey(xPlugField.FieldId))
{
xPlugFields.Add(xPlugField.FieldId,
xPlugField);
}
}
}
foreach (MethodBase xMethod in xType.Key.GetMethods(BindingFlags.Public | BindingFlags.Static))
{
PlugMethodAttribute xPlugMethodAttrib = xMethod.GetCustomAttributes(typeof(PlugMethodAttribute),
true).Cast<PlugMethodAttribute>().FirstOrDefault();
string xSignature = String.Empty;
if (xPlugMethodAttrib != null)
{
xSignature = xPlugMethodAttrib.Signature;
if (!xPlugMethodAttrib.Enabled)
{
continue;
}
if (xPlugAttrib.IsMonoOnly && !RunningOnMono)
{
continue;
}
if (xPlugAttrib.IsMicrosoftdotNETOnly && RunningOnMono)
{
continue;
}
if (!String.IsNullOrEmpty(xSignature))
{
if (!mPlugMethods.ContainsKey(xSignature))
{
mPlugMethods.Add(xSignature,
xMethod);
}
continue;
}
}
foreach (MethodBase xOrigMethodDef in xTypeRef.GetMethods(BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance | BindingFlags.NonPublic))
{
string xStrippedSignature = GetStrippedMethodBaseFullName(xMethod,
xOrigMethodDef);
string xOrigStrippedSignature = GetStrippedMethodBaseFullName(xOrigMethodDef,
null);
if (xOrigStrippedSignature == xStrippedSignature)
{
if (!mPlugMethods.ContainsKey(Label.GenerateLabelName(xOrigMethodDef)))
{
mPlugMethods.Add(Label.GenerateLabelName(xOrigMethodDef),
xMethod);
}
}
}
foreach (MethodBase xOrigMethodDef in xTypeRef.GetConstructors(BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance | BindingFlags.NonPublic))
{
string xStrippedSignature = GetStrippedMethodBaseFullName(xMethod,
xOrigMethodDef);
string xOrigStrippedSignature = GetStrippedMethodBaseFullName(xOrigMethodDef,
null);
if (xOrigStrippedSignature == xStrippedSignature)
{
if (mPlugMethods.ContainsKey(Label.GenerateLabelName(xOrigMethodDef)))
{
System.Diagnostics.Debugger.Break();
}
mPlugMethods.Add(Label.GenerateLabelName(xOrigMethodDef),
xMethod);
}
}
}
}
}
private MethodBase GetCustomMethodImplementation(string aMethodName)
{
if (mPlugMethods.ContainsKey(aMethodName))
{
return mPlugMethods[aMethodName];
}
return null;
}
public TypeInformation GetTypeInfo(Type aType)
{
TypeInformation xTypeInfo;
uint xObjectStorageSize;
Dictionary<string, TypeInformation.Field> xTypeFields = GetTypeFieldInfo(aType,
out xObjectStorageSize);
xTypeInfo = new TypeInformation(xObjectStorageSize,
xTypeFields,
aType,
(!aType.IsValueType) && aType.IsClass);
return xTypeInfo;
}
public MethodInformation GetMethodInfo(MethodBase aCurrentMethodForArguments,
MethodBase aCurrentMethodForLocals,
string aMethodName,
TypeInformation aTypeInfo,
bool aDebugMode)
{
return GetMethodInfo(aCurrentMethodForArguments,
aCurrentMethodForLocals,
aMethodName,
aTypeInfo,
aDebugMode,
null);
}
public MethodInformation GetMethodInfo(MethodBase aCurrentMethodForArguments,
MethodBase aCurrentMethodForLocals,
string aMethodName,
TypeInformation aTypeInfo,
bool aDebugMode,
IDictionary<string, object> aMethodData)
{
MethodInformation xMethodInfo;
{
MethodInformation.Variable[] xVars = new MethodInformation.Variable[0];
int xCurOffset = 0;
// todo:implement check for body
//if (aCurrentMethodForLocals.HasBody) {
MethodBody xBody = aCurrentMethodForLocals.GetMethodBody();
if (xBody != null)
{
xVars = new MethodInformation.Variable[xBody.LocalVariables.Count];
foreach (LocalVariableInfo xVarDef in xBody.LocalVariables)
{
int xVarSize = (int)GetFieldStorageSize(xVarDef.LocalType);
if ((xVarSize % 4) != 0)
{
xVarSize += 4 - (xVarSize % 4);
}
xVars[xVarDef.LocalIndex] = new MethodInformation.Variable(xCurOffset,
xVarSize,
!xVarDef.LocalType.IsValueType,
xVarDef.LocalType);
// todo: implement support for generic parameters?
//if (!(xVarDef.VariableType is GenericParameter)) {
RegisterType(xVarDef.LocalType);
//}
xCurOffset += xVarSize;
}
}
MethodInformation.Argument[] xArgs;
if (!aCurrentMethodForArguments.IsStatic)
{
ParameterInfo[] xParameters = aCurrentMethodForArguments.GetParameters();
xArgs = new MethodInformation.Argument[xParameters.Length + 1];
xCurOffset = 0;
uint xArgSize;
for (int i = xArgs.Length - 1; i > 0; i--)
{
ParameterInfo xParamDef = xParameters[i - 1];
xArgSize = GetFieldStorageSize(xParamDef.ParameterType);
if ((xArgSize % 4) != 0)
{
xArgSize += 4 - (xArgSize % 4);
}
MethodInformation.Argument.KindEnum xKind = MethodInformation.Argument.KindEnum.In;
if (xParamDef.IsOut)
{
if (xParamDef.IsIn)
{
xKind = MethodInformation.Argument.KindEnum.ByRef;
}
else
{
xKind = MethodInformation.Argument.KindEnum.Out;
}
}
xArgs[i] = new MethodInformation.Argument(xArgSize,
xCurOffset,
xKind,
!xParamDef.ParameterType.IsValueType,
GetTypeInfo(xParamDef.ParameterType),
xParamDef.ParameterType);
xCurOffset += (int)xArgSize;
}
xArgSize = 4;
// this
xArgs[0] = new MethodInformation.Argument(xArgSize,
xCurOffset,
MethodInformation.Argument.KindEnum.In,
!aCurrentMethodForArguments.DeclaringType.IsValueType,
GetTypeInfo(aCurrentMethodForArguments.DeclaringType),
aCurrentMethodForArguments.DeclaringType);
}
else
{
ParameterInfo[] xParameters = aCurrentMethodForArguments.GetParameters();
xArgs = new MethodInformation.Argument[xParameters.Length];
xCurOffset = 0;
for (int i = xArgs.Length - 1; i >= 0; i--)
{
ParameterInfo xParamDef = xParameters[i]; //xArgs.Length - i - 1];
uint xArgSize = GetFieldStorageSize(xParamDef.ParameterType);
if ((xArgSize % 4) != 0)
{
xArgSize += 4 - (xArgSize % 4);
}
MethodInformation.Argument.KindEnum xKind = MethodInformation.Argument.KindEnum.In;
if (xParamDef.IsOut)
{
if (xParamDef.IsIn)
{
xKind = MethodInformation.Argument.KindEnum.ByRef;
}
else
{
xKind = MethodInformation.Argument.KindEnum.Out;
}
}
xArgs[i] = new MethodInformation.Argument(xArgSize,
xCurOffset,
xKind,
!xParamDef.ParameterType.IsValueType,
GetTypeInfo(xParamDef.ParameterType),
xParamDef.ParameterType);
xCurOffset += (int)xArgSize;
}
}
int xResultSize = 0;
//= GetFieldStorageSize(aCurrentMethodForArguments.ReturnType.ReturnType);
MethodInfo xMethInfo = aCurrentMethodForArguments as MethodInfo;
Type xReturnType = typeof(void);
if (xMethInfo != null)
{
xResultSize = (int)GetFieldStorageSize(xMethInfo.ReturnType);
xReturnType = xMethInfo.ReturnType;
}
xMethodInfo = new MethodInformation(aMethodName,
xVars,
xArgs,
(uint)xResultSize,
!aCurrentMethodForArguments.IsStatic,
aTypeInfo,
aCurrentMethodForArguments,
xReturnType,
aDebugMode,
aMethodData);
}
return xMethodInfo;
}
public Dictionary<string, TypeInformation.Field> GetTypeFieldInfo(MethodBase aCurrentMethod,
out uint aObjectStorageSize)
{
Type xCurrentInspectedType = aCurrentMethod.DeclaringType;
return GetTypeFieldInfo(xCurrentInspectedType,
out aObjectStorageSize);
}
private void GetTypeFieldInfoImpl(List<KeyValuePair<string, TypeInformation.Field>> aTypeFields,
Type aType,
ref uint aObjectStorageSize)
{
Type xActualType = aType;
Dictionary<string, PlugFieldAttribute> xCurrentPlugFieldList = new Dictionary<string, PlugFieldAttribute>();
do
{
if (mPlugFields.ContainsKey(aType))
{
var xOrigList = mPlugFields[aType];
foreach (var item in xOrigList)
{
xCurrentPlugFieldList.Add(item.Key,
item.Value);
}
}
foreach (FieldInfo xField in aType.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly))
{
if (xField.IsStatic)
{
continue;
}
//if (xField.HasConstant) {
// Console.WriteLine("Field is constant: " + xField.GetFullName());
//}
// todo: add support for constants?
PlugFieldAttribute xPlugFieldAttr = null;
if (xCurrentPlugFieldList.ContainsKey(xField.GetFullName()))
{
xPlugFieldAttr = xCurrentPlugFieldList[xField.GetFullName()];
xCurrentPlugFieldList.Remove(xField.GetFullName());
}
Type xFieldType = null;
int xFieldSize;
string xFieldId;
if (xPlugFieldAttr != null)
{
xFieldType = xPlugFieldAttr.FieldType;
xFieldId = xPlugFieldAttr.FieldId;
}
else
{
xFieldId = xField.GetFullName();
}
if (xFieldType == null)
{
xFieldType = xField.FieldType;
}
//if ((!xFieldType.IsValueType && aGCObjects && xFieldType.IsClass) || (xPlugFieldAttr != null && xPlugFieldAttr.IsExternalValue && aGCObjects)) {
// continue;
//}
if ((xFieldType.IsClass && !xFieldType.IsValueType) || (xPlugFieldAttr != null && xPlugFieldAttr.IsExternalValue))
{
xFieldSize = 4;
}
else
{
xFieldSize = (int)GetFieldStorageSize(xFieldType);
}
//}
if ((from item in aTypeFields
where item.Key == xFieldId
select item).Count() > 0)
{
continue;
}
int xOffset = (int)aObjectStorageSize;
FieldOffsetAttribute xOffsetAttrib = xField.GetCustomAttributes(typeof(FieldOffsetAttribute),
true).FirstOrDefault() as FieldOffsetAttribute;
if (xOffsetAttrib != null)
{
xOffset = xOffsetAttrib.Value;
}
else
{
aObjectStorageSize += (uint)xFieldSize;
xOffset = -1;
}
aTypeFields.Insert(0,
new KeyValuePair<string, TypeInformation.Field>(xField.GetFullName(),
new TypeInformation.Field(xFieldSize,
xFieldType.IsClass && !xFieldType.IsValueType,
xFieldType,
(xPlugFieldAttr != null && xPlugFieldAttr.IsExternalValue))
{
Offset = xOffset
}));
}
while (xCurrentPlugFieldList.Count > 0)
{
var xItem = xCurrentPlugFieldList.Values.First();
xCurrentPlugFieldList.Remove(xItem.FieldId);
Type xFieldType = xItem.FieldType;
int xFieldSize;
string xFieldId = xItem.FieldId;
if (xFieldType == null)
{
xFieldType = xItem.FieldType;
}
if (xFieldType == null)
{
OnDebugLog(LogSeverityEnum.Error, "Plugged field {0} not found! (On Type {1})", xItem.FieldId, aType.AssemblyQualifiedName);
}
if (xItem.IsExternalValue || (xFieldType.IsClass && !xFieldType.IsValueType))
{
xFieldSize = 4;
}
else
{
xFieldSize = (int)GetFieldStorageSize(xFieldType);
}
int xOffset = (int)aObjectStorageSize;
aObjectStorageSize += (uint)xFieldSize;
aTypeFields.Insert(0,
new KeyValuePair<string, TypeInformation.Field>(xItem.FieldId,
new TypeInformation.Field(xFieldSize,
xFieldType.IsClass && !xFieldType.IsValueType,
xFieldType,
xItem.IsExternalValue)));
}
if (aType.FullName != "System.Object" && aType.BaseType != null)
{
aType = aType.BaseType;
}
else
{
break;
}
} while (true);
}
private Dictionary<string, TypeInformation.Field> GetTypeFieldInfo(Type aType,
out uint aObjectStorageSize)
{
var xTypeFields = new List<KeyValuePair<string, TypeInformation.Field>>();
aObjectStorageSize = 0;
GetTypeFieldInfoImpl(xTypeFields,
aType,
ref aObjectStorageSize);
if (aType.IsExplicitLayout)
{
var xStructLayout = aType.StructLayoutAttribute;
if (xStructLayout.Size == 0)
{
aObjectStorageSize = (uint)((from item in xTypeFields
let xSize = item.Value.Offset + item.Value.Size
orderby xSize descending
select xSize).FirstOrDefault());
}
else
{
aObjectStorageSize = (uint)xStructLayout.Size;
}
}
int xOffset = 0;
Dictionary<string, TypeInformation.Field> xResult = new Dictionary<string, TypeInformation.Field>();
foreach (var item in xTypeFields)
{
var xItem = item.Value;
if (item.Value.Offset == -1)
{
xItem.Offset = xOffset;
xOffset += xItem.Size;
}
xResult.Add(item.Key,
xItem);
}
return xResult;
}
private static Op GetOpFromType(Type aType, ILReader aReader, MethodInformation aMethodInfo)
{
return (Op)Activator.CreateInstance(aType, aReader, aMethodInfo);
}
private void QueueStaticField(FieldInfo aField)
{
using (mStaticFieldsLocker.AcquireReaderLock())
{
if (mStaticFields.ContainsKey(aField))
{
return;
}
}
using (mStaticFieldsLocker.AcquireWriterLock())
{
if (!mStaticFields.ContainsKey(aField))
{
mStaticFields.Add(aField,
new QueuedStaticFieldInformation());
}
}
}
private void QueueStaticField(string aAssembly,
string aType,
string aField,
out string aFieldName)
{
Type xTypeDef = GetType(aAssembly,
aType);
var xFieldDef = xTypeDef.GetField(aField);
if (xFieldDef != null)
{
QueueStaticField(xFieldDef);
aFieldName = DataMember.GetStaticFieldName(xFieldDef);
return;
}
throw new Exception("Field not found!(" + String.Format("{0}/{1}/{2}",
aAssembly,
aType,
aField));
}
private void QueueStaticField(FieldInfo aField,
out string aDataName)
{
if (!aField.IsStatic)
{
throw new Exception("Cannot add an instance field to the StaticField queue!");
}
aDataName = DataMember.GetStaticFieldName(aField);
QueueStaticField(aField);
}
// MtW:
// Right now, we only support one engine at a time per AppDomain. This might be changed
// later. See for example NHibernate does this with the ICurrentSessionContext interface
private void QueueMethod(MethodBase aMethod)
{
if (ChangingInnerMethod != null)
ChangingInnerMethod.Invoke(aMethod.GetFullName());
//Doku: it is not complete..it should check if a method is from P/Invoked Namespace and it checks it has pluuged
/*string xInnerMethodName = aMethod.GetFullName();
string xPattern=" System.";
int xPosIn = xInnerMethodName.IndexOf(xPattern,0);
//get method name and namespace
string xNameSpaceAndMethod=xInnerMethodName.Substring(xPosIn+xPattern.Length);
if (xNameSpaceAndMethod.StartsWith("Globalization.") || xNameSpaceAndMethod.StartsWith("Net.") || xNameSpaceAndMethod.StartsWith("Reflection.") || xNameSpaceAndMethod.StartsWith("Xml."))
{
string xMethodSignature=xInnerMethodName.Replace('.','_');
xMethodSignature = xInnerMethodName.Replace(" ", "__");
//throw new Exception(xInnerMethodName);
}*/
if (!aMethod.IsStatic)
{
RegisterType(aMethod.DeclaringType);
}
using (mMethodsLocker.AcquireReaderLock())
{
if (mMethods.ContainsKey(aMethod))
{
return;
}
}
using (mMethodsLocker.AcquireWriterLock())
{
if (!mMethods.ContainsKey(aMethod))
{
if (mMethods is ReadOnlyDictionary<MethodBase, QueuedMethodInformation>)
{
EmitDependencyGraphLine(false,
aMethod.GetFullName());
throw new Exception("Cannot queue " + aMethod.GetFullName());
}
EmitDependencyGraphLine(false,
aMethod.GetFullName());
mMethods.Add(aMethod,
new QueuedMethodInformation()
{
Processed = false,
PreProcessed = false,
Index = mMethods.Count
});
}
}
}
private int GetMethodIdentifier(MethodBase aMethod)
{
QueueMethod(aMethod);
using (mMethodsLocker.AcquireReaderLock())
{
return mMethods[aMethod].Index;
}
}
/// <summary>
/// Registers_Old a type and returns the Type identifier
/// </summary>
/// <param name="aType"></param>
/// <returns></returns>
private int RegisterType(Type aType)
{
if (aType == null)
{
throw new ArgumentNullException("aType");
}
if (aType.IsArray || aType.IsPointer)
{
if (aType.IsArray && aType.GetArrayRank() != 1)
{
//throw new Exception("Multidimensional arrays are not yet supported!");
}
if (aType.IsArray)
{
aType = typeof(Array);
}
else
{
aType = aType.GetElementType();
}
}
using (mTypesLocker.AcquireReaderLock())
{
var xItem = mTypes.FirstOrDefault(x => x.FullName.Equals(aType.FullName));
if (xItem != null)
{
return mTypes.IndexOf(xItem);
}
}
Type xFoundItem;
using (mTypesLocker.AcquireWriterLock())
{
xFoundItem = mTypes.FirstOrDefault(x => x.FullName.Equals(aType.FullName));
if (xFoundItem == null)
{
mTypes.Add(aType);
if (aType.FullName != "System.Object" && aType.BaseType != null)
{
Type xCurInspectedType = aType.BaseType;
RegisterType(xCurInspectedType);
}
return RegisterType(aType);
}
else
{
return mTypes.IndexOf(xFoundItem);
}
}
}
//private Assembly GetCrawledAssembly()
//{
// if (mCurrent == null)
// {
// throw new Exception("ERROR: No Current Engine found!");
// }
// return mCrawledAssembly;
//}
private void QueueMethod2(string aAssembly,
string aType,
string aMethod)
{
MethodBase xMethodDef;
QueueMethod2(aAssembly,
aType,
aMethod,
out xMethodDef);
}
private void QueueMethod2(string aAssembly,
string aType,
string aMethod,
out MethodBase aMethodDef)
{
Type xTypeDef = GetType(aAssembly,
aType);
// todo: find a way to specify one overload of a method
int xCount = 0;
aMethodDef = null;
foreach (MethodBase xMethodDef in xTypeDef.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static))
{
if (xMethodDef.Name == aMethod)
{
QueueMethod(xMethodDef);
if (aMethodDef == null)
{
aMethodDef = xMethodDef;
}
xCount++;
}
}
foreach (MethodBase xMethodDef in xTypeDef.GetConstructors(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static))
{
if (xMethodDef.Name == aMethod)
{
QueueMethod(xMethodDef);
xCount++;
}
}
if (xCount == 0)
{
throw new Exception("Method '" + aType + "." + aMethod + "' not found in assembly '" + aAssembly + "'!");
}
}
public event DebugLogHandler DebugLog
{
add
{
mDebugLog += value;
}
remove
{
mDebugLog -= value;
}
}
private void OnDebugLog(LogSeverityEnum aSeverity,
string aMessage,
params object[] args)
{
if (mDebugLog != null)
{
mDebugLog(aSeverity,
String.Format(aMessage,
args));
}
}
private SortedList<string, Assembly> mAssemblyDefCache = new SortedList<string, Assembly>();
public Type GetType(string aAssembly,
string aType)
{
Assembly xAssemblyDef;
if (mAssemblyDefCache.ContainsKey(aAssembly))
{
xAssemblyDef = mAssemblyDefCache[aAssembly];
}
else
{
//
// Assembly xAssembly = (from item in AppDomain.CurrentDomain.GetAssemblies()
// where item.FullName == aAssembly || item.GetName().Name == aAssembly
// select item).FirstOrDefault();
// if (xAssembly == null) {
// if (String.IsNullOrEmpty(aAssembly) || aAssembly == typeof(Engine).Assembly.GetName().Name || aAssembly == typeof(Engine).Assembly.GetName().FullName) {
// xAssembly = typeof(Engine).Assembly;
// }
// }
// if (xAssembly != null) {
// if (aAssembly.StartsWith("mscorlib"))
// throw new Exception("Shouldn't be used!");
// Console.WriteLine("Using AssemblyFactory for '{0}'", aAssembly);
// xAssemblyDef = AssemblyFactory.GetAssembly(xAssembly.Location);
// } else {
// xAssemblyDef = mCrawledAssembly.Resolver.Resolve(aAssembly);
// }
// mAssemblyDefCache.Add(aAssembly, xAssemblyDef);
if (String.IsNullOrEmpty(aAssembly) || aAssembly == typeof(Engine).Assembly.GetName().Name || aAssembly == typeof(Engine).Assembly.GetName().FullName)
{
aAssembly = typeof(Engine).Assembly.FullName;
}
xAssemblyDef = Assembly.Load(aAssembly);
}
return GetType(xAssemblyDef,
aType);
}
public Type GetType(Assembly aAssembly,
string aType)
{
string xActualTypeName = aType;
if (xActualTypeName.Contains("<") && xActualTypeName.Contains(">"))
{
xActualTypeName = xActualTypeName.Substring(0,
xActualTypeName.IndexOf("<"));
}
Type xResult = aAssembly.GetType(aType,
false);
if (xResult != null)
{
RegisterType(xResult);
return xResult;
}
throw new Exception("Type '" + aType + "' not found in assembly '" + aAssembly + "'!");
}
public MethodBase GetMethodBase(Type aType,
string aMethod,
params string[] aParamTypes)
{
foreach (MethodBase xMethod in aType.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static))
{
if (xMethod.Name != aMethod)
{
continue;
}
ParameterInfo[] xParams = xMethod.GetParameters();
if (xParams.Length != aParamTypes.Length)
{
continue;
}
bool errorFound = false;
for (int i = 0; i < xParams.Length; i++)
{
if (xParams[i].ParameterType.FullName != aParamTypes[i])
{
errorFound = true;
break;
}
}
if (!errorFound)
{
return xMethod;
}
}
foreach (MethodBase xMethod in aType.GetConstructors(BindingFlags.NonPublic | BindingFlags.Public))
{
if (xMethod.Name != aMethod)
{
continue;
}
ParameterInfo[] xParams = xMethod.GetParameters();
if (xParams.Length != aParamTypes.Length)
{
continue;
}
bool errorFound = false;
for (int i = 0; i < xParams.Length; i++)
{
if (xParams[i].ParameterType.FullName != aParamTypes[i])
{
errorFound = true;
break;
}
}
if (!errorFound)
{
return xMethod;
}
}
throw new Exception("Method not found!");
}
public IEnumerable<Assembly> GetAllAssemblies()
{
using (mMethodsLocker.AcquireReaderLock())
{
return (from item in mMethods.Keys
select item.DeclaringType.Module.Assembly).Distinct(new AssemblyEqualityComparer()).ToArray();
}
}
private int mInstructionsToSkip = 0;
public void SetInstructionsToSkip(int aCount)
{
mInstructionsToSkip = aCount;
}
#region Dependency graph code
private static bool mEmitDependencyGraph = false;
private void EmitDependencyGraphLine(bool aIsContainer, string aMessage)
{
}
//static Engine()
//{
// mEmitDependencyGraph = Environment.GetEnvironmentVariables().Contains("CosmosDependencyGraph") || Environment.MachineName.Equals("laptop-matthijs",
// StringComparison.InvariantCultureIgnoreCase);
// if (mEmitDependencyGraph)
// {
// File.Delete(@"d:\dependencygraph.txt");
// }
// RunningOnMono = Type.GetType("Mono.Runtime") != null;
//}
#endregion
private readonly bool RunningOnMono;
}
}