#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 { NativeX86 } 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 mMLDebugSymbols = new List(); private string mOutputDir; /// /// 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, string aAssemblyDir, IEnumerable aPlugs, DebugModeEnum aDebugMode, byte aDebugComNumber) { 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 = Path.GetDirectoryName(aAssembly); 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.NativeX86: { mMap = (OpCodeMap)Activator.CreateInstance(Type.GetType("Indy.IL2CPU.IL.X86.Native.NativeOpCodeMap, Indy.IL2CPU.IL.X86.Native", true)); mAssembler = new Assembler.X86.Native.Assembler(aGetFileNameForGroup, aInMetalMode, ((aDebugMode != DebugModeEnum.None) && (aDebugMode != DebugModeEnum.MLUsingGDB)) ? aDebugComNumber : (byte?)null); 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 }); 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(); } mMap.PostProcess(mAssembler); ProcessAllStaticFields(); if (mMLDebugSymbols != null) { MLDebugSymbol.WriteSymbolsListToFile(mMLDebugSymbols, Path.Combine(mOutputDir, "msil-instructions.dbg")); } //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() { Op xOp = GetOpFromType(mMap.MethodHeaderOp, null, new MethodInformation("____INIT__VMT____", new MethodInformation.Variable[0], new MethodInformation.Argument[0], 0, false, null, null, typeof(void))); 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))); 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 && !xMethod.IsFinal) { 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); } } } } } } } 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, aMethodParams); 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 E) { // 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) { RegisterType(xCurrentField.FieldType); //xCurrentField. //object xDefault = xCurrentField.GetRawConstantValue(); //if (xDefault != null) { // throw new Exception("Field has RawConstantValue, but this is not handled!"); //} //if (xCurrentField.InitialValue != null && xCurrentField.InitialValue.Length > 0) { // string xTheData = ""; // int xStorageSize = GetFieldStorageSize(xCurrentField.FieldType); // if (xCurrentField.InitialValue.Length > 4) { // xTheData = "0,0,0,0,"; // xTheData += BitConverter.GetBytes(0x80000002).Aggregate("", (r, b) => r + b + ","); // xTheData += "1,0,0,0,"; // } // xTheData += BitConverter.GetBytes(xCurrentField.InitialValue.Length).Aggregate("", (r, b) => r + b + ","); // xTheData += xCurrentField.InitialValue.Aggregate("", (r, b) => r + b + ","); // xTheData = xTheData.TrimEnd(','); // if (xTheData.Length == 0) { // throw new Exception("Field '" + xCurrentField.ToString() + "' doesn't have a valid size!"); // } // mAssembler.DataMembers.Add(new KeyValuePair(mAssembler.CurrentGroup, new DataMember(xFieldName, "db", xTheData))); //} else { 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; } } 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); 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; List xSymbols = null; 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; } } xSymbols = new List(); } 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); } DebugSymbolsAssemblyTypeMethodInstruction xInstructionInfo = null; int xCurrentStack = 0; 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 aShouldIncludeDebugHeader = false; #region determine if a new DebugHeader should be emitted if (mDebugMode == DebugModeEnum.IL) { aShouldIncludeDebugHeader = true; } else { if (mDebugMode == DebugModeEnum.Source) { if (xPreviousOffset == -1) { aShouldIncludeDebugHeader = 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]) { aShouldIncludeDebugHeader = true; } } } } } #endregion if (aShouldIncludeDebugHeader) { mMap.EmitOpDebugHeader(mAssembler, 0, xLabel, mDebugComport); mDebugSymbols.Add(new DebugSymbol() { AssemblyFileName = xCurrentMethod.DeclaringType.Assembly.Location, InstructionOffset = xCurrentOffset, LabelName = xLabel, MethodMetaDataToken = xCurrentMethod.MetadataToken }); } if (mMLDebugSymbols != 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; mMLDebugSymbols.Add(xMLSymbol); xSymbols.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 (xSymbols != null) { mMethods[xCurrentMethod].Instructions = xSymbols.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 E) { OnDebugLog(LogSeverityEnum.Error, xCurrentMethod.GetFullName()); throw; } } } 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) { 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) { 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) { 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, xParamDef.ParameterType); xCurOffset += xArgSize; } xArgSize = 4; // this xArgs[0] = new MethodInformation.Argument(xArgSize, xCurOffset, MethodInformation.Argument.KindEnum.In, !aCurrentMethodForArguments.DeclaringType.IsValueType, 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, 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); } return xMethodInfo; } public static Dictionary GetTypeFieldInfo(MethodBase aCurrentMethod, out int aObjectStorageSize) { Type xCurrentInspectedType = aCurrentMethod.DeclaringType; return GetTypeFieldInfo(xCurrentInspectedType, out aObjectStorageSize); } private static void GetTypeFieldInfoImpl(Dictionary 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)) { 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 (aTypeFields.ContainsKey(xFieldId)) { continue; } int xOffset = aObjectStorageSize; FieldOffsetAttribute xOffsetAttrib = xField.GetCustomAttributes(typeof(FieldOffsetAttribute), true).FirstOrDefault() as FieldOffsetAttribute; if (xOffsetAttrib != null) { xOffset = xOffsetAttrib.Value; } else { aObjectStorageSize += xFieldSize; } aTypeFields.Add(xField.GetFullName(), new TypeInformation.Field(xFieldSize, xFieldType.IsClass && !xFieldType.IsValueType, xFieldType, (xPlugFieldAttr != null && xPlugFieldAttr.IsExternalValue))); } 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.Add(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) { Dictionary xTypeFields = new Dictionary(); aObjectStorageSize = 0; if (aType == typeof(string)) { System.Console.Write(""); } GetTypeFieldInfoImpl(xTypeFields, aType, ref aObjectStorageSize); if (aType.IsExplicitLayout) { var xStructLayout = aType.StructLayoutAttribute; if (xStructLayout.Size == 0) { aObjectStorageSize = (from item in xTypeFields.Values let xSize = item.Offset + item.Size orderby xSize select xSize).FirstOrDefault(); } else { aObjectStorageSize = xStructLayout.Size; } } int xOffset = 0; Dictionary xResult = new Dictionary(); foreach (var item in xTypeFields.Reverse()) { var xItem = item.Value; 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.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!"); } 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; } } }