#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; using Indy.IL2CPU.Compiler; using IServiceProvider=Indy.IL2CPU.IL.IServiceProvider; namespace Indy.IL2CPU { public enum DebugMode { None, IL, Source, MLUsingGDB } public enum LogSeverityEnum : byte { Warning = 0, Error = 1, Informational = 2, Performance = 3 } public delegate void DebugLogHandler(LogSeverityEnum aSeverity, string aMessage); public enum TargetPlatformEnum { X86 } public enum TraceAssemblies { All, Cosmos, User }; public class QueuedStaticFieldInformation { public bool Processed; } public class Engine: IServiceProvider, IMetaDataInfoService { protected static Engine mCurrent; protected DebugLogHandler mDebugLog; protected OpCodeMap mMap; protected Assembler.Assembler mAssembler; public TraceAssemblies TraceAssemblies { get; set; } private IDictionary mPlugMethods; private IDictionary> mPlugFields; /// /// Contains a list of all methods. This includes methods to be processed and already processed. /// //protected IDictionary mMethods = new Dictionary(new MethodBaseComparer()); protected IDictionary mMethods = new SortedList(new MethodBaseComparer()); protected ReaderWriterLocker mMethodsLocker = new ReaderWriterLocker(); /// /// Contains a list of all static fields. This includes static fields to be processed and already processed. /// protected IDictionary mStaticFields = new SortedList(new FieldInfoComparer()); protected ReaderWriterLocker mStaticFieldsLocker = new ReaderWriterLocker(); protected IList mTypes = new List(); protected ReaderWriterLocker mTypesLocker = new ReaderWriterLocker(); protected TypeEqualityComparer mTypesEqualityComparer = new TypeEqualityComparer(); private byte mDebugComport; private DebugMode mDebugMode; private List mSymbols = new List(); private ReaderWriterLocker mSymbolsLocker = new ReaderWriterLocker(); private string mOutputDir; public event Action ChangingCurrentMethod; public event Action ChangingInnerMethod; public event Action CompilingMethods; public event Action CompilingStaticFields; ///// ///// 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. ///// ///// For now, only entrypoints without params are supported! ///// The assembly of which to crawl the entry-point method. ///// The platform to target when assembling the code. ///// //public void Simulate(IEnumerable 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 aGetFileNameForGroup, IEnumerable aPlugs, DebugMode aDebugMode, bool aGDBDebug, byte aDebugComNumber, string aOutputDir, bool aUseBinaryEmission, OpCodeMap aMap, Assembler.Assembler aAssembler) { Assembly mCrawledAssembly; mMap = aMap; mMap.SetServiceProvider(this); mAssembler = aAssembler; mCurrent = this; 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 xSearchDirs = new List(new string[] { Path.GetDirectoryName(aAssembly), aAssemblyDir }); //xSearchDirs.AddRange((from item in aPlugs // select Path.GetDirectoryName(item)).Distinct()); switch (aTargetPlatform) { case TargetPlatformEnum.X86: { 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 xAppDefs = new List(); 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(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); // MTW DEBUG if (Environment.MachineName.Equals("MATTHIJS-A01F0E", StringComparison.InvariantCultureIgnoreCase)) { using (var xMethodsOut = new StreamWriter(@"e:\methods.txt", false)) { foreach (var xMethod in mMethods) { xMethodsOut.WriteLine(xMethod.Value.FullName); } } using (var xTypesOut = new StreamWriter(@"e:\types.txt", false)) { foreach (var xType in mTypes) { xTypesOut.WriteLine(xType.AssemblyQualifiedName); } } } // END MTW DEBUG // 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) { if(xType.IsGenericTypeDefinition) { continue; } foreach (MethodBase xMethod in xType.GetConstructors(BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public)) { if(xType.FullName.Contains("List`1")) { Console.Write(""); } 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(mMethods); } using (mStaticFieldsLocker.AcquireWriterLock()) { mStaticFields = new ReadOnlyDictionary(mStaticFields); } // todo: caching, speedups, etc ProcessAllMethods(); mMap.PostProcess(mAssembler); ProcessAllStaticFields(); GenerateVMT(mDebugMode != DebugMode.None); // TODO: fix the compiler so that it's not needed anymore // explanation: // right now (06132009) we use the fullname of a type ("System.String") instead of the // fully qualified name ("System.String, mscorlib, Version=2.0.0.0") of a type to uniquely // identify it. The folowing three types are duplicates in mscorlib and system // MtW var xDeleteItem = new Action(delegate(string obj) { for (int i = 0; i < aAssembler.DataMembers.Count; i++) { if (aAssembler.DataMembers[i].Name == obj) { aAssembler.DataMembers.RemoveAt(i); return; } } throw new Exception("Item not found: maybe this hack isn't neccessary anymore?"); }); xDeleteItem("____SYSTEM____TYPE___System_ThrowHelper"); xDeleteItem("____SYSTEM____TYPE___System_ExceptionResource"); xDeleteItem("____SYSTEM____TYPE___System_ExceptionArgument"); // 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 { mCurrent = null; } File.WriteAllText(@"e:\cosmos.dbg", String.Format("Instruction count = {0}", mInstructionCount)); } // 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 = null; foreach (var method in mMethods) { if (method.Value.PreProcessed == false) { xCurrentMethod = method.Key; break; } } if (xCurrentMethod == null) { break; } //{ // 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())); try { RegisterType(xCurrentMethod.DeclaringType); // using (mMethodsLocker.AcquireReaderLock()) { mMethods[xCurrentMethod].PreProcessed = true; } if (xCurrentMethod.IsAbstract) { continue; } // EXPERIMENTAL: types on generic type definitions dont need building? if(xCurrentMethod.IsGenericMethodDefinition || xCurrentMethod.DeclaringType.IsGenericTypeDefinition) { continue; } string xMethodName = Label.GetFullName(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; try { xReader = new ILReader(xCurrentMethod); } catch { continue; } MethodBody xBody = xCurrentMethod.GetMethodBody(); // todo: add better detection of implementation state if (xBody != null) { mInstructionsToSkip = 0; mAssembler.StackContents.Clear(); var xInstructionInfos = new List(); while (xReader.Read()) { SortedList xInfo = null; // using (mMethodsLocker.AcquireReaderLock()) { xInfo = mMethods[xCurrentMethod].Info; } mMap.ScanILCode(xReader, xMethodInfo, xInfo); switch (xReader.OpCode) { case OpCodeEnum.Call: case OpCodeEnum.Callvirt: case OpCodeEnum.Newobj: case OpCodeEnum.Ldftn: QueueMethod(xReader.OperandValueMethod); break; case OpCodeEnum.Initobj: case OpCodeEnum.Ldelema: RegisterType(xReader.OperandValueType); break; case OpCodeEnum.Stsfld: case OpCodeEnum.Ldsfld: case OpCodeEnum.Ldsflda: QueueStaticField(xReader.OperandValueField); break; case OpCodeEnum.Ldtoken: if(xReader.OperandValueType != null) { RegisterType(xReader.OperandValueType); break; } if(xReader.OperandValueField!=null) { QueueStaticField(xReader.OperandValueField); break; } break; } } } } 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())); try { RegisterType(xCurrentMethod.DeclaringType); using (mMethodsLocker.AcquireReaderLock()) { mMethods[xCurrentMethod].PreProcessed = true; } if (xCurrentMethod.IsAbstract) { continue; } string xMethodName = Label.GetFullName(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(); while (xReader.Read()) { SortedList xInfo = null; using (mMethodsLocker.AcquireReaderLock()) { xInfo = mMethods[xCurrentMethod].Info; } mMap.ScanILCode(xReader, xMethodInfo, xInfo); switch (xReader.OpCode) { case OpCodeEnum.Call: case OpCodeEnum.Callvirt: case OpCodeEnum.Newobj: QueueMethod(xReader.OperandValueMethod); break; case OpCodeEnum.Initobj: case OpCodeEnum.Ldelema: RegisterType(xReader.OperandValueType); break; } } } } 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(); 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(); 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(); var xTypeInfo = GetTypeInfo(xType); xDbgType.StorageSize = GetFieldStorageSize(xType); foreach (var xField in xType.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static)) { 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(); foreach (var xMethod in xType.GetMethods(BindingFlags.ExactBinding | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance).Cast().Union(xType.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | 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(); 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())); 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())); xOp.Assembler = mAssembler; xOp.Assemble(); } private void ScanForMethodsToIncludeForVMT() { List xCheckedTypes = new List(); 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 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 static 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 static 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() + "'"); } /// /// Gives the size to store an instance of the for use in a field. /// /// For classes, this is the pointer size. /// /// 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 } try { if (aType.FullName.EndsWith("*")) { // pointer return 4; } }catch { Console.Write(""); throw; } // 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; } IDictionary IMetaDataInfoService.GetTypeFieldInfo(MethodBase aCurrentMethod, out uint aObjectStorageSize) { return GetTypeFieldInfo(aCurrentMethod, out aObjectStorageSize); } IDictionary IMetaDataInfoService.GetTypeFieldInfo(Type aType, out uint aObjectStorageSize) { return GetTypeFieldInfo(aType, out aObjectStorageSize); } TypeInformation IMetaDataInfoService.GetTypeInfo(Type aType) { return GetTypeInfo(aType); } MethodInformation IMetaDataInfoService.GetMethodInfo(MethodBase aCurrentMethodForArguments, MethodBase aCurrentMethodForLocals, string aMethodName, TypeInformation aTypeInfo, bool aDebugMode, IDictionary aMethodData) { return GetMethodInfo(aCurrentMethodForArguments, aCurrentMethodForLocals, aMethodName, aTypeInfo, aDebugMode, aMethodData); } MethodInformation IMetaDataInfoService.GetMethodInfo(MethodBase aCurrentMethodForArguments, MethodBase aCurrentMethodForLocals, string aMethodName, TypeInformation aTypeInfo, bool aDebugMode) { return GetMethodInfo(aCurrentMethodForArguments, aCurrentMethodForLocals, aMethodName, aTypeInfo, aDebugMode); } public MethodInformation GetMethodInfo(MethodBase aMethod, bool aDebugMode) { return GetMethodInfo(aMethod, aMethod, MethodInfoLabelGenerator.GenerateLabelName(aMethod), GetTypeInfo(aMethod.DeclaringType), aDebugMode); } public uint GetObjectStorageSize(Type aType) { if (aType == null) { throw new ArgumentNullException("aType"); } var xTypeInfo = GetTypeInfo(aType); return xTypeInfo.NeedsGC ? xTypeInfo.StorageSize + ObjectImpl.FieldDataOffset : xTypeInfo.StorageSize; } public void LogMessage(LogSeverityEnum aSeverity, string aMessage, params object[] aArgs) { this.OnDebugLog(aSeverity, aMessage, aArgs); } public string GetStaticFieldLabel(FieldInfo aField) { var xLabel = DataMember.GetStaticFieldName(aField); QueueStaticField(aField); // todo: need to register it? return xLabel; } public string GetTypeIdLabel(Type aType) { if (aType.IsArray) { aType = typeof(Array); } var xLabel = Label.FilterStringForIncorrectChars(aType.AssemblyQualifiedName + "__TYPE_ID"); if (xLabel == "System__DOT__ConsoleKey__mscorlib__Version_2__DOT__0__DOT__0__DOT__0__Culture_neutral__PublicKeyToken_b77a5c561934e089__TYPE_ID") { Console.Write(""); } //if (!mCreatedIDLabels.Contains(xLabel)) //{ // mAssembler.DataMembers.Add(new DataMember(xLabel, 0)); // mCreatedIDLabels.Add(xLabel); //} return xLabel; } private HashSet mCreatedIDLabels = new HashSet(StringComparer.InvariantCulture); public string GetMethodIdLabel(MethodBase aMethod) { var xLabel = Label.FilterStringForIncorrectChars(aMethod.GetFullName() + "__METHOD_ID"); QueueMethod(aMethod); //if (!mCreatedIDLabels.Contains(xLabel)) //{ // mAssembler.DataMembers.Add(new DataMember(xLabel, 0)); // mCreatedIDLabels.Add(xLabel); //} return xLabel; } private static 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 xItemList = (from item in xCurrentField.GetCustomAttributes(false) where item.GetType().FullName == "ManifestResourceStreamAttribute" select item).ToList(); object xItem = null; if (xItemList.Count > 0) xItem = xItemList[0]; 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 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(); Assembly EMITassm = (from assm in AppDomain.CurrentDomain.GetAssemblies() where assm.GetName().Name == "IndyIL2CPU_EmitAssm" select assm).FirstOrDefault(); 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); } else { xCurrentMethod = mMethods.Keys.ElementAt(i); if (DynamicMethodEmit.GetHasDynamicMethod(xCurrentMethod)) continue; CompilingMethods(i, xCount); } } OnDebugLog(LogSeverityEnum.Informational, "Processing method {0}", xCurrentMethod.GetFullName()); try { RegisterType(xCurrentMethod.DeclaringType); if (xCurrentMethod.IsAbstract) { using (mMethodsLocker.AcquireReaderLock()) { mMethods[xCurrentMethod].Processed = true; } continue; } string xMethodName = Label.GetFullName(xCurrentMethod); TypeInformation xTypeInfo = null; if (!xCurrentMethod.IsStatic) { xTypeInfo = GetTypeInfo(xCurrentMethod.DeclaringType); } SortedList 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(); // 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()) { mInstructionCount++; 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 //if (EMITmode) //{ // CompilingMethods(EMITi, EMITdefs.Count); //cant see the point of sending 0,0 prob bug //} //else { CompilingMethods(i, xCount); } } private static int mInstructionCount = 0; private IList GetPlugAssemblies() { var xResult = this.mMap.GetPlugAssemblies(); xResult.Add(typeof(Engine).Assembly); return xResult; } /// /// Gets the full name of a method, without the defining type included /// /// /// 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 aPlugs) { if (mPlugMethods != null) { throw new Exception("PlugMethods list already initialized!"); } if (mPlugFields != null) { throw new Exception("PlugFields list already initialized!"); } mPlugMethods = new SortedList(); mPlugFields = new SortedList>(new TypeComparer()); AppDomain.CurrentDomain.AssemblyLoad += CurrentDomain_AssemblyLoad; AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve); foreach (var xAsm in AppDomain.CurrentDomain.GetAssemblies()) { CheckAssemblyForPlugAssemblies(xAsm); } List xPlugs = new List(); 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); } /// /// Load any plug assemblies referred to in this assembly's .config file. /// 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); } } } /// /// Retrieves a list of plug assemblies from the given .config file. /// /// private IEnumerable 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); } } /// /// Searches assembly for methods or fields marked with custom attributes PlugMethodAttribute or PlugFieldAttribute. /// Matches found are inserted in SortedLists mPlugMethods and mPlugFields. /// 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(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 xPlugFields; if (mPlugFields.ContainsKey(xTypeRef)) { xPlugFields = mPlugFields[xTypeRef]; } else { mPlugFields.Add(xTypeRef, xPlugFields = new Dictionary()); } 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().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.GetFullName(xOrigMethodDef))) { mPlugMethods.Add(Label.GetFullName(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.GetFullName(xOrigMethodDef))) { System.Diagnostics.Debugger.Break(); } mPlugMethods.Add(Label.GetFullName(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 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 aMethodData) { QueueMethod(aCurrentMethodForLocals); QueueMethod(aCurrentMethodForArguments); 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; } uint IMetaDataInfoService.GetFieldStorageSize(Type aType) { return GetFieldStorageSize(aType); } public Dictionary GetTypeFieldInfo(MethodBase aCurrentMethod, out uint aObjectStorageSize) { Type xCurrentInspectedType = aCurrentMethod.DeclaringType; return GetTypeFieldInfo(xCurrentInspectedType, out aObjectStorageSize); } private void GetTypeFieldInfoImpl(List> aTypeFields, Type aType, ref uint aObjectStorageSize) { Type xActualType = aType; Dictionary xCurrentPlugFieldList = new Dictionary(); do { if (mCurrent.mPlugFields.ContainsKey(aType)) { var xOrigList = mCurrent.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(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) { Engine.mCurrent.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(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); } public Dictionary GetTypeFieldInfo(Type aType, out uint aObjectStorageSize) { RegisterType(aType); var xTypeFields = new List>(); 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 xResult = new Dictionary(); 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 Op GetOpFromType(Type aType, ILReader aReader, MethodInformation aMethodInfo) { var xResult = (Op)Activator.CreateInstance(aType, aReader, aMethodInfo); xResult.SetServiceProvider(this); return xResult; } public static void QueueStaticField(FieldInfo aField) { if (mCurrent == null) { throw new Exception("ERROR: No Current Engine found!"); } using (mCurrent.mStaticFieldsLocker.AcquireReaderLock()) { if (mCurrent.mStaticFields.ContainsKey(aField)) { return; } } using (mCurrent.mStaticFieldsLocker.AcquireWriterLock()) { if (!mCurrent.mStaticFields.ContainsKey(aField)) { mCurrent.mStaticFields.Add(aField, new QueuedStaticFieldInformation()); } } } public static void QueueStaticField(string aAssembly, string aType, string aField, out string aFieldName) { if (mCurrent == null) { throw new Exception("ERROR: No Current Engine found!"); } 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)); } public static void QueueStaticField(FieldInfo aField, out string aDataName) { if (mCurrent == null) { throw new Exception("ERROR: No Current Engine found!"); } 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 public static void QueueMethod(MethodBase aMethod) { if (mCurrent == null) { throw new Exception("ERROR: No Current Engine found!"); } if (mCurrent.ChangingInnerMethod != null) mCurrent.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.DeclaringType.Assembly.GetName().Name == "IndyIL2CPU_EmitAssm") { return; } if (!aMethod.IsStatic) { RegisterType(aMethod.DeclaringType); } using (mCurrent.mMethodsLocker.AcquireReaderLock()) { if (mCurrent.mMethods.ContainsKey(aMethod)) { return; } } using (mCurrent.mMethodsLocker.AcquireWriterLock()) { if (!mCurrent.mMethods.ContainsKey(aMethod)) { if (mCurrent.mMethods is ReadOnlyDictionary) { throw new Exception("Cannot queue " + aMethod.GetFullName()); } mCurrent.mMethods.Add(aMethod, new QueuedMethodInformation() { Processed = false, PreProcessed = false, Index = mCurrent.mMethods.Count }); } } } public static int GetMethodIdentifier(MethodBase aMethod) { QueueMethod(aMethod); using (mCurrent.mMethodsLocker.AcquireReaderLock()) { return mCurrent.mMethods[aMethod].Index; } } /// /// Registers_Old a type and returns the Type identifier /// /// /// public static void RegisterType(Type aType) { if (aType == null) { throw new ArgumentNullException("aType"); } if (mCurrent == null) { throw new Exception("ERROR: No Current Engine found!"); } 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 (mCurrent.mTypesLocker.AcquireReaderLock()) { var xItem = mCurrent.mTypes.FirstOrDefault(x => x.AssemblyQualifiedName.Equals(aType.AssemblyQualifiedName)); if (xItem != null) { return; } } Type xFoundItem; using (mCurrent.mTypesLocker.AcquireWriterLock()) { xFoundItem = mCurrent.mTypes.FirstOrDefault(x => x.AssemblyQualifiedName.Equals(aType.AssemblyQualifiedName)); if (xFoundItem == null) { mCurrent.mTypes.Add(aType); if (aType.FullName != "System.Object" && aType.BaseType != null) { Type xCurInspectedType = aType.BaseType; RegisterType(xCurInspectedType); } RegisterType(aType); } else { return; } } } //public static Assembly GetCrawledAssembly() //{ // if (mCurrent == null) // { // throw new Exception("ERROR: No Current Engine found!"); // } // return mCurrent.mCrawledAssembly; //} public static void QueueMethod2(string aAssembly, string aType, string aMethod) { MethodBase xMethodDef; QueueMethod2(aAssembly, aType, aMethod, out xMethodDef); } public static 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 mAssemblyDefCache = new SortedList(); public static Type GetType(string aAssembly, string aType) { Assembly xAssemblyDef; if (mCurrent.mAssemblyDefCache.ContainsKey(aAssembly)) { xAssemblyDef = mCurrent.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 = mCurrent.mCrawledAssembly.Resolver.Resolve(aAssembly); // } // mCurrent.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 static Type GetType(Assembly aAssembly, string aType) { if (mCurrent == null) { throw new Exception("ERROR: No Current Engine found!"); } 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 static 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 static IEnumerable GetAllAssemblies() { using (mCurrent.mMethodsLocker.AcquireReaderLock()) { return (from item in mCurrent.mMethods.Keys select item.DeclaringType.Module.Assembly).Distinct(new AssemblyEqualityComparer()).ToArray(); } } private int mInstructionsToSkip = 0; public static void SetInstructionsToSkip(int aCount) { if (mCurrent == null) { throw new Exception("No Current Engine!"); } mCurrent.mInstructionsToSkip = aCount; } public static readonly bool RunningOnMono; #region Implementation of IServiceProvider public T GetService() { if(typeof(T) == typeof(IMetaDataInfoService)) { return (T)(object)this; } throw new Exception("Service '" + typeof(T).FullName + "' not supported!"); } #endregion } }