#define VERBOSE_DEBUG using System; using System.Collections.Generic; using System.Diagnostics.SymbolStore; using System.Linq; using System.Reflection; using System.Runtime.InteropServices; using System.Text; using Indy.IL2CPU.Assembler; using Indy.IL2CPU.Assembler.X86; using Indy.IL2CPU.IL; using Indy.IL2CPU.Plugs; using Microsoft.Samples.Debugging.CorSymbolStore; namespace Indy.IL2CPU.Compiler { public partial class CompilerHelper { public CompilerHelper() { SkipList=new List(); } public List SkipList { get; set; } /// /// first parameter tells which assembly this assembler is for. second param tells whether it's the entrypoint assembly /// public event Func GetAssembler; public event Action SaveAssembler; public event Func GetOpCodeMap; public event Action DebugLog; private Dictionary mAssemblyInfos = new Dictionary(); // does based on instances is unique? private List mAllMethods = new List(); private int mNextMethodToScan = 0; private List mAllStaticFields= new List(); public List Plugs = new List(); public DebugMode DebugMode; public TraceAssemblies TraceAssemblies; private Assembly mEntryPointAssembly; private OpCodeMap mCurrentMap; public void CompileExe(Assembly aAssembly) { mEntryPointAssembly = aAssembly; Initialize(); // add standard methods (mainly the entry point) AddStandardMethods(); ScanMethods(); foreach(var xAsmInfo in mAssemblyInfos.Values) { CompileAssembly(xAsmInfo); } } private void CompileAssembly(AssemblyCompilationInfo info) { using(var xCurrentAssembler = GetAssembler(info.Assembly, info.Assembly == mEntryPointAssembly)) { mCurrentAssemblyCompilationInfo = info; try { // emit the methods. foreach (var xMethod in info.Methods.Values) { CompileMethod(xMethod, xCurrentAssembler); } // emit the fields foreach (var xField in info.StaticFields.Values) { CompileStaticField(xField, xCurrentAssembler); } // emit the method and type id data members foreach (var xIdMember in info.IDLabels) { xCurrentAssembler.DataMembers.Add(new DataMember(xIdMember, new int[1])); } // emit externals foreach (var xExternal in info.Externals) { new ExternalLabel(xExternal); } // todo: implement string init method, vmt init methods, cctor calling method, etc SaveAssembler(info.Assembly, xCurrentAssembler); }finally { mCurrentAssemblyCompilationInfo = null; } } } private void CompileStaticField(FieldInfo aField, Assembler.Assembler aAssembler) { //ProgressChanged.Invoke(String.Format("Processing static field: {0}", xCurrentField.GetFullName())); string xFieldName = aField.GetFullName(); xFieldName = DataMember.GetStaticFieldName(aField); if (aAssembler.DataMembers.Count(x => x.Name == xFieldName) == 0) { var xItemList = (from item in aField.GetCustomAttributes(false) where item.GetType().FullName == "ManifestResourceStreamAttribute" select item).ToList(); object xItem = null; if (xItemList.Count > 0) xItem = xItemList[0]; string xManifestResourceName = null; if (xItem != null) { var xItemType = xItem.GetType(); xManifestResourceName = (string)xItemType.GetField("ResourceName").GetValue(xItem); } if (xManifestResourceName != null) { //RegisterType(xCurrentField.FieldType); //string xFileName = Path.Combine(mOutputDir, // (xCurrentField.DeclaringType.Assembly.FullName + "__" + xManifestResourceName).Replace(",", // "_") + ".res"); //using (var xStream = xCurrentField.DeclaringType.Assembly.GetManifestResourceStream(xManifestResourceName)) { // if (xStream == null) { // throw new Exception("Resource '" + xManifestResourceName + "' not found!"); // } // using (var xTarget = File.Create(xFileName)) { // // todo: abstract this array code out. // xTarget.Write(BitConverter.GetBytes(Engine.RegisterType(Engine.GetType("mscorlib", // "System.Array"))), // 0, // 4); // xTarget.Write(BitConverter.GetBytes((uint)InstanceTypeEnum.StaticEmbeddedArray), // 0, // 4); // xTarget.Write(BitConverter.GetBytes((int)xStream.Length), 0, 4); // xTarget.Write(BitConverter.GetBytes((int)1), 0, 4); // var xBuff = new byte[128]; // while (xStream.Position < xStream.Length) { // int xBytesRead = xStream.Read(xBuff, 0, 128); // xTarget.Write(xBuff, 0, xBytesRead); // } // } //} //mAssembler.DataMembers.Add(new DataMember("___" + xFieldName + "___Contents", // "incbin", // "\"" + xFileName + "\"")); //mAssembler.DataMembers.Add(new DataMember(xFieldName, // "dd", // "___" + xFieldName + "___Contents")); throw new NotImplementedException(); } else { uint xTheSize; //string theType = "db"; Type xFieldTypeDef = aField.FieldType; if (!xFieldTypeDef.IsClass || xFieldTypeDef.IsValueType) { xTheSize = SizeOfType(aField.FieldType); } else { xTheSize = 4; } var xData = new byte[xTheSize]; try { object xValue = aField.GetValue(null); if (xValue != null) { try { xData = new byte[xTheSize]; if (xValue.GetType().IsValueType) { for (int x = 0; x < xTheSize; x++) { xData[x] = Marshal.ReadByte(xValue, x); } } } catch { } } } catch { } aAssembler.DataMembers.Add(new DataMember(xFieldName, xData)); } } } private void CompileMethod(MethodBase xCurrentMethod, Assembler.Assembler assembler) { try { if (xCurrentMethod.IsAbstract) { return; } string xMethodName = Label.GetFullName(xCurrentMethod); TypeInformation xTypeInfo = null; if (!xCurrentMethod.IsStatic) { xTypeInfo = GetTypeInfo(xCurrentMethod.DeclaringType); } var xMethodScanInfo = new SortedList(StringComparer.InvariantCultureIgnoreCase); MethodInformation xMethodInfo = GetMethodInfo(xCurrentMethod, xCurrentMethod , xMethodName, xTypeInfo, DebugMode != DebugMode.None, xMethodScanInfo); Op xOp = GetOpFromType(mCurrentMap.MethodHeaderOp, null, xMethodInfo); xOp.Assembler = assembler; #if VERBOSE_DEBUG string comment = "(No Type Info available)"; if (xMethodInfo.TypeInfo != null) { comment = "Type Info:\r\n \r\n" + xMethodInfo.TypeInfo; } foreach (string s in comment.Trim().Split(new string[] { "\r\n" } , StringSplitOptions.RemoveEmptyEntries)) { new Comment(s); } comment = xMethodInfo.ToString(); foreach (string s in comment.Trim().Split(new string[] { "\r\n" } , StringSplitOptions.RemoveEmptyEntries)) { new Comment(s); } #endif xOp.Assemble(); MethodBase xCustomImplementation = GetCustomMethodImplementation(xMethodName); bool xIsCustomImplementation = (xCustomImplementation != null); // what to do if a method doesn't have a body? bool xContentProduced = false; if (xIsCustomImplementation) { // this is for the support for having extra fields on types, and being able to use // them in custom implementation methods CustomMethodImplementationProxyOp xProxyOp = (CustomMethodImplementationProxyOp) GetOpFromType( mCurrentMap.CustomMethodImplementationProxyOp, null, xMethodInfo); xProxyOp.Assembler = assembler; xProxyOp.ProxiedMethod = xCustomImplementation; xProxyOp.Assemble(); xContentProduced = true; } if (!xContentProduced) { Type xOpType = mCurrentMap.GetOpForCustomMethodImplementation(xMethodName); if (xOpType != null) { Op xMethodOp = GetOpFromType(xOpType, null, xMethodInfo); if (xMethodOp != null) { xMethodOp.Assembler = assembler; xMethodOp.Assemble(); xContentProduced = true; } } } if (!xContentProduced) { if (mCurrentMap.HasCustomAssembleImplementation(xMethodInfo)) { mCurrentMap.DoCustomAssembleImplementation(assembler, xMethodInfo); // No plugs, we need to compile the IL from the method } else { MethodBody xBody = xCurrentMethod.GetMethodBody(); // todo: add better detection of implementation state if (xBody != null) { assembler.StackContents.Clear(); var xReader = new ILReader(xCurrentMethod); #region let instructions prepare themselves while(xReader.Read()) { mCurrentMap.ScanILCode(xReader, xMethodInfo, xMethodScanInfo); } #endregion xReader.Restart(); var xInstructionInfos = new List(); // Section currently is dead code. Working on matching it up // with contents from inside the read int[] xCodeOffsets = null; if (DebugMode == DebugMode.Source) { var xSymbolReader = GetSymbolReaderForAssembly(xCurrentMethod.DeclaringType.Assembly); if (xSymbolReader != null) { var xSmbMethod = xSymbolReader.GetMethod(new SymbolToken(xCurrentMethod.MetadataToken)); // This gets the Sequence Points. // Sequence Points are spots that identify what the compiler/debugger says is a spot // that a breakpoint can occur one. Essentially, an atomic source line in C# if (xSmbMethod != null) { xCodeOffsets = new int[xSmbMethod.SequencePointCount]; var xCodeDocuments = new ISymbolDocument[xSmbMethod.SequencePointCount]; var xCodeLines = new int[xSmbMethod.SequencePointCount]; var xCodeColumns = new int[xSmbMethod.SequencePointCount]; var xCodeEndLines = new int[xSmbMethod.SequencePointCount]; var xCodeEndColumns = new int[xSmbMethod.SequencePointCount]; xSmbMethod.GetSequencePoints(xCodeOffsets, xCodeDocuments , xCodeLines, xCodeColumns, xCodeEndLines, xCodeEndColumns); } } } // Scan each IL op in the method while (xReader.Read()) { ExceptionHandlingClause xCurrentHandler = null; #region Exception handling support code // todo: add support for nested handlers using a stack or so.. foreach (ExceptionHandlingClause xHandler in xBody.ExceptionHandlingClauses) { if (xHandler.TryOffset > 0) { if (xHandler.TryOffset <= xReader.NextPosition && (xHandler.TryLength + xHandler.TryOffset) > xReader.NextPosition) { if (xCurrentHandler == null) { xCurrentHandler = xHandler; continue; } else if (xHandler.TryOffset > xCurrentHandler.TryOffset && (xHandler.TryLength + xHandler.TryOffset) < (xCurrentHandler.TryLength + xCurrentHandler.TryOffset)) { // only replace if the current found handler is narrower xCurrentHandler = xHandler; continue; } } } if (xHandler.HandlerOffset > 0) { if (xHandler.HandlerOffset <= xReader.NextPosition && (xHandler.HandlerOffset + xHandler.HandlerLength) > xReader.NextPosition) { if (xCurrentHandler == null) { xCurrentHandler = xHandler; continue; } else if (xHandler.HandlerOffset > xCurrentHandler.HandlerOffset && (xHandler.HandlerOffset + xHandler.HandlerLength) < (xCurrentHandler.HandlerOffset + xCurrentHandler.HandlerLength)) { // only replace if the current found handler is narrower xCurrentHandler = xHandler; continue; } } } if ((xHandler.Flags & ExceptionHandlingClauseOptions.Filter) > 0) { if (xHandler.FilterOffset > 0) { if (xHandler.FilterOffset <= xReader.NextPosition) { if (xCurrentHandler == null) { xCurrentHandler = xHandler; continue; } else if (xHandler.FilterOffset > xCurrentHandler.FilterOffset) { // only replace if the current found handler is narrower xCurrentHandler = xHandler; continue; } } } } } #endregion xMethodInfo.CurrentHandler = xCurrentHandler; xOp = GetOpFromType(mCurrentMap.GetOpForOpCode(xReader.OpCode), xReader, xMethodInfo); xOp.Assembler = assembler; new Comment("StackItems = " + assembler.StackContents.Count); foreach (var xStackContent in assembler.StackContents) { new Comment(" " + xStackContent.Size); } // Create label for current point string xLabel = Op.GetInstructionLabel(xReader); if (xLabel.StartsWith(".")) { xLabel = DataMember.FilterStringForIncorrectChars( Label.LastFullLabel + "__DOT__" + xLabel.Substring(1)); } // Possibly emit Tracer call EmitTracer(xOp, xCurrentMethod.DeclaringType.Namespace, (int) xReader.Position, xCodeOffsets, xLabel, assembler); if (mSymbols != null) { var xMLSymbol = new MLDebugSymbol(); xMLSymbol.LabelName = xLabel; int xStackSize = (from item in assembler.StackContents let xSize = (item.Size%4 == 0) ? item.Size : (item.Size + (4 - (item.Size%4))) select xSize).Sum(); xMLSymbol.StackDifference = xMethodInfo.LocalsSize + xStackSize; try { xMLSymbol.AssemblyFile = xCurrentMethod.DeclaringType.Assembly.Location; } catch (NotSupportedException) { xMLSymbol.AssemblyFile = "DYNAMIC: " + xCurrentMethod.DeclaringType.Assembly.FullName; } xMLSymbol.MethodToken = xCurrentMethod.MetadataToken; xMLSymbol.TypeToken = xCurrentMethod.DeclaringType.MetadataToken; xMLSymbol.ILOffset = (int) xReader.Position; mSymbols.Add(xMLSymbol); } xOp.Assemble(); //if (xInstructionInfo != null) { // int xNewStack = (from item in mAssembler.StackContents // let xSize = (item.Size % 4 == 0) ? item.Size : (item.Size + (4 - (item.Size % 4))) // select xSize).Sum(); // xInstructionInfo.StackResult = xNewStack - xCurrentStack; // xInstructionInfo.StackResultSpecified = true; // xInstructionInfos.Add(xInstructionInfo); //} } if (mSymbols != null) { MLDebugSymbol[] xSymbols; xSymbols = mSymbols.ToArray(); } } else { if ((xCurrentMethod.Attributes & MethodAttributes.PinvokeImpl) != 0) { LogMessage(LogSeverityEnum.Error, "Method '{0}' not generated!", xCurrentMethod.GetFullName()); new Comment("Method not being generated yet, as it's handled by a PInvoke"); } else { LogMessage(LogSeverityEnum.Error, "Method '{0}' not generated!", xCurrentMethod.GetFullName()); new Comment("Method not being generated yet, as it's handled by an iCall"); } } } } xOp = GetOpFromType(mCurrentMap.MethodFooterOp, null, xMethodInfo); xOp.Assembler = assembler; xOp.Assemble(); assembler.StackContents.Clear(); } catch (Exception e) { LogMessage(LogSeverityEnum.Error, xCurrentMethod.GetFullName()); LogMessage(LogSeverityEnum.Warning, e.ToString()); throw; } } private void Initialize() { mCurrentMap = GetOpCodeMap(); InitializePlugs(Plugs); mCurrentMap.SetServiceProvider(this); mCurrentMap.Initialize(new[] { mEntryPointAssembly }); } private void CheckAssemblyForPlugAssemblies(Assembly aAssembly) { //If in the GAC, then ignore assembly if (aAssembly.GlobalAssemblyCache) { return; } // todo: implement this again // todo: try to get rid of the try..catch. find a way to detect dynamic assemblies. try { //Search for related .config file //string configFile = String.Intern(aAssembly.Location + ".cosmos-config"); //if (System.IO.File.Exists(configFile)) //{ // //Load and parse all PlugAssemblies referred to in the .config file // foreach (Assembly xAssembly in GetAssembliesFromConfigFile(configFile)) // { // LoadPlugAssembly(xAssembly); // } //} } catch { } } private void InitializePlugs(IEnumerable aPlugs) { if (mPlugMethods != null) { throw new Exception("PlugMethods list already initialized!"); } if (mPlugFields != null) { throw new Exception("PlugFields list already initialized!"); } mPlugMethods = new SortedList(); mPlugFields = new SortedList>(new TypeComparer()); //AppDomain.CurrentDomain.AssemblyLoad += CurrentDomain_AssemblyLoad; //AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve); foreach (var xAsm in AppDomain.CurrentDomain.GetAssemblies()) { CheckAssemblyForPlugAssemblies(xAsm); } List xPlugs = new List(); var xComparer = new AssemblyEqualityComparer(); foreach (string s in aPlugs) { Assembly a = Assembly.LoadFrom(s); a.GetTypes(); if (!xPlugs.Contains(a, xComparer)) { xPlugs.Add(a); } } foreach (var item in GetPlugAssemblies()) { if (!xPlugs.Contains(item, xComparer)) { xPlugs.Add(item); } } foreach (Assembly xAssemblyDef in xPlugs) { LoadPlugAssembly(xAssemblyDef); } } private IList GetPlugAssemblies() { var xResult = mCurrentMap.GetPlugAssemblies(); xResult.Add(typeof(CompilerHelper).Assembly); return xResult; } public readonly bool RunningOnMono; private void LoadPlugAssembly(Assembly aAssemblyDef) { foreach (var xType in (from item in aAssemblyDef.GetTypes() let xCustomAttribs = item.GetCustomAttributes(typeof(PlugAttribute), false) where xCustomAttribs != null && xCustomAttribs.Length > 0 select new KeyValuePair(item, (PlugAttribute)xCustomAttribs[0]))) { PlugAttribute xPlugAttrib = xType.Value; if (xPlugAttrib.IsMonoOnly && !RunningOnMono) { continue; } if (xPlugAttrib.IsMicrosoftdotNETOnly && RunningOnMono) { continue; } Type xTypeRef = xPlugAttrib.Target; if (xTypeRef == null) { xTypeRef = Type.GetType(xPlugAttrib.TargetName, true); } PlugFieldAttribute[] xTypePlugFields = xType.Key.GetCustomAttributes(typeof(PlugFieldAttribute), false) as PlugFieldAttribute[]; if (xTypePlugFields != null && xTypePlugFields.Length > 0) { Dictionary xPlugFields; if (mPlugFields.ContainsKey(xTypeRef)) { xPlugFields = mPlugFields[xTypeRef]; } else { mPlugFields.Add(xTypeRef, xPlugFields = new Dictionary()); } foreach (var xPlugField in xTypePlugFields) { if (xPlugAttrib.IsMonoOnly && !RunningOnMono) { continue; } if (xPlugAttrib.IsMicrosoftdotNETOnly && RunningOnMono) { continue; } if (!xPlugFields.ContainsKey(xPlugField.FieldId)) { xPlugFields.Add(xPlugField.FieldId, xPlugField); } } } foreach (MethodBase xMethod in xType.Key.GetMethods(BindingFlags.Public | BindingFlags.Static)) { PlugMethodAttribute xPlugMethodAttrib = xMethod.GetCustomAttributes(typeof(PlugMethodAttribute), true).Cast().FirstOrDefault(); string xSignature = String.Empty; if (xPlugMethodAttrib != null) { xSignature = xPlugMethodAttrib.Signature; if (!xPlugMethodAttrib.Enabled) { continue; } if (xPlugAttrib.IsMonoOnly && !RunningOnMono) { continue; } if (xPlugAttrib.IsMicrosoftdotNETOnly && RunningOnMono) { continue; } if (!String.IsNullOrEmpty(xSignature)) { if (!mPlugMethods.ContainsKey(xSignature)) { mPlugMethods.Add(xSignature, xMethod); } continue; } } foreach (MethodBase xOrigMethodDef in xTypeRef.GetMethods(BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance | BindingFlags.NonPublic)) { string xStrippedSignature = GetStrippedMethodBaseFullName(xMethod, xOrigMethodDef); string xOrigStrippedSignature = GetStrippedMethodBaseFullName(xOrigMethodDef, null); if (xOrigStrippedSignature == xStrippedSignature) { if (!mPlugMethods.ContainsKey(MethodInfoLabelGenerator.GenerateLabelName(xOrigMethodDef))) { mPlugMethods.Add(MethodInfoLabelGenerator.GenerateLabelName(xOrigMethodDef), xMethod); } } } foreach (MethodBase xOrigMethodDef in xTypeRef.GetConstructors(BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance | BindingFlags.NonPublic)) { string xStrippedSignature = GetStrippedMethodBaseFullName(xMethod, xOrigMethodDef); string xOrigStrippedSignature = GetStrippedMethodBaseFullName(xOrigMethodDef, null); if (xOrigStrippedSignature == xStrippedSignature) { if (mPlugMethods.ContainsKey(MethodInfoLabelGenerator.GenerateLabelName(xOrigMethodDef))) { System.Diagnostics.Debugger.Break(); } mPlugMethods.Add(MethodInfoLabelGenerator.GenerateLabelName(xOrigMethodDef), xMethod); } } } } } private void ScanMethods() { int xOldCount = 0; do { xOldCount = mAllMethods.Count; ScanMethods_OnePass(); } while (xOldCount != mAllMethods.Count); } private IDictionary mPlugMethods; private IDictionary> mPlugFields; private AssemblyCompilationInfo mCurrentAssemblyCompilationInfo = null; /// /// contains the code for scanning for new methods, but just one pass. /// private void ScanMethods_OnePass() { var xEmptyDict = new Dictionary(); for (int i = mNextMethodToScan; i < mAllMethods.Count; i++) { var xCurrentMethod = mAllMethods[i]; if (xCurrentMethod.IsAbstract) { continue; } if(!mAssemblyInfos.TryGetValue(xCurrentMethod.DeclaringType.Assembly, out mCurrentAssemblyCompilationInfo)) { mCurrentAssemblyCompilationInfo = new AssemblyCompilationInfo {Assembly = xCurrentMethod.DeclaringType.Assembly}; mAssemblyInfos.Add(mCurrentAssemblyCompilationInfo.Assembly, mCurrentAssemblyCompilationInfo); } try { string xMethodName = Label.GetFullName(xCurrentMethod); TypeInformation xTypeInfo = null; if (!xCurrentMethod.IsStatic) { xTypeInfo = GetTypeInfo(xCurrentMethod.DeclaringType); } MethodInformation xMethodInfo; // using (mMethodsLocker.AcquireReaderLock()) { xEmptyDict.Clear(); xMethodInfo = GetMethodInfo(xCurrentMethod, xCurrentMethod, xMethodName, xTypeInfo, false, // debug mode xEmptyDict); } MethodBase xCustomImplementation = GetCustomMethodImplementation(xMethodName); if (xCustomImplementation != null) { try { AddMethod(xCustomImplementation); } catch (Exception e) { throw new Exception("Method " + xCurrentMethod.GetFullName() + " has called " + e.Message + "! Probably it needs to be plugged"); } // using (mMethodsLocker.AcquireReaderLock()) //{ // mMethods[xCurrentMethod].Implementation = xCustomImplementation; //} continue; } Type xOpType = mCurrentMap.GetOpForCustomMethodImplementation(xMethodName); if (xOpType != null) { Op xMethodOp = GetOpFromType(xOpType, null, xMethodInfo); if (xMethodOp != null) { continue; } } if (mCurrentMap.HasCustomAssembleImplementation(xMethodInfo)) { mCurrentMap.ScanCustomAssembleImplementation(xMethodInfo); continue; } //xCurrentMethod.GetMethodImplementationFlags() == MethodImplAttributes. MethodBody xBody = xCurrentMethod.GetMethodBody(); // todo: add better detection of implementation state if (xBody != null) { ILReader xReader = new ILReader(xCurrentMethod); var xInstructionInfos = new List(); while (xReader.Read()) { SortedList xInfo = new SortedList(); // using (mMethodsLocker.AcquireReaderLock()) //{ // xInfo = mMethods[xCurrentMethod].Info; //} mCurrentMap.ScanILCode(xReader, xMethodInfo, xInfo); switch (xReader.OpCode) { case OpCodeEnum.Call: case OpCodeEnum.Callvirt: case OpCodeEnum.Newobj: case OpCodeEnum.Ldftn: AddMethod(xReader.OperandValueMethod); break; case OpCodeEnum.Initobj: case OpCodeEnum.Ldelema: //Add(xReader.OperandValueType); break; case OpCodeEnum.Stsfld: case OpCodeEnum.Ldsfld: case OpCodeEnum.Ldsflda: AddStaticField(xReader.OperandValueField); break; case OpCodeEnum.Ldtoken: if (xReader.OperandValueType != null) { //RegisterType(xReader.OperandValueType); break; } if (xReader.OperandValueField != null) { AddStaticField(xReader.OperandValueField); break; } break; } } } } finally { mCurrentAssemblyCompilationInfo = null; } } mNextMethodToScan = mAllMethods.Count; } private Op GetOpFromType(Type aType, ILReader aReader, MethodInformation aMethodInfo) { var xResult = (Op)Activator.CreateInstance(aType, aReader, aMethodInfo); xResult.SetServiceProvider(this); return xResult; } private MethodBase GetCustomMethodImplementation(string aMethodName) { if (mPlugMethods.ContainsKey(aMethodName)) { return mPlugMethods[aMethodName]; } return null; } private void AddMethod(MethodBase aMethod) { if ((from item in mAllMethods where item.GetFullName() == aMethod.GetFullName() select item).Any()) { return; } mAllMethods.Add(aMethod); AssemblyCompilationInfo xAsmCompileInfo; if (!mAssemblyInfos.TryGetValue(aMethod.DeclaringType.Assembly, out xAsmCompileInfo)) { mAssemblyInfos.Add(aMethod.DeclaringType.Assembly, xAsmCompileInfo=new AssemblyCompilationInfo {Assembly = aMethod.DeclaringType.Assembly}); } xAsmCompileInfo.AddMethod(aMethod); } private void AddStaticField(FieldInfo aField) { if (mAllStaticFields.Contains(aField)) { return; } mAllStaticFields.Add(aField); AssemblyCompilationInfo xAsmCompileInfo; if (!mAssemblyInfos.TryGetValue(aField.DeclaringType.Assembly, out xAsmCompileInfo)) { mAssemblyInfos.Add(aField.DeclaringType.Assembly, xAsmCompileInfo = new AssemblyCompilationInfo { Assembly = aField.DeclaringType.Assembly }); } xAsmCompileInfo.AddStaticField(aField); } private void AddStandardMethods() { AddMethod(mEntryPointAssembly.EntryPoint.DeclaringType.GetMethod("Init", new Type[0])); AddMethod(RuntimeEngineRefs.InitializeApplicationRef); AddMethod(RuntimeEngineRefs.FinalizeApplicationRef); AddMethod(typeof(Assembler.Assembler).GetMethod("PrintException")); AddMethod(VTablesImplRefs.LoadTypeTableRef); AddMethod(VTablesImplRefs.SetMethodInfoRef); AddMethod(VTablesImplRefs.IsInstanceRef); AddMethod(VTablesImplRefs.SetTypeInfoRef); AddMethod(VTablesImplRefs.GetMethodAddressForTypeRef); AddMethod(GCImplementationRefs.IncRefCountRef); AddMethod(GCImplementationRefs.DecRefCountRef); AddMethod(GCImplementationRefs.AllocNewObjectRef); } private static string GetStrippedMethodBaseFullName(MethodBase aMethod, MethodBase aRefMethod) { StringBuilder xBuilder = new StringBuilder(256); string[] xParts = aMethod.ToString().Split(' '); string[] xParts2 = xParts.Skip(1).ToArray(); MethodInfo xMethodInfo = aMethod as MethodInfo; if (xMethodInfo != null) { xBuilder.Append(xMethodInfo.ReturnType.FullName); } else { if (aMethod is ConstructorInfo) { xBuilder.Append(typeof(void).FullName); } else { xBuilder.Append(xParts[0]); } } xBuilder.Append(" "); xBuilder.Append("."); xBuilder.Append(aMethod.Name); xBuilder.Append("("); ParameterInfo[] xParams = aMethod.GetParameters(); bool xParamAdded = false; for (int i = 0; i < xParams.Length; i++) { if (i == 0 && (aRefMethod != null && !aRefMethod.IsStatic)) { continue; } if (xParams[i].IsDefined(typeof(FieldAccessAttribute), true)) { continue; } if (xParamAdded) { xBuilder.Append(", "); } xBuilder.Append(xParams[i].ParameterType.FullName); xParamAdded = true; } xBuilder.Append(")"); return String.Intern(xBuilder.ToString()); } private ISymbolReader GetSymbolReaderForAssembly(Assembly aAssembly) { try { return SymbolAccess.GetReaderForFile(aAssembly.Location); } catch (NotSupportedException) { return null; } } protected void EmitTracer(Op aOp, string aNamespace, int aPos, int[] aCodeOffsets, string aLabel, Assembler.Assembler aAssembler) { // NOTE - These if statemens can be optimized down - but clarity is // more importnat the optimizations would not offer much benefit // Determine if a new DebugStub should be emitted //bool xEmit = false; // Skip NOOP's so we dont have breakpoints on them //TODO: Each IL op should exist in IL, and descendants in IL.X86. // Because of this we have this hack if (aOp.ToString() == "Indy.IL2CPU.IL.X86.Nop") { return; } else if (DebugMode == DebugMode.None) { return; } else if (DebugMode == DebugMode.Source) { // If the current position equals one of the offsets, then we have // reached a new atomic C# statement if (aCodeOffsets != null) { if (aCodeOffsets.Contains(aPos) == false) { return; } } } // Check options for Debug Level // Set based on TracedAssemblies if (TraceAssemblies == TraceAssemblies.Cosmos || TraceAssemblies == TraceAssemblies.User) { if (aNamespace.StartsWith("System.", StringComparison.InvariantCultureIgnoreCase)) { return; } else if (aNamespace.ToLower() == "system") { return; } else if (aNamespace.StartsWith("Microsoft.", StringComparison.InvariantCultureIgnoreCase)) { return; } } if (TraceAssemblies == TraceAssemblies.User) { //TODO: Maybe an attribute that could be used to turn tracing on and off //TODO: This doesnt match Cosmos.Kernel exact vs Cosmos.Kernel., so a user // could do Cosmos.KernelMine and it will fail. Need to fix this if (aNamespace.StartsWith("Cosmos.Kernel", StringComparison.InvariantCultureIgnoreCase)) { return; } else if (aNamespace.StartsWith("Cosmos.Sys", StringComparison.InvariantCultureIgnoreCase)) { return; } else if (aNamespace.StartsWith("Cosmos.Hardware", StringComparison.InvariantCultureIgnoreCase)) { return; } else if (aNamespace.StartsWith("Indy.IL2CPU", StringComparison.InvariantCultureIgnoreCase)) { return; } } // If we made it this far, emit the Tracer mCurrentMap.EmitOpDebugHeader(aAssembler, 0, aLabel); } private List mSymbols = new List(); } }