diff --git a/source/Cosmos.Build.Windows/Builder.cs b/source/Cosmos.Build.Windows/Builder.cs index e6bcc8c6d..775504eee 100644 --- a/source/Cosmos.Build.Windows/Builder.cs +++ b/source/Cosmos.Build.Windows/Builder.cs @@ -117,7 +117,7 @@ namespace Cosmos.Build.Windows { }; xEngine.DebugLog += DoDebugLog; xEngine.Execute(xTarget.Location, TargetPlatformEnum.X86, g => Path.Combine(xAsmPath, g + ".asm"), false, - new string[] { Path.Combine(Path.Combine(ToolsPath, "Cosmos.Kernel.Plugs"), "Cosmos.Kernel.Plugs.dll") }, aDebugMode, aDebugComport, BuildPath); + new string[] { Path.Combine(Path.Combine(ToolsPath, "Cosmos.Kernel.Plugs"), "Cosmos.Kernel.Plugs.dll") }, aDebugMode, aDebugComport, xAsmPath); xSW.Stop(); Console.WriteLine("IL2CPU Run took " + xSW.Elapsed.ToString()); diff --git a/source/Cosmos.Build.Windows/Global.cs b/source/Cosmos.Build.Windows/Global.cs index 1ca4021ca..0060c4893 100644 --- a/source/Cosmos.Build.Windows/Global.cs +++ b/source/Cosmos.Build.Windows/Global.cs @@ -34,7 +34,7 @@ namespace Cosmos.Build.Windows { } if (aWait || (aCapture && xProcess.HasExited)) { - if (!xProcess.WaitForExit(60 * 1000) || xProcess.ExitCode != 0) { + if (!xProcess.WaitForExit(120 * 1000) || xProcess.ExitCode != 0) { //TODO: Fix if (aCapture) { Console.ForegroundColor = ConsoleColor.Red; diff --git a/source/Indy.IL2CPU.IL.X86/Callvirt.cs b/source/Indy.IL2CPU.IL.X86/Callvirt.cs index 081abc869..0be79d995 100644 --- a/source/Indy.IL2CPU.IL.X86/Callvirt.cs +++ b/source/Indy.IL2CPU.IL.X86/Callvirt.cs @@ -41,6 +41,7 @@ namespace Indy.IL2CPU.IL.X86 { mArgumentCount = mTargetMethodInfo.Arguments.Length; mReturnSize = mTargetMethodInfo.ReturnSize; mThisOffset = mTargetMethodInfo.Arguments[0].Offset; + if (mTargetMethodInfo.ExtraStackSize > 0) { mThisOffset -= mTargetMethodInfo.ExtraStackSize; } mCurrentILOffset = aReader.Position; mExtraStackSpace = mTargetMethodInfo.ExtraStackSize; diff --git a/source/Indy.IL2CPU.IL/InitVmtImplementationOp.cs b/source/Indy.IL2CPU.IL/InitVmtImplementationOp.cs index 68c8f3906..5e32f1be1 100644 --- a/source/Indy.IL2CPU.IL/InitVmtImplementationOp.cs +++ b/source/Indy.IL2CPU.IL/InitVmtImplementationOp.cs @@ -1,5 +1,4 @@ -#define MTW_DEBUG -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -22,7 +21,10 @@ namespace Indy.IL2CPU.IL { public InitVmtImplementationOp(ILReader aReader, MethodInformation aMethodInfo) : base(aReader, aMethodInfo) { } - + private static readonly bool mDebugMode = false; + static InitVmtImplementationOp() { + mDebugMode = Environment.MachineName.Equals("laptop-matthijs", StringComparison.InvariantCultureIgnoreCase); + } private IList mTypes; public MethodBase LoadTypeTableRef; public MethodBase SetTypeInfoRef; @@ -46,20 +48,23 @@ namespace Indy.IL2CPU.IL { protected abstract void Call(MethodBase aMethod); public override void DoAssemble() { -#if MTW_DEBUG - using (XmlWriter xDebug = XmlWriter.Create(@"d:\vtables.xml")) { - xDebug.WriteStartDocument(); - xDebug.WriteStartElement("VTables"); - xDebug.WriteStartElement("AllMethods"); - for(int i = 0; i < Methods.Count; i++){ - MethodBase xTheMethod = Methods[i]; - xDebug.WriteStartElement("Method"); - xDebug.WriteAttributeString("Id", GetMethodIdentifier(xTheMethod).ToString("X")); - xDebug.WriteAttributeString("Name", xTheMethod.GetFullName()); - xDebug.WriteEndElement(); - } - xDebug.WriteEndElement(); -#endif + XmlWriter xDebug=null; + if (mDebugMode) + { + xDebug = XmlWriter.Create(@"d:\vtables.xml"); + xDebug.WriteStartDocument(); + xDebug.WriteStartElement("VTables"); + xDebug.WriteStartElement("AllMethods"); + for (int i = 0; i < Methods.Count; i++) + { + MethodBase xTheMethod = Methods[i]; + xDebug.WriteStartElement("Method"); + xDebug.WriteAttributeString("Id", GetMethodIdentifier(xTheMethod).ToString("X")); + xDebug.WriteAttributeString("Name", xTheMethod.GetFullName()); + xDebug.WriteEndElement(); + } + xDebug.WriteEndElement(); + } string xTheName = DataMember.GetStaticFieldName(TypesFieldRef); DataMember xDataMember = (from item in Assembler.DataMembers where item.Value.Name == xTheName @@ -84,11 +89,12 @@ namespace Indy.IL2CPU.IL { Pushd("0" + mTypes.Count.ToString("X") + "h"); Call(LoadTypeTableRef); for (int i = 0; i < mTypes.Count; i++) { -#if MTW_DEBUG - xDebug.WriteStartElement("Type"); - xDebug.WriteAttributeString("Id", i.ToString("X")); + if (mDebugMode) + { + xDebug.WriteStartElement("Type"); + xDebug.WriteAttributeString("Id", i.ToString("X")); xDebug.WriteAttributeString("Name", mTypes[i].FullName); -#endif + } try { Type xType = mTypes[i]; @@ -159,9 +165,10 @@ namespace Indy.IL2CPU.IL { { throw new Exception("Base type not found!"); } -#if MTW_DEBUG - xDebug.WriteAttributeString("BaseId", xBaseIndex.Value.ToString("X")); -#endif + if (mDebugMode) + { + xDebug.WriteAttributeString("BaseId", xBaseIndex.Value.ToString("X")); + } if (!xType.IsInterface) { @@ -215,12 +222,13 @@ namespace Indy.IL2CPU.IL { if (xNewMethod == null) { System.Diagnostics.Debugger.Break(); } xMethod = xNewMethod; } -#if MTW_DEBUG - xDebug.WriteStartElement("Method"); - xDebug.WriteAttributeString("Id", xMethodId.ToString("X")); - xDebug.WriteAttributeString("Name", xMethod.GetFullName()); - xDebug.WriteEndElement(); -#endif + if (mDebugMode) + { + xDebug.WriteStartElement("Method"); + xDebug.WriteAttributeString("Id", xMethodId.ToString("X")); + xDebug.WriteAttributeString("Name", xMethod.GetFullName()); + xDebug.WriteEndElement(); + } if (!xType.IsInterface) { @@ -240,14 +248,17 @@ namespace Indy.IL2CPU.IL { } finally { -#if MTW_DEBUG - xDebug.WriteEndElement(); -#endif + if (mDebugMode) + { + xDebug.WriteEndElement(); + } } } -#if MTW_DEBUG - } -#endif + if (mDebugMode) + { + xDebug.Close(); + } + } } } diff --git a/source/Indy.IL2CPU/CustomImplementation/Microsoft/Win32/RegistryKeyImpl.cs b/source/Indy.IL2CPU/CustomImplementation/Microsoft/Win32/RegistryKeyImpl.cs new file mode 100644 index 000000000..bbfed5623 --- /dev/null +++ b/source/Indy.IL2CPU/CustomImplementation/Microsoft/Win32/RegistryKeyImpl.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Indy.IL2CPU.Plugs; +using Microsoft.Win32; + +namespace Indy.IL2CPU.CustomImplementation.Microsoft.Win32 +{ + [Plug(Target=typeof(RegistryKey))] + public static class RegistryKeyImpl + { + [PlugMethod(Signature="System_Void__Microsoft_Win32_RegistryKey__cctor__")] + public static void CCtor() { } + } +} diff --git a/source/Indy.IL2CPU/CustomImplementation/System/ArrayImpl.cs b/source/Indy.IL2CPU/CustomImplementation/System/ArrayImpl.cs index a2fa5f245..7280cc3c0 100644 --- a/source/Indy.IL2CPU/CustomImplementation/System/ArrayImpl.cs +++ b/source/Indy.IL2CPU/CustomImplementation/System/ArrayImpl.cs @@ -2,9 +2,12 @@ using System.Collections.Generic; using System.Linq; using System.Text; +using Indy.IL2CPU.Plugs; namespace Indy.IL2CPU.CustomImplementation.System { + [Plug(Target=typeof(Array))] public static class ArrayImpl { + public static object Clone(Array aThis) { return aThis; } //[MethodAlias(Name = "System.Void System.Array.Copy(System.Array,System.Int32,System.Array,System.Int32,System.Int32,System.Boolean)")] //public static void Copy(Array sourceArray, int sourceIndex, Array destinationArray, int destinationIndex, int length, bool reliable) { // for(int i = sourceIndex; i < length; i++) { diff --git a/source/Indy.IL2CPU/CustomImplementation/System/Security/Cryptography/Utils.cs b/source/Indy.IL2CPU/CustomImplementation/System/Security/Cryptography/Utils.cs new file mode 100644 index 000000000..b54869fda --- /dev/null +++ b/source/Indy.IL2CPU/CustomImplementation/System/Security/Cryptography/Utils.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Indy.IL2CPU.Plugs; + +namespace Indy.IL2CPU.CustomImplementation.System.Security.Cryptography +{ + [Plug(TargetName="System.Security.Cryptography.Utils")] + public static class Utils + { + public static int get_FipsAlgorithmPolicy() { return 0; } + } +} diff --git a/source/Indy.IL2CPU/Engine.cs b/source/Indy.IL2CPU/Engine.cs index 618befb09..7c60c5482 100644 --- a/source/Indy.IL2CPU/Engine.cs +++ b/source/Indy.IL2CPU/Engine.cs @@ -139,7 +139,7 @@ namespace Indy.IL2CPU { } public event Action ProgressChanged; - + private Func mGetFileNameForGroup; private void OnProgressChanged() { if (ProgressChanged != null) { ProgressChanged(); @@ -853,26 +853,28 @@ namespace Indy.IL2CPU { if (xManifestResourceName != null) { RegisterType(xCurrentField.FieldType); string xTheData = ""; + string xFileName = Path.Combine(mOutputDir, (xCurrentField.DeclaringType.Assembly.FullName + "__" + xManifestResourceName).Replace(",", "_") + ".res"); using (var xStream = xCurrentField.DeclaringType.Assembly.GetManifestResourceStream(xManifestResourceName)) { - // todo: abstract this array code out. - StringBuilder xSB = new StringBuilder((int)((xStream.Length * 4) + 32)); - xSB.Append(BitConverter.GetBytes(Engine.RegisterType(Engine.GetType("mscorlib", "System.Array"))).Aggregate("", (r, b) => r + b + ",")); - xSB.Append(BitConverter.GetBytes((uint)InstanceTypeEnum.StaticEmbeddedArray).Aggregate("", (r, b) => r + b + ",")); - xSB.Append(BitConverter.GetBytes((int)xStream.Length).Aggregate("", (r, b) => r + b + ",")); - xSB.Append(BitConverter.GetBytes((int)1).Aggregate("", (r, b) => r + b + ",")); - var xBuff = new byte [128]; - while(xStream.Position < xStream.Length){ - int xBytesRead = xStream.Read(xBuff, 0, 128); - xSB.Append(xBuff.Take(xBytesRead).Aggregate("", (r, b) => r + b + ",")); + 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); + } } - xTheData = xSB.ToString(); } - xTheData = xTheData.TrimEnd(','); mAssembler.DataMembers.Add(new KeyValuePair("ManifestResourceStreams", new DataMember("___" + xFieldName + "___Contents", - "db", - xTheData))); + "incbin", + "\"" + xFileName + "\""))); mAssembler.DataMembers.Add(new KeyValuePair("ManifestResourceStreams", new DataMember(xFieldName, "dd", diff --git a/source/Indy.IL2CPU/Indy.IL2CPU.csproj b/source/Indy.IL2CPU/Indy.IL2CPU.csproj index 0c63474fb..0c77b455a 100644 --- a/source/Indy.IL2CPU/Indy.IL2CPU.csproj +++ b/source/Indy.IL2CPU/Indy.IL2CPU.csproj @@ -91,6 +91,7 @@ + @@ -98,6 +99,7 @@ + diff --git a/source/MatthijsTest/Program.cs b/source/MatthijsTest/Program.cs index 1b66b73a6..d555acd7f 100644 --- a/source/MatthijsTest/Program.cs +++ b/source/MatthijsTest/Program.cs @@ -1,10 +1,12 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Reflection; using System.Text; using Cosmos.Build.Windows; using System.Collections; +using System.Security.Cryptography; namespace MatthijsTest { @@ -28,19 +30,61 @@ namespace MatthijsTest public static void Init() { Console.Clear(); - if (TheManifestResource == null) { - Console.WriteLine("Field TheManifestResource is null!"); - return; } + MemoryStream xMS = new MemoryStream(TheManifestResource, false); Console.Write("Length: "); - Console.WriteLine(TheManifestResource.Length.ToString()); - int xLength = TheManifestResource.Length; - if(xLength > 10) { - Console.WriteLine("Too much data!"); - return; - } - for(int i = 0; i < xLength;i++) { - Console.WriteLine(TheManifestResource[i].ToString()); + Console.WriteLine(((int)xMS.Length).ToString()); + SHA256Managed xSHA = new SHA256Managed(); + var xHash = xSHA.ComputeHash(xMS); + Console.Write("0x"); + for (int i = 0; i < xHash.Length; i++) { + PrintHex(xHash[i]);} + Console.WriteLine(""); + } + + private static string SingleDigitToHex(byte d) + { + switch (d) + { + case 0: + return "0"; + case 1: + return "1"; + case 2: + return "2"; + case 3: + return "3"; + case 4: + return "4"; + case 5: + return "5"; + case 6: + return "6"; + case 7: + return "7"; + case 8: + return "8"; + case 9: + return "9"; + case 10: + return "A"; + case 11: + return "B"; + case 12: + return "C"; + case 13: + return "D"; + case 14: + return "E"; + case 15: + return "F"; } + return " "; + + } + + public static void PrintHex(byte aByte) { + Console.Write(SingleDigitToHex((byte)(aByte / 16))); + Console.Write(SingleDigitToHex((byte)(aByte & 0xF))); } } } diff --git a/source/MatthijsTest/Test.txt b/source/MatthijsTest/Test.txt index 6d5e02637..618befb09 100644 --- a/source/MatthijsTest/Test.txt +++ b/source/MatthijsTest/Test.txt @@ -1 +1,2033 @@ -Test \ No newline at end of file +#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; + +namespace Indy.IL2CPU { + public class MethodBaseComparer : IComparer { + #region IComparer Members + + public int Compare(MethodBase x, + MethodBase y) { + return x.GetFullName().CompareTo(y.GetFullName()); + } + + #endregion + } + + public class FieldInfoComparer : IComparer { + #region IComparer Members + + public int Compare(FieldInfo x, + FieldInfo y) { + return x.GetFullName().CompareTo(y.GetFullName()); + } + + #endregion + } + + public class TypeComparer : IComparer { + public int Compare(Type x, + Type y) { + return x.AssemblyQualifiedName.CompareTo(y.AssemblyQualifiedName); + } + } + + public class TypeEqualityComparer : IEqualityComparer { + public bool Equals(Type x, + Type y) { + return x.FullName.Equals(y.FullName); + } + + public int GetHashCode(Type obj) { + return obj.FullName.GetHashCode(); + } + } + + public class AssemblyEqualityComparer : IEqualityComparer { + public bool Equals(Assembly x, + Assembly y) { + return x.GetName().FullName.Equals(y.GetName().FullName); + } + + public int GetHashCode(Assembly obj) { + return obj.GetName().FullName.GetHashCode(); + } + } + + public enum LogSeverityEnum { + Informational, + Warning, + Error + } + + public delegate void DebugLogHandler(LogSeverityEnum aSeverity, + string aMessage); + + public enum TargetPlatformEnum { + X86 + } + + public enum DebugModeEnum { + None, + IL, + Source, + MLUsingGDB + } + + public class QueuedMethodInformation { + public bool Processed; + public int Index; + public MLDebugSymbol[] Instructions; + } + + public class Engine { + protected static Engine mCurrent; + protected Assembly mCrawledAssembly; + protected DebugLogHandler mDebugLog; + protected OpCodeMap mMap; + protected Assembler.Assembler mAssembler; + + private SortedList mPlugMethods; + private SortedList> mPlugFields; + + /// + /// Contains a list of all methods. This includes methods to be processed and already processed. + /// + protected SortedList mMethods = new SortedList(new MethodBaseComparer()); + + /// + /// Contains a list of all static fields. This includes static fields to be processed and already processed. + /// + protected SortedList mStaticFields = new SortedList(new FieldInfoComparer()); + + protected IList mTypes = new List(); + protected TypeEqualityComparer mTypesEqualityComparer = new TypeEqualityComparer(); + private byte mDebugComport; + private DebugModeEnum mDebugMode; + private List mDebugSymbols = new List(); + private List mSymbols = new List(); + private string mOutputDir; + + public int ProgressMax { + get { + return mMethods.Count + mStaticFields.Count; + } + } + + public int ProgressCurrent { + get { + return (from item in mMethods + where item.Value.Processed + select item).Count() + (from item in mStaticFields + where item.Value + select item).Count(); + } + } + + public event Action ProgressChanged; + + private void OnProgressChanged() { + if (ProgressChanged != null) { + ProgressChanged(); + } + } + + /// + /// 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. + /// + /// Whether or not the output is metalmode only. + public void Execute(string aAssembly, + TargetPlatformEnum aTargetPlatform, + Func aGetFileNameForGroup, + bool aInMetalMode, + IEnumerable aPlugs, + DebugModeEnum aDebugMode, + byte aDebugComNumber, + string aOutputDir) { + mCurrent = this; + try { + if (aGetFileNameForGroup == null) { + throw new ArgumentNullException("aGetFileNameForGroup"); + } + mCrawledAssembly = Assembly.LoadFile(aAssembly); + //if (!String.IsNullOrEmpty(aDebugSymbols)) { + // mDebugSymbols = new DebugSymbolsOld(); + //} + 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; + //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: { + mMap = (OpCodeMap)Activator.CreateInstance(Type.GetType("Indy.IL2CPU.IL.X86.X86OpCodeMap, Indy.IL2CPU.IL.X86", + true)); + mAssembler = new Assembler.X86.Assembler(aGetFileNameForGroup, + aInMetalMode, + ((aDebugMode != DebugModeEnum.None) && (aDebugMode != DebugModeEnum.MLUsingGDB)) + ? aDebugComNumber + : (byte)0); + break; + } + default: + throw new NotSupportedException("TargetPlatform '" + aTargetPlatform + "' not supported!"); + } + InitializePlugs(aPlugs); + using (mAssembler) { + //mAssembler.OutputType = Assembler.Win32.Assembler.OutputTypeEnum.Console; + //foreach (string xPlug in aPlugs) { + //this.I + List xAppDefs = new List(); + xAppDefs.Add(mCrawledAssembly); + mAssembler.MainGroup = "main"; + mAssembler.CurrentGroup = "main"; + AssemblyEqualityComparer xComparer = new AssemblyEqualityComparer(); + foreach (Assembly xAsm in AppDomain.CurrentDomain.GetAssemblies()) { + Assembly xAssemblyDef = Assembly.LoadFrom(xAsm.Location); + if (!xAppDefs.Contains(xAssemblyDef)) { + xAppDefs.Add(xAssemblyDef); + } + } + //for (int i = 0; i < xAppDefs.Count; i++) { + // Assembly xCurDef = xAppDefs[i]; + // foreach (ModuleDefinition xModDef in xCurDef.Modules) { + // foreach (AssemblyNameReference xAssemblyNameRef in xModDef.AssemblyReferences) { + // Assembly xReffedAssemblyDef = mCrawledAssembly.Resolver.Resolve(xAssemblyNameRef); + // if (xReffedAssemblyDef != null) { + // if (!xAppDefs.Contains(xReffedAssemblyDef, new AssemblyEqualityComparer())) { + // xAppDefs.Add(xReffedAssemblyDef); + // } + // } + // } + // } + //} + mMap.Initialize(mAssembler, + xAppDefs); + mAssembler.DebugMode = false; + //!String.IsNullOrEmpty(aDebugSymbols); + IL.Op.QueueMethod += QueueMethod; + IL.Op.QueueStaticField += QueueStaticField; + try { + mTypes.Add(typeof(object)); + mMethods.Add(RuntimeEngineRefs.InitializeApplicationRef, + new QueuedMethodInformation() { + Processed = false, + Index = mMethods.Count + }); + mMethods.Add(RuntimeEngineRefs.FinalizeApplicationRef, + new QueuedMethodInformation() { + Processed = false, + Index = mMethods.Count + }); + if (!aInMetalMode) { + 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(xEntryPoint, + new QueuedMethodInformation() { + Processed = false, + Index = mMethods.Count + }); + OnProgressChanged(); + ProcessAllMethods(); + if (!aInMetalMode) { + do { + int xOldCount = mMethods.Count; + ScanForMethodsToIncludeForVMT(); + ProcessAllMethods(); + if (xOldCount == mMethods.Count) { + break; + } + } while (true); + } + // initialize the runtime engine + mAssembler.CurrentGroup = "main"; + MainEntryPointOp xEntryPointOp = (MainEntryPointOp)GetOpFromType(mMap.MainEntryPointOp, + null, + null); + xEntryPointOp.Assembler = mAssembler; + xEntryPointOp.Enter(Assembler.Assembler.EntryPointName); + xEntryPointOp.Call(RuntimeEngineRefs.InitializeApplicationRef); + if (!aInMetalMode) { + xEntryPointOp.Call("____INIT__VMT____"); + } + 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.Pushd("0"); + } + // todo: implement support for returncodes? + xEntryPointOp.Call(RuntimeEngineRefs.FinalizeApplicationRef); + xEntryPointOp.Exit(); + ProcessAllMethods(); + if (!aInMetalMode) { + do { + int xOldCount = mMethods.Count; + ScanForMethodsToIncludeForVMT(); + ProcessAllMethods(); + if (xOldCount == mMethods.Count) { + break; + } + } while (true); + mAssembler.CurrentGroup = "main"; + GenerateVMT(mDebugMode != DebugModeEnum.None); + } + mMap.PostProcess(mAssembler); + ProcessAllStaticFields(); + if (mSymbols != null) { + string xOutputFile = Path.Combine(mOutputDir, + "debug.cxdb"); + MLDebugSymbol.WriteSymbolsListToFile(mSymbols, + xOutputFile); + } + //if (mDebugSymbols != null) { + // GenerateDebugSymbols(); + //} + //XmlSerializer xSerializer = new XmlSerializer(typeof(DebugSymbolsOld)); + //using (FileStream xFS = new FileStream(aDebugSymbols, FileMode.Create)) { + // xSerializer.Serialize(xFS, mDebugSymbols); + //} + } finally { + mAssembler.Flush(); + IL.Op.QueueMethod -= QueueMethod; + IL.Op.QueueStaticField -= QueueStaticField; + } + } + } finally { + mCurrent = null; + } + } + + 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)); + 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); + xInitVmtOp.Methods = mMethods.Keys; + xInitVmtOp.VTableEntrySize = GetFieldStorageSize(GetType("", + typeof(VTable).FullName.Replace('+', + '.'))); + xInitVmtOp.GetMethodIdentifier += delegate(MethodBase aMethod) { + 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); + }; + 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)); + xOp.Assembler = mAssembler; + xOp.Assemble(); + } + + private void ScanForMethodsToIncludeForVMT() { + List xCheckedTypes = new List(); + foreach (MethodBase xMethod in mMethods.Keys) { + if (xMethod.IsStatic) { + continue; + } + Type xCurrentType = xMethod.DeclaringType; + if (!xCheckedTypes.Contains(xCurrentType, + mTypesEqualityComparer)) { + xCheckedTypes.Add(xCurrentType); + } + } + foreach (Type xType in mTypes) { + if (!xCheckedTypes.Contains(xType, + mTypesEqualityComparer)) { + xCheckedTypes.Add(xType); + } + } + for (int 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 i = 0; i < xParams.Length; i++) { + xMethodParams[i] = xParams[i].ParameterType; + } + MethodBase xBaseMethod = GetUltimateBaseMethod(xMethod, + xMethodParams, + xTD); + if (xBaseMethod != null && + xBaseMethod != xMethod) { + if (mMethods.ContainsKey(xBaseMethod)) { + QueueMethod(xMethod); + } + } + } + } + } + } + for (int j = 0; j < mMethods.Count; j++) { + var xMethod = mMethods.Skip(j).First(); + if (xMethod.Key.DeclaringType.IsInterface) { + var xInterface = xMethod.Key.DeclaringType; + foreach (var xImplType in mTypes) { + 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) { + 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]); + 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) { + 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) { + 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 static int 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 xSLA.Size; + } + } + } + int xResult; + GetTypeFieldInfo(aType, + out xResult); + return xResult; + } + + private static string GetGroupForType(Type aType) { + return aType.Module.Assembly.GetName().Name; + } + + private void ProcessAllStaticFields() { + FieldInfo xCurrentField; + while ((xCurrentField = (from item in mStaticFields.Keys + where !mStaticFields[item] + select item).FirstOrDefault()) != null) { + mAssembler.CurrentGroup = GetGroupForType(xCurrentField.DeclaringType); + string xFieldName = xCurrentField.GetFullName(); + OnDebugLog(LogSeverityEnum.Informational, + "Processing Static Field '{0}'", + xFieldName); + xFieldName = DataMember.GetStaticFieldName(xCurrentField); + if (mAssembler.DataMembers.Count(x => x.Value.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 xTheData = ""; + using (var xStream = xCurrentField.DeclaringType.Assembly.GetManifestResourceStream(xManifestResourceName)) + { + // todo: abstract this array code out. + StringBuilder xSB = new StringBuilder((int)((xStream.Length * 4) + 32)); + xSB.Append(BitConverter.GetBytes(Engine.RegisterType(Engine.GetType("mscorlib", "System.Array"))).Aggregate("", (r, b) => r + b + ",")); + xSB.Append(BitConverter.GetBytes((uint)InstanceTypeEnum.StaticEmbeddedArray).Aggregate("", (r, b) => r + b + ",")); + xSB.Append(BitConverter.GetBytes((int)xStream.Length).Aggregate("", (r, b) => r + b + ",")); + xSB.Append(BitConverter.GetBytes((int)1).Aggregate("", (r, b) => r + b + ",")); + var xBuff = new byte [128]; + while(xStream.Position < xStream.Length){ + int xBytesRead = xStream.Read(xBuff, 0, 128); + xSB.Append(xBuff.Take(xBytesRead).Aggregate("", (r, b) => r + b + ",")); + } + xTheData = xSB.ToString(); + } + xTheData = xTheData.TrimEnd(','); + mAssembler.DataMembers.Add(new KeyValuePair("ManifestResourceStreams", + new DataMember("___" + xFieldName + "___Contents", + "db", + xTheData))); + mAssembler.DataMembers.Add(new KeyValuePair("ManifestResourceStreams", + new DataMember(xFieldName, + "dd", + "___" + xFieldName + "___Contents"))); + } + else + { + RegisterType(xCurrentField.FieldType); + { + int xTheSize; + string theType = "db"; + Type xFieldTypeDef = xCurrentField.FieldType; + //TypeSpecification xTypeSpec = xCurrentField.FieldType as TypeSpecification; + //if (xTypeSpec == null) { + if (!xFieldTypeDef.IsClass || + xFieldTypeDef.IsValueType) + { + xTheSize = GetFieldStorageSize(xCurrentField.FieldType); + } + else + { + xTheSize = 4; + } + //} else { + //xTheSize = 4; + //} + if (xTheSize == 4) + { + theType = "dd"; + xTheSize = 1; + } + else + { + if (xTheSize == 2) + { + theType = "dw"; + xTheSize = 1; + } + } + string xTheData = ""; + if (xTheSize == 0) + { + throw new Exception("Field '" + xCurrentField.ToString() + "' doesn't have a valid size!"); + } + for (uint i = 0; i < xTheSize; i++) + { + xTheData += "0,"; + } + xTheData = xTheData.TrimEnd(','); + mAssembler.DataMembers.Add(new KeyValuePair(mAssembler.CurrentGroup, + new DataMember(xFieldName, + theType, + xTheData))); + } + } + } + mStaticFields[xCurrentField] = true; + OnProgressChanged(); + } + } + + private ISymbolReader GetSymbolReaderForAssembly(Assembly aAssembly) { + return SymbolAccess.GetReaderForFile(aAssembly.Location); + } + + private void ProcessAllMethods() { + MethodBase xCurrentMethod; + while ((xCurrentMethod = (from item in mMethods.Keys + where !mMethods[item].Processed + select item).FirstOrDefault()) != null) { + try { + mAssembler.CurrentGroup = GetGroupForType(xCurrentMethod.DeclaringType); + OnDebugLog(LogSeverityEnum.Informational, + "Processing method '{0}'", + xCurrentMethod.GetFullName()); + RegisterType(xCurrentMethod.DeclaringType); + if (xCurrentMethod.IsAbstract) { + mMethods[xCurrentMethod].Processed = true; + continue; + } + string xMethodName = Label.GenerateLabelName(xCurrentMethod); + TypeInformation xTypeInfo = null; + { + if (!xCurrentMethod.IsStatic) { + xTypeInfo = GetTypeInfo(xCurrentMethod.DeclaringType); + } + } + MethodInformation xMethodInfo = GetMethodInfo(xCurrentMethod, + xCurrentMethod, + xMethodName, + xTypeInfo, + mDebugMode != DebugModeEnum.None); + IL.Op xOp = GetOpFromType(mMap.MethodHeaderOp, + null, + xMethodInfo); + xOp.Assembler = mAssembler; +#if VERBOSE_DEBUG + string comment = ""; + if (xMethodInfo.TypeInfo == null) { + comment = "(No Type Info available)"; + } else { + comment = "Type Info:\r\n \r\n" + xMethodInfo.TypeInfo.ToString(); + } + 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(); + bool xIsCustomImplementation = false; + MethodBase xCustomImplementation = GetCustomMethodImplementation(xMethodName); + if (xCustomImplementation != null) { + xIsCustomImplementation = true; + } + // 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, + mAssembler.InMetalMode)) { + mMap.DoCustomAssembleImplementation(mAssembler.InMetalMode, + mAssembler, + xMethodInfo); + } else { + if (Enum.GetNames(typeof(CustomMethodEnum)).Contains(xMethodName)) { + CustomMethodImplementationOp xCustomMethodImplOp = (CustomMethodImplementationOp)GetOpFromType(mMap.CustomMethodImplementationOp, + null, + xMethodInfo); + xCustomMethodImplOp.Assembler = mAssembler; + xCustomMethodImplOp.Method = (CustomMethodEnum)Enum.Parse(typeof(CustomMethodEnum), + xMethodName); + xCustomMethodImplOp.Assemble(); + } else { + //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(); + int xPreviousOffset = -1; + int[] xCodeOffsets = null; + ISymbolDocument[] xCodeDocuments = null; + int[] xCodeLines = null; + int[] xCodeColumns = null; + int[] xCodeEndLines = null; + int[] xCodeEndColumns = null; + int xCurrentOffset = 0; + bool xHasSymbols = false; + if (mDebugMode == DebugModeEnum.Source) { + var xSymbolReader = GetSymbolReaderForAssembly(xCurrentMethod.DeclaringType.Assembly); + if (xSymbolReader != null) { + var xSmbMethod = xSymbolReader.GetMethod(new SymbolToken(xCurrentMethod.MetadataToken)); + if (xSmbMethod != null) { + xCodeOffsets = new int[xSmbMethod.SequencePointCount]; + xCodeDocuments = new ISymbolDocument[xSmbMethod.SequencePointCount]; + xCodeLines = new int[xSmbMethod.SequencePointCount]; + xCodeColumns = new int[xSmbMethod.SequencePointCount]; + xCodeEndLines = new int[xSmbMethod.SequencePointCount]; + xCodeEndColumns = new int[xSmbMethod.SequencePointCount]; + xSmbMethod.GetSequencePoints(xCodeOffsets, + xCodeDocuments, + xCodeLines, + xCodeColumns, + xCodeEndLines, + xCodeEndColumns); + xHasSymbols = true; + } + } + } + int xILIndex = -1; + while (xReader.Read()) { + xILIndex++; + if (mInstructionsToSkip > 0) { + mInstructionsToSkip--; + continue; + } + ExceptionHandlingClause xCurrentHandler = null; + + #region Exception handling support code + + 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; + } + 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; + } + 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; + } + 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); + if ((!xOp.SupportsMetalMode) && + mAssembler.InMetalMode) { + throw new Exception("OpCode '" + xReader.OpCode + "' not supported in Metal mode!"); + } + xOp.Assembler = mAssembler; + new Comment("StackItems = " + mAssembler.StackContents.Count); + foreach (var xStackContent in mAssembler.StackContents) { + new Comment(" " + xStackContent.Size); + } + string xLabel = Op.GetInstructionLabel(xReader); + if (xLabel.StartsWith(".")) { + xLabel = Label.LastFullLabel + "__DOT__" + xLabel.Substring(1); + xLabel = DataMember.FilterStringForIncorrectChars(xLabel); + } + //if (mDebugSymbols != null) { + // xInstructionInfo = new DebugSymbolsAssemblyTypeMethodInstruction(); + // xInstructionInfo.Address = xLabel; + // xInstructionInfo.InstructionType = xReader.OpCode.ToString(); + // xCurrentStack = (from item in mAssembler.StackContents + // let xSize = (item.Size % 4 == 0) ? item.Size : (item.Size + (4 - (item.Size % 4))) + // select xSize).Sum(); + //} + // todo: calculate opcode number + bool xShouldIncludeDebugHeader = false; + + #region determine if a new DebugHeader should be emitted + + if (mDebugMode == DebugModeEnum.IL) { + xShouldIncludeDebugHeader = true; + } else { + if (mDebugMode == DebugModeEnum.Source) { + if (xPreviousOffset == -1) { + xShouldIncludeDebugHeader = true; + } else { + if (xHasSymbols) { + if (xCodeDocuments[xPreviousOffset] != xCodeDocuments[xCurrentOffset] || xCodeLines[xPreviousOffset] != xCodeLines[xCurrentOffset] || xCodeColumns[xPreviousOffset] != xCodeColumns[xCurrentOffset] || xCodeEndLines[xPreviousOffset] != xCodeEndLines[xCurrentOffset] || + xCodeEndColumns[xPreviousOffset] != xCodeEndColumns[xCurrentOffset]) { + xShouldIncludeDebugHeader = true; + } + } + } + } + } + xShouldIncludeDebugHeader &= xReader.OpCode != OpCodeEnum.Nop; + + #endregion + + if (xShouldIncludeDebugHeader) { + mMap.EmitOpDebugHeader(mAssembler, + 0, + xLabel); + mDebugSymbols.Add(new DebugSymbol() { + AssemblyFileName = xCurrentMethod.DeclaringType.Assembly.Location, + InstructionOffset = xCurrentOffset, + LabelName = xLabel, + MethodMetaDataToken = xCurrentMethod.MetadataToken + }); + xPreviousOffset = xCurrentOffset; + } + 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; + xMLSymbol.AssemblyFile = xCurrentMethod.DeclaringType.Assembly.Location; + xMLSymbol.MethodToken = xCurrentMethod.MetadataToken; + xMLSymbol.TypeToken = xCurrentMethod.DeclaringType.MetadataToken; + xMLSymbol.ILOffset = 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) { + mMethods[xCurrentMethod].Instructions = mSymbols.ToArray(); + } + //if (mDebugSymbols != null) { + // mMethods[xCurrentMethod].Instructions = xInstructionInfos.ToArray(); + //} + } else { + if ((xCurrentMethod.Attributes & MethodAttributes.PinvokeImpl) != 0) { + HandlePInvoke(xCurrentMethod, + xMethodInfo); + } else { + OnDebugLog(LogSeverityEnum.Warning, + "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(); + mMethods[xCurrentMethod].Processed = true; + } catch (Exception) { + OnDebugLog(LogSeverityEnum.Error, + xCurrentMethod.GetFullName()); + throw; + } + OnProgressChanged(); + } + } + + 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) { + 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 (xParams[i].Name == "aThis" && + i == 0) { + 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()); + 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) { + foreach (var xType in (from item in xAssemblyDef.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; + 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 (xPlugFields.ContainsKey(xPlugField.FieldId)) { + throw new Exception("PlugField already defined!"); + } + 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 (mAssembler.InMetalMode && + !xPlugMethodAttrib.InMetalMode) { + continue; + } else { + if (!xPlugMethodAttrib.InNormalMode) { + continue; + } + } + if (!String.IsNullOrEmpty(xSignature)) { + if (mPlugMethods.ContainsKey(xSignature)) { + System.Diagnostics.Debugger.Break(); + } + mPlugMethods.Add(xSignature, + xMethod); + continue; + } + } + string xStrippedSignature = GetStrippedMethodBaseFullName(xMethod); + foreach (MethodBase xOrigMethodDef in xTypeRef.GetMethods(BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance | BindingFlags.NonPublic)) { + string xOrigStrippedSignature = GetStrippedMethodBaseFullName(xOrigMethodDef); + if (xOrigStrippedSignature == xStrippedSignature) { + if (mPlugMethods.ContainsKey(Label.GenerateLabelName(xOrigMethodDef))) { + System.Diagnostics.Debugger.Break(); + } + mPlugMethods.Add(Label.GenerateLabelName(xOrigMethodDef), + xMethod); + } + } + foreach (MethodBase xOrigMethodDef in xTypeRef.GetConstructors(BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance | BindingFlags.NonPublic)) { + string xOrigStrippedSignature = GetStrippedMethodBaseFullName(xOrigMethodDef); + if (xOrigStrippedSignature == xStrippedSignature) { + if (mPlugMethods.ContainsKey(Label.GenerateLabelName(xOrigMethodDef))) { + System.Diagnostics.Debugger.Break(); + } + mPlugMethods.Add(Label.GenerateLabelName(xOrigMethodDef), + xMethod); + } + } + } + } + } + //Console.Write(new String('-', Console.WindowWidth)); + Console.WriteLine("Recognized Plug methods:"); + foreach (string s in mPlugMethods.Keys) { + Console.WriteLine(s); + } + //Console.Write(new String('-', Console.WindowWidth)); + } + + private MethodBase GetCustomMethodImplementation(string aMethodName) { + if (mPlugMethods.ContainsKey(aMethodName)) { + return mPlugMethods[aMethodName]; + } + return null; + } + + public static TypeInformation GetTypeInfo(Type aType) { + TypeInformation xTypeInfo; + int xObjectStorageSize; + Dictionary xTypeFields = GetTypeFieldInfo(aType, + out xObjectStorageSize); + xTypeInfo = new TypeInformation(xObjectStorageSize, + xTypeFields, + aType, + (!aType.IsValueType) && aType.IsClass); + return xTypeInfo; + } + + public static MethodInformation GetMethodInfo(MethodBase aCurrentMethodForArguments, + MethodBase aCurrentMethodForLocals, + string aMethodName, + TypeInformation aTypeInfo, + bool aDebugMode) { + 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 = 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; + int 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 += 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]; + int 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 += xArgSize; + } + } + int xResultSize = 0; + //= GetFieldStorageSize(aCurrentMethodForArguments.ReturnType.ReturnType); + MethodInfo xMethInfo = aCurrentMethodForArguments as MethodInfo; + Type xReturnType = typeof(void); + if (xMethInfo != null) { + xResultSize = GetFieldStorageSize(xMethInfo.ReturnType); + xReturnType = xMethInfo.ReturnType; + } + xMethodInfo = new MethodInformation(aMethodName, + xVars, + xArgs, + xResultSize, + !aCurrentMethodForArguments.IsStatic, + aTypeInfo, + aCurrentMethodForArguments, + xReturnType, + aDebugMode); + } + return xMethodInfo; + } + + public static Dictionary GetTypeFieldInfo(MethodBase aCurrentMethod, + out int aObjectStorageSize) { + Type xCurrentInspectedType = aCurrentMethod.DeclaringType; + return GetTypeFieldInfo(xCurrentInspectedType, + out aObjectStorageSize); + } + + private static void GetTypeFieldInfoImpl(List> aTypeFields, + Type aType, + ref int 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 = GetFieldStorageSize(xFieldType); + } + //} + if ((from item in aTypeFields + where item.Key == xFieldId + select item).Count() > 0) { continue; } + int xOffset = aObjectStorageSize; + FieldOffsetAttribute xOffsetAttrib = xField.GetCustomAttributes(typeof(FieldOffsetAttribute), + true).FirstOrDefault() as FieldOffsetAttribute; + if (xOffsetAttrib != null) { + xOffset = xOffsetAttrib.Value; + } else { + aObjectStorageSize += 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.IsClass && !xFieldType.IsValueType) || + xItem.IsExternalValue) { + xFieldSize = 4; + } else { + xFieldSize = GetFieldStorageSize(xFieldType); + } + int xOffset = aObjectStorageSize; + aObjectStorageSize += 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 static Dictionary GetTypeFieldInfo(Type aType, + out int aObjectStorageSize) { + var xTypeFields = new List>(); + aObjectStorageSize = 0; + GetTypeFieldInfoImpl(xTypeFields, + aType, + ref aObjectStorageSize); + if (aType.IsExplicitLayout) { + var xStructLayout = aType.StructLayoutAttribute; + if (xStructLayout.Size == 0) { + aObjectStorageSize = (from item in xTypeFields + let xSize = item.Value.Offset + item.Value.Size + orderby xSize + select xSize).FirstOrDefault(); + } else { + aObjectStorageSize = 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 static Op GetOpFromType(Type aType, + ILReader aReader, + MethodInformation aMethodInfo) { + return (IL.Op)Activator.CreateInstance(aType, + aReader, + aMethodInfo); + } + + public static void QueueStaticField(FieldInfo aField) { + if (mCurrent == null) { + throw new Exception("ERROR: No Current Engine found!"); + } + if (!mCurrent.mStaticFields.ContainsKey(aField)) { + mCurrent.mStaticFields.Add(aField, + false); + } + } + + 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 (aMethod == null) { System.Diagnostics.Debugger.Break(); } + if (!aMethod.IsStatic) { + RegisterType(aMethod.DeclaringType); + } + if (aMethod.DeclaringType.FullName == "System.Object" && aMethod.Name == "Equals" && aMethod.GetParameters().Length == 1 && + aMethod.GetParameters()[0].ParameterType.FullName == "System.Object") { + System.Diagnostics.Debugger.Break(); + } + if (!mCurrent.mMethods.ContainsKey(aMethod)) { + mCurrent.mMethods.Add(aMethod, + new QueuedMethodInformation() { + Processed = false, + Index = mCurrent.mMethods.Count + }); + } + } + + public static int GetMethodIdentifier(MethodBase aMethod) { + QueueMethod(aMethod); + return mCurrent.mMethods[aMethod].Index; + } + + /// + /// Registers a type and returns the Type identifier + /// + /// + /// + public static int 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(); + } + } + Type xFoundItem = mCurrent.mTypes.FirstOrDefault(x => x.FullName.Equals(aType.FullName)); + if (xFoundItem == null) { + mCurrent.mTypes.Add(aType); + if (aType.FullName != "System.Object" && + aType.BaseType != null) { + Type xCurInspectedType = aType.BaseType; + RegisterType(xCurInspectedType); + } + return RegisterType(aType); + } else { + return mCurrent.mTypes.IndexOf(xFoundItem); + } + } + + private static int GetTypeId(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!"); + } + aType = aType.GetElementType(); + } + Type xFoundItem = mCurrent.mTypes.FirstOrDefault(x => x.FullName.Equals(aType.FullName)); + if (xFoundItem == null) { + return -1; + } else { + return mCurrent.mTypes.IndexOf(xFoundItem); + } + } + + 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!"); + } + + private void HandlePInvoke(MethodBase aMethod, + MethodInformation aMethodInfo) { + IL.Op xPInvokeMethodBodyOp = (IL.Op)Activator.CreateInstance(mMap.PInvokeMethodBodyOp, + aMethod, + aMethodInfo); + xPInvokeMethodBodyOp.Assembler = mAssembler; + xPInvokeMethodBodyOp.Assemble(); + } + + public static IEnumerable GetAllAssemblies() { + return (from item in mCurrent.mMethods.Keys + select item.DeclaringType.Module.Assembly).Distinct(new AssemblyEqualityComparer()); + } + + private int mInstructionsToSkip = 0; + + public static void SetInstructionsToSkip(int aCount) { + if (mCurrent == null) { + throw new Exception("No Current Engine!"); + } + mCurrent.mInstructionsToSkip = aCount; + } + } +} \ No newline at end of file