Cosmos/source2/IL2CPU/Cosmos.IL2CPU/ILScanner.cs
blah38621_cp 92dcac4a51 Made a few improvements to the speed of the ILScanner, including caching the resolved plugs.
Added the possibility for an optimization step in the IL2CPU MSBuild task. Currently commented out, but should work fine with a few modifications to the optimizer.
Moved classes that are dependent on Cosmos from the Orvid.Graphics, into the Orvid.Graphics.Cosmos assembly. 
Re-factored the font mechanism, added partially working .fnt Font support. 
Added a Rectangle class, and a Vec2d class, which is the same as Vec2, except with doubles for the X and Y values.
Made a small aesthetic improvement to the output of the File2ByteArray Converter.
2011-09-03 21:05:46 +00:00

1556 lines
72 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using Cosmos.IL2CPU;
using Cosmos.IL2CPU.Plugs;
using Cosmos.IL2CPU.IL;
using SR = System.Reflection;
using Cosmos.Compiler.Assembler;
using System.Reflection.Emit;
namespace Cosmos.IL2CPU
{
// This is necessary because HashSet and Dictionary
// have troubles when different types of objects are stored
// in them. I dont remember the exact problem, but something
// with how it compares objects. ie when HashSet<object> is used, this is necessary.
/*public class HashcodeComparer<T> : IEqualityComparer<T> {
public bool Equals(T x, T y) {
return internalEqualsSinceNET40(x, y);// x.GetHashCode() == y.GetHashCode();
}
public bool internalEqualsSinceNET40(T left, T right)
{
var methodDeclaringType = left.GetType().GetMethod("get_DeclaringType");
var leftDeclaringType = methodDeclaringType.Invoke(left, null);
var method = right.GetType().GetMethod("get_DeclaringType");
var rightDeclaringType = method.Invoke(right, null);
if (left.ToString() == right.ToString()
&& leftDeclaringType == rightDeclaringType)
{
return true;
}
return false;
}
public int GetHashCode(T obj) {
return obj.GetHashCode();
}
}*/
public class ILScanner : IDisposable
{
protected ILReader mReader;
protected AppAssembler mAsmblr;
protected OurHashSet<object> mItems = new OurHashSet<object>();
protected List<object> mItemsList = new List<object>();
// Contains items to be scanned, both types and methods
protected Queue<object> mQueue = new Queue<object>();
// Virtual methods are nasty and constantly need to be rescanned for
// overriding methods in new types, so we keep track of them separately.
// They are also in the main mItems and mQueue.
protected HashSet<MethodBase> mVirtuals = new HashSet<MethodBase>();
protected IDictionary<MethodBase, uint> mMethodUIDs = new Dictionary<MethodBase, uint>();
protected IDictionary<Type, uint> mTypeUIDs = new Dictionary<Type, uint>();
// Contains a list of plug implementor classes
// Key = Target Class
// Value = List of Implementors. There may be more than one
protected Dictionary<Type, List<Type>> mPlugImpls = new Dictionary<Type, List<Type>>();
// List of inheritable plugs. Plugs that start at an ancestor and plug all
// descendants. For example, delegates
protected Dictionary<Type, List<Type>> mPlugImplsInhrt = new Dictionary<Type, List<Type>>();
// list of field plugs
protected IDictionary<Type, IDictionary<string, PlugFieldAttribute>> mPlugFields = new Dictionary<Type, IDictionary<string, PlugFieldAttribute>>();
// Logging
// Only use for debugging and profiling.
protected bool mLogEnabled = false;
protected string mMapPathname;
protected TextWriter mLogWriter;
protected struct LogItem
{
public string SrcType;
public object Item;
}
protected Dictionary<object, List<LogItem>> mLogMap;
//TODO: Look for Field plugs
// System.ThrowHelper exists in MS .NET twice...
// Its an internal class that exists in both mscorlib and system assemblies.
// They are separate types though, so normally the scanner scans both and
// then we get conflicting labels. MS included it twice to make exception
// throwing code smaller. They are internal though, so we cannot
// reference them directly and only via finding them as they come along.
// We find it here, not via QueueType so we only check it here. Later
// we might have to checkin QueueType also.
// For now we accept both types, and just emit code for only one. This works
// with the current Nasm assembler as we resolve by name in the assembler.
// However with other assemblers this approach may not work.
// If AssemblerNASM adds assembly name to the label, this will allow
// both to exist as they do in BCL.
// So in the future we might be able to remove this hack, or change
// how it works.
// private Type mThrowHelper;
public ILScanner(AppAssembler aAsmblr)
{
mAsmblr = aAsmblr;
mReader = new ILReader();
//mThrowHelper = typeof(object).Assembly.GetType("System.ThrowHelper");
}
public void EnableLogging(string aPathname)
{
mLogMap = new Dictionary<object, List<LogItem>>();
mMapPathname = aPathname;
mLogEnabled = true;
}
protected void Queue(object aItem, object aSrc, string aSrcType)
{
var xMemInfo = aItem as MemberInfo;
//TODO: fix this, as each label/symbol should also contain an assembly specifier.
if (xMemInfo != null
&& xMemInfo.DeclaringType != null
&& xMemInfo.DeclaringType.FullName == "System.ThrowHelper"
&& xMemInfo.DeclaringType.Assembly.GetName().Name != "mscorlib")
{
return;
}
if (!mItems.Contains(aItem))
{
if (mLogEnabled)
{
LogMapPoint(aSrc, aSrcType, aItem);
}
mItems.Add(aItem);
mItemsList.Add(aItem);
mQueue.Enqueue(aItem);
}
}
protected void ScanPlugs(Dictionary<Type, List<Type>> aPlugs)
{
foreach (var xPlug in aPlugs)
{
var xImpls = xPlug.Value;
foreach (var xImpl in xImpls)
{
#region PlugMethods scan
foreach (var xMethod in xImpl.GetMethods(BindingFlags.Public | BindingFlags.Static))
{
PlugMethodAttribute xAttrib = null;
foreach (PlugMethodAttribute x in xMethod.GetCustomAttributes(typeof(PlugMethodAttribute), false))
{
xAttrib = x;
}
if (xAttrib == null)
{
ScanMethod(xMethod, true);
}
else
{
if (xAttrib.IsWildcard && xAttrib.Assembler == null)
{
throw new Exception("Wildcard PlugMethods need to use an assembler for now.");
}
if (xAttrib.Enabled && !xAttrib.IsMonoOnly)
{
ScanMethod(xMethod, true);
}
}
}
#endregion
#region PlugFields scan
foreach (var xField in xImpl.GetCustomAttributes(typeof(PlugFieldAttribute), true).Cast<PlugFieldAttribute>())
{
IDictionary<string, PlugFieldAttribute> xFields = null;
if (!mPlugFields.TryGetValue(xPlug.Key, out xFields))
{
xFields = new Dictionary<string, PlugFieldAttribute>();
mPlugFields.Add(xPlug.Key, xFields);
}
if (xFields.ContainsKey(xField.FieldId))
{
throw new Exception("Duplicate PlugField found for field '" + xField.FieldId + "'!");
}
xFields.Add(xField.FieldId, xField);
}
#endregion
}
}
}
public event Action<string> TempDebug;
private void DoTempDebug(string message)
{
if (TempDebug != null)
{
TempDebug(message);
}
else
{
System.Diagnostics.Debug.WriteLine(message);
}
}
public void Execute(System.Reflection.MethodBase aStartMethod)
{
if (aStartMethod == null)
{
throw new ArgumentNullException("aStartMethod");
}
// TODO: Investigate using MS CCI
// Need to check license, as well as in profiler
// http://cciast.codeplex.com/
#region Description
// Methodology
//
// Ok - we've done the scanner enough times to know it needs to be
// documented super well so that future changes won't inadvertently
// break undocumented and unseen requirements.
//
// We've tried many approaches including recursive and additive scanning.
// They typically end up being inefficient, overly complex, or both.
//
// -We would like to scan all types/methods so we can plug them.
// -But we can't scan them utnil we plug them, becuase we will scan things
// that plugs would remove/change the paths of.
// -Plugs may also call methods which are also plugged.
// -We cannot resolve plugs ahead of time but must do on the fly during
// scanning.
// -TODO: Because we do on the fly resolution, we need to add explicit
// checking of plug classes and err when public methods are found that
// do not resolve. Maybe we can make a list and mark, or rescan. Can be done
// later or as an optional auditing step.
//
// This why in the past we had repetitive scans.
//
// Now we focus on more passes, but simpler execution. In the end it should
// be eaiser to optmize and yield overall better performance. Most of the
// passes should be low overhead versus an integrated system which often
// would need to reiterate over items multiple times. So we do more loops on
// with less repetitive analysis, instead of fewer loops but more repetition.
//
// -Locate all plug classes
// -Scan from entry point collecting all types and methods while checking
// for and following plugs
// -For each type
// -Include all ancestors
// -Include all static constructors
// -For each virtual method
// -Scan overloads in descendants until IsFinal, IsSealed or end
// -Scan base in ancestors until top or IsAbstract
// -Go to scan types again, until no new ones found.
// -Because the virtual method scanning will add to the list as it goes, maintain
// 2 lists.
// -Known Types and Methods
// -Types and Methods in Queue - to be scanned
// -Finally, do compilation
#endregion
FindPlugImpls();
// Now that we found all plugs, scan them.
// We have to scan them after we find all plugs, but because
// plugs can use other plugs
ScanPlugs(mPlugImpls);
ScanPlugs(mPlugImplsInhrt);
foreach (var xPlug in mPlugImpls)
{
DoTempDebug(String.Format("Plug found: '{0}'", xPlug.Key.FullName));
}
ILOp.mPlugFields = mPlugFields;
// // Pull in extra implementations, GC etc.
Queue(RuntimeEngineRefs.InitializeApplicationRef, null, "Explicit Entry");
Queue(RuntimeEngineRefs.FinalizeApplicationRef, null, "Explicit Entry");
//Queue(typeof(CosmosAssembler).GetMethod("PrintException"), null, "Explicit Entry");
Queue(VTablesImplRefs.LoadTypeTableRef, null, "Explicit Entry");
Queue(VTablesImplRefs.SetMethodInfoRef, null, "Explicit Entry");
Queue(VTablesImplRefs.IsInstanceRef, null, "Explicit Entry");
Queue(VTablesImplRefs.SetTypeInfoRef, null, "Explicit Entry");
Queue(VTablesImplRefs.GetMethodAddressForTypeRef, null, "Explicit Entry");
Queue(GCImplementationRefs.IncRefCountRef, null, "Explicit Entry");
Queue(GCImplementationRefs.DecRefCountRef, null, "Explicit Entry");
Queue(GCImplementationRefs.AllocNewObjectRef, null, "Explicit Entry");
// for now, to ease runtime exception throwing
Queue(typeof(ExceptionHelper).GetMethod("ThrowNotImplemented", BindingFlags.Static | BindingFlags.Public, null, new Type[] { typeof(string) }, null), null, "Explicit Entry");
Queue(typeof(ExceptionHelper).GetMethod("ThrowOverflow", BindingFlags.Static | BindingFlags.Public, null, new Type[] { }, null), null, "Explicit Entry");
Queue(RuntimeEngineRefs.InitializeApplicationRef, null, "Explicit Entry");
Queue(RuntimeEngineRefs.FinalizeApplicationRef, null, "Explicit Entry");
// register system types:
Queue(typeof(Array), null, "Explicit Entry");
Queue(typeof(Array).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, Type.EmptyTypes, null), null, "Explicit Entry");
var xThrowHelper = Type.GetType("System.ThrowHelper", true);
Queue(xThrowHelper.GetMethod("ThrowInvalidOperationException", BindingFlags.NonPublic | BindingFlags.Static), null, "Explicit Entry");
Queue(typeof(MulticastDelegate).GetMethod("GetInvocationList"), null, "Explicit Entry");
Queue(ExceptionHelperRefs.CurrentExceptionRef, null, "Explicit Entry");
//System_Delegate____System_MulticastDelegate_GetInvocationList__
// Start from entry point of this program
Queue(aStartMethod, null, "Entry Point");
MethodAndTypeLabelsHolder.GC_IncRefLabel = MethodInfoLabelGenerator.GenerateLabelName(GCImplementationRefs.IncRefCountRef);
ScanQueue();
// Now everything is scanned, lets assemble
foreach (var xItem in mItems)
{
if (xItem is MethodBase)
{
var xMethod = (MethodBase)xItem;
#region Method handling
var xParams = xMethod.GetParameters();
var xParamTypes = new Type[xParams.Length];
// Dont use foreach, enum generaly keeps order but
// isn't guaranteed.
for (int i = 0; i < xParams.Length; i++)
{
xParamTypes[i] = xParams[i].ParameterType;
}
var xPlug = ResolvePlug(xMethod, xParamTypes);
var xMethodType = MethodInfo.TypeEnum.Normal;
Type xPlugAssembler = null;
MethodInfo xPlugInfo = null;
if (xPlug != null)
{
xMethodType = MethodInfo.TypeEnum.NeedsPlug;
PlugMethodAttribute xAttrib = null;
foreach (PlugMethodAttribute attrib in xPlug.GetCustomAttributes(typeof(PlugMethodAttribute), true))
{
xAttrib = attrib;
}
if (xAttrib != null)
{
xPlugAssembler = xAttrib.Assembler;
xPlugInfo = new MethodInfo(xPlug, (uint)mItemsList.IndexOf(xPlug), MethodInfo.TypeEnum.Plug, null, xPlugAssembler);
var xMethodInfo = new MethodInfo(xMethod, (uint)mItemsList.IndexOf(xMethod), xMethodType, xPlugInfo/*, xPlugAssembler*/);
if (xAttrib != null && xAttrib.IsWildcard)
{
xPlugInfo.PluggedMethod = xMethodInfo;
var xInstructions = mReader.ProcessMethod(xPlug);
if (xInstructions != null)
{
ProcessInstructions(xInstructions);
mAsmblr.ProcessMethod(xPlugInfo, xInstructions);
}
}
mAsmblr.GenerateMethodForward(xMethodInfo, xPlugInfo);
}
else
{
InlineAttribute inl = null;
foreach (InlineAttribute inli in xPlug.GetCustomAttributes(typeof(InlineAttribute), false))
{
inl = inli;
}
if (inl != null)
{
xPlugInfo = new MethodInfo(xPlug, (uint)mItemsList.IndexOf(xPlug), MethodInfo.TypeEnum.Plug, null, true);
var xMethodInfo = new MethodInfo(xMethod, (uint)mItemsList.IndexOf(xMethod), xMethodType, xPlugInfo/*, xPlugAssembler*/);
xPlugInfo.PluggedMethod = xMethodInfo;
var xInstructions = mReader.ProcessMethod(xPlug);
if (xInstructions != null)
{
ProcessInstructions(xInstructions);
mAsmblr.ProcessMethod(xPlugInfo, xInstructions);
}
mAsmblr.GenerateMethodForward(xMethodInfo, xPlugInfo);
}
else
{
xPlugInfo = new MethodInfo(xPlug, (uint)mItemsList.IndexOf(xPlug), MethodInfo.TypeEnum.Plug, null, xPlugAssembler);
var xMethodInfo = new MethodInfo(xMethod, (uint)mItemsList.IndexOf(xMethod), xMethodType, xPlugInfo/*, xPlugAssembler*/);
if (xAttrib != null && xAttrib.IsWildcard)
{
xPlugInfo.PluggedMethod = xMethodInfo;
var xInstructions = mReader.ProcessMethod(xPlug);
if (xInstructions != null)
{
ProcessInstructions(xInstructions);
mAsmblr.ProcessMethod(xPlugInfo, xInstructions);
}
}
mAsmblr.GenerateMethodForward(xMethodInfo, xPlugInfo);
}
}
}
else
{
PlugMethodAttribute xAttrib = null;
foreach (PlugMethodAttribute attrib in xMethod.GetCustomAttributes(typeof(PlugMethodAttribute), true))
{
xAttrib = attrib;
}
if (xAttrib != null && xAttrib.IsWildcard)
{
continue;
//xPlugAssembler = xAttrib.Assembler;
}
if (xAttrib != null)
{
xPlugAssembler = xAttrib.Assembler;
}
var xMethodInfo = new MethodInfo(xMethod, (uint)mItemsList.IndexOf(xMethod), xMethodType, xPlugInfo, xPlugAssembler);
var xInstructions = mReader.ProcessMethod(xMethod);
if (xInstructions != null)
{
ProcessInstructions(xInstructions);
mAsmblr.ProcessMethod(xMethodInfo, xInstructions);
}
}
#endregion
}
if (xItem is FieldInfo)
{
var xField = (FieldInfo)xItem;
mAsmblr.ProcessField(xField);
}
}
var xTypes = new HashSet<Type>();
var xMethods = new HashSet<MethodBase>();
foreach (var xItem in mItems)
{
var xMethod = xItem as MethodBase;
if (xMethod != null)
{
xMethods.Add(xMethod);
continue;
}
var xType = xItem as Type;
if (xType != null)
{
xTypes.Add(xType);
continue;
}
}
// do dup check
foreach (var xItem in xTypes)
{
var xType = xItem as Type;
if (xType != null)
{
if (xType.FullName == "Cosmos.Kernel.Heap")
{
Console.WriteLine("{0} - {1}", xType.FullName, xType.GetHashCode());
}
}
}
mAsmblr.GenerateVMTCode(xTypes, xMethods, GetTypeUID, x => GetMethodUID(x, false));
mAsmblr.EmitEntrypoint(aStartMethod, (from item in mItems
where item is MethodBase
select (MethodBase)item));
// mAsmblr.GenerateVMTCode(mTypes, mTypesSet, mKnownMethods);
// dump all methods to temp file.
//File.WriteAllLines(@"e:\methods.txt", (from item in mItems
// let xMethod = item as MethodBase
// where xMethod != null
// select Label.GetFullName(xMethod)).ToArray());
}
public void QueueMethod(MethodBase method)
{
Queue(method, null, "Explicit entry via QueueMethod");
}
/// <summary>
/// This method changes the opcodes. Changes are:
/// * inserting the ValueUID for method ops.
/// </summary>
/// <param name="aOpCodes"></param>
private void ProcessInstructions(List<ILOpCode> aOpCodes)
{
foreach (var xOpCode in aOpCodes)
{
var xOpMethod = xOpCode as ILOpCodes.OpMethod;
if (xOpMethod != null)
{
xOpMethod.Value = (MethodBase)mItems.GetItemInList(xOpMethod.Value);
xOpMethod.ValueUID = (uint)GetMethodUID(xOpMethod.Value, true);
xOpMethod.BaseMethodUID = GetMethodUID(xOpMethod.Value, false);
}
}
}
public void Dispose()
{
if (mLogEnabled)
{
// Create bookmarks, but also a dictionary that
// we can find the items in
var xBookmarks = new Dictionary<object, int>();
int xBookmark = 0;
foreach (var xList in mLogMap)
{
foreach (var xItem in xList.Value)
{
xBookmarks.Add(xItem.Item, xBookmark);
xBookmark++;
}
}
using (mLogWriter = new StreamWriter(mMapPathname, false))
{
mLogWriter.WriteLine("<html><body>");
foreach (var xList in mLogMap)
{
mLogWriter.WriteLine("<hr>");
// Emit bookmarks above source, so when clicking links user doesn't need
// to constantly scroll up.
foreach (var xItem in xList.Value)
{
mLogWriter.WriteLine("<a name=\"Item" + xBookmarks[xItem.Item].ToString() + "\"></a>");
}
int xHref;
if (!xBookmarks.TryGetValue(xList.Key, out xHref))
{
xHref = -1;
}
mLogWriter.Write("<p>");
if (xHref >= 0)
{
mLogWriter.WriteLine("<a href=\"#Item" + xHref.ToString() + "\">");
}
if (xList.Key == null)
{
mLogWriter.WriteLine("Unspecified Source");
}
else
{
mLogWriter.WriteLine(LogItemText(xList.Key));
}
if (xHref >= 0)
{
mLogWriter.Write("</a>");
}
mLogWriter.WriteLine("</a></p>");
mLogWriter.WriteLine("<ul>");
foreach (var xItem in xList.Value)
{
mLogWriter.Write("<li>" + LogItemText(xItem.Item) + "</li>");
mLogWriter.WriteLine("<ul>");
mLogWriter.WriteLine("<li>" + xItem.SrcType + "</<li>");
mLogWriter.WriteLine("</ul>");
}
mLogWriter.WriteLine("</ul>");
}
mLogWriter.WriteLine("</body></html>");
}
}
}
public int MethodCount
{
get
{
return 0;
}
}
protected string LogItemText(object aItem)
{
if (aItem is MethodBase)
{
var x = (MethodBase)aItem;
return "Method: " + x.DeclaringType + "." + x.Name + "<br>" + x.GetFullName();
}
else if (aItem is Type)
{
var x = (Type)aItem;
return "Type: " + x.FullName;
}
else
{
return "Other: " + aItem.ToString();
}
}
protected void FindPlugImpls()
{
// TODO: Cache method list with info - so we dont have to keep
// scanning attributes for enabled etc repeatedly
// TODO: New plug system, common plug base which all descend from
// It can have a "this" member and then we
// can separate static from instance by the static keyword
// and ctors can be static "ctor" by name
// Will still need plug attrib though to specify target
// Also need to handle asm plugs, but those will be different anyways
// TODO: Allow whole class plugs? ie, a class that completely replaces another class
// and is substituted on the fly? Plug scanner would direct all access to that
// class and throw an exception if any method, field, member etc is missing.
foreach (var xAsm in AppDomain.CurrentDomain.GetAssemblies())
{
if (!xAsm.GlobalAssemblyCache)
{
//if (xAsm.GetName().Name == "Cosmos.IL2CPU.X86") {
// // skip this assembly for now. at the moment we introduced the AssemblerMethod.AssembleNew method, for allowing those to work
// // with the Cosmos.IL2CPU* stack, we found we could not use the Cosmos.IL2CPU.X86 plugs, as they contained some AssemblerMethods.
// // This would result in a circular reference, thus we copied them to a new assembly. While the Cosmos.IL2CPU.X86 assembly is being
// // referenced, we need to skip it here.
// continue;
//}
// Find all classes marked as a Plug
foreach (var xPlugType in xAsm.GetTypes())
{
// Foreach, it is possible there could be one plug class with mult plug targets
foreach (PlugAttribute xAttrib in xPlugType.GetCustomAttributes(typeof(PlugAttribute), false))
{
var xTargetType = xAttrib.Target;
// If no type is specified, try to find by a specified name.
// This is needed in cross assembly references where the
// plug cannot reference the assembly of the target type
if (xTargetType == null)
{
try
{
xTargetType = Type.GetType(xAttrib.TargetName, true, false);
}
catch (Exception E)
{
throw new Exception("Error", E);
}
}
// Only keep this plug if its for MS.NET.
// TODO: Integrate with builder options to allow Mono support again.
if (!xAttrib.IsMonoOnly)
{
var mPlugs = xAttrib.Inheritable ? mPlugImplsInhrt : mPlugImpls;
List<Type> xImpls;
if (mPlugs.TryGetValue(xTargetType, out xImpls))
{
xImpls.Add(xPlugType);
}
else
{
xImpls = new List<Type>();
xImpls.Add(xPlugType);
mPlugs.Add(xTargetType, xImpls);
}
}
}
}
}
}
}
protected void ScanMethod(MethodBase aMethod, bool aIsPlug)
{
var xParams = aMethod.GetParameters();
var xParamTypes = new Type[xParams.Length];
// Dont use foreach, enum generaly keeps order but
// isn't guaranteed.
for (int i = 0; i < xParams.Length; i++)
{
xParamTypes[i] = xParams[i].ParameterType;
Queue(xParamTypes[i], aMethod, "Parameter");
}
var xIsDynamicMethod = aMethod.DeclaringType == null;
// Queue Types directly related to method
if (!aIsPlug)
{
// Don't queue declaring types of plugs
if (!xIsDynamicMethod)
{
// dont queue declaring types of dynamic methods either, those dont have a declaring type
Queue(aMethod.DeclaringType, aMethod, "Declaring Type");
}
}
if (aMethod is System.Reflection.MethodInfo)
{
Queue(((System.Reflection.MethodInfo)aMethod).ReturnType, aMethod, "Return Type");
}
// Scan virtuals
#region Virtuals scan
if (!xIsDynamicMethod && aMethod.IsVirtual)
{
// For virtuals we need to climb up the type tree
// and find the top base method. We then add that top
// node to the mVirtuals list. We don't need to add the
// types becuase adding DeclaringType will already cause
// all ancestor types to be added.
var xVirtMethod = aMethod;
var xVirtType = aMethod.DeclaringType;
MethodBase xNewVirtMethod;
while (true)
{
xVirtType = xVirtType.BaseType;
if (xVirtType == null)
{
// We've reached object, can't go farther
xNewVirtMethod = null;
}
else
{
xNewVirtMethod = xVirtType.GetMethod(aMethod.Name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, xParamTypes, null);
if (xNewVirtMethod != null)
{
if (!xNewVirtMethod.IsVirtual)
{
// This can happen if a virtual "replaces" a non virtual
// above it that is not virtual.
xNewVirtMethod = null;
}
}
}
// We dont bother to add these to Queue, because we have to do a
// full downlevel scan if its a new base virtual anyways.
if (xNewVirtMethod == null)
{
// If its already in the list, we mark it null
// so we dont do a full downlevel scan.
if (mVirtuals.Contains(xVirtMethod))
{
xVirtMethod = null;
}
break;
}
xVirtMethod = xNewVirtMethod;
}
// New virtual base found, we need to downscan it
// If it was already in mVirtuals, then ScanType will take
// care of new additions.
if (xVirtMethod != null)
{
Queue(xVirtMethod, aMethod, "Virtual Base");
mVirtuals.Add(xVirtMethod);
if (aMethod.Name == "ToString")
{
Console.Write("");
}
// List changes as we go, cant be foreach
for (int i = 0; i < mItemsList.Count; i++)
{
if (mItemsList[i] is Type)
{
var xType = (Type)mItemsList[i];
if (xType.IsSubclassOf(xVirtMethod.DeclaringType))
{
var xNewMethod = xType.GetMethod(aMethod.Name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, xParamTypes, null);
if (xNewMethod != null)
{
// We need to check IsVirtual, a non virtual could
// "replace" a virtual above it?
if (xNewMethod.IsVirtual)
{
Queue(xNewMethod, aMethod, "Virtual Downscan");
}
}
}
}
}
}
}
#endregion
MethodBase xPlug = null;
// Plugs may use plugs, but plugs won't be plugged over themself
if (!aIsPlug && !xIsDynamicMethod)
{
// Check to see if method is plugged, if it is we don't scan body
xPlug = ResolvePlug(aMethod, xParamTypes);
}
if (xPlug == null)
{
bool xNeedsPlug = false;
if ((aMethod.Attributes & MethodAttributes.PinvokeImpl) != 0)
{
// pinvoke methods dont have an embedded implementation
xNeedsPlug = true;
}
else
{
var xImplFlags = aMethod.GetMethodImplementationFlags();
// todo: prob even more
if ((xImplFlags & MethodImplAttributes.Native) != 0 ||
(xImplFlags & MethodImplAttributes.InternalCall) != 0)
{
// native implementations cannot be compiled
xNeedsPlug = true;
}
}
if (xNeedsPlug)
{
throw new Exception("Plug needed. " + MethodInfoLabelGenerator.GenerateFullName(aMethod));
}
//TODO: As we scan each method, we could update or put in a new list
// that has the resolved plug so we don't have to reresolve it again
// later for compilation.
// Scan the method body for more type and method refs
//TODO: Dont queue new items if they are plugged
// or do we need to queue them with a resolved ref in a new list?
List<ILOpCode> xOpCodes;
xOpCodes = mReader.ProcessMethod(aMethod);
if (xOpCodes != null)
{
ProcessInstructions(xOpCodes);
foreach (var xOpCode in xOpCodes)
{
if (xOpCode is ILOpCodes.OpMethod)
{
Queue(((ILOpCodes.OpMethod)xOpCode).Value, aMethod, "Call");
}
else if (xOpCode is ILOpCodes.OpType)
{
Queue(((ILOpCodes.OpType)xOpCode).Value, aMethod, "OpCode Value");
}
else if (xOpCode is ILOpCodes.OpField)
{
var xOpField = (ILOpCodes.OpField)xOpCode;
//TODO: Need to do this? Will we get a ILOpCodes.OpType as well?
Queue(xOpField.Value.DeclaringType, aMethod, "OpCode Value");
if (xOpField.Value.IsStatic)
{
//TODO: Why do we add static fields, but not instance?
// AW: instance fields are "added" always, as part of a type, but for static fields, we need to emit a datamember
Queue(xOpField.Value, aMethod, "OpCode Value");
}
}
else if (xOpCode is ILOpCodes.OpToken)
{
var xTokenOp = (ILOpCodes.OpToken)xOpCode;
if (xTokenOp.ValueIsType)
{
Queue(xTokenOp.ValueType, aMethod, "OpCode Value");
}
if (xTokenOp.ValueIsField)
{
Queue(xTokenOp.ValueField.DeclaringType, aMethod, "OpCode Value");
if (xTokenOp.ValueField.IsStatic)
{
//TODO: Why do we add static fields, but not instance?
// AW: instance fields are "added" always, as part of a type, but for static fields, we need to emit a datamember
Queue(xTokenOp.ValueField, aMethod, "OpCode Value");
}
}
}
}
}
}
}
protected void ScanType(Type aType)
{
if (aType.IsArray)
{
Console.Write("");
}
// Add immediate ancestor type
// We dont need to crawl up farther, when the BaseType is scanned
// it will add its BaseType, and so on.
if (aType.BaseType != null)
{
Queue(aType.BaseType, aType, "Base Type");
}
// Queue static ctors
// We always need static ctors, else the type cannot
// be created.
foreach (var xCctor in aType.GetConstructors(BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public))
{
if (xCctor.DeclaringType == aType)
{
Queue(xCctor, aType, "Static Constructor");
}
}
// For each new type, we need to scan for possible new virtuals
// in our new type if its a descendant of something in
// mVirtuals.
foreach (var xVirt in mVirtuals)
{
// See if our new type is a subclass of any virt's DeclaringTypes
// If so our new type might have some virtuals
if (aType.IsSubclassOf(xVirt.DeclaringType))
{
var xParams = xVirt.GetParameters();
var xParamTypes = new Type[xParams.Length];
// Dont use foreach, enum generaly keeps order but
// isn't guaranteed.
for (int i = 0; i < xParams.Length; i++)
{
xParamTypes[i] = xParams[i].ParameterType;
}
var xMethod = aType.GetMethod(xVirt.Name, xParamTypes);
if (xMethod != null)
{
// We need to check IsVirtual, a non virtual could
// "replace" a virtual above it?
if (xMethod.IsVirtual)
{
Queue(xMethod, aType, "Virtual");
}
}
}
if (!aType.IsGenericParameter && xVirt.DeclaringType.IsInterface)
{
if (aType.GetInterfaces().Contains(xVirt.DeclaringType))
{
var xIntfMapping = aType.GetInterfaceMap(xVirt.DeclaringType);
if (xIntfMapping.InterfaceMethods != null && xIntfMapping.TargetMethods != null)
{
var xIdx = Array.IndexOf(xIntfMapping.InterfaceMethods, xVirt);
if (xIdx != -1)
{
Queue(xIntfMapping.TargetMethods[xIdx], aType, "Virtual");
}
}
}
}
}
}
protected void ScanQueue()
{
while (mQueue.Count > 0)
{
var xItem = mQueue.Dequeue();
// Check for MethodBase first, they are more numerous
// and will reduce compares
if (xItem is MethodBase)
{
ScanMethod((MethodBase)xItem, false);
}
else if (xItem is Type)
{
ScanType((Type)xItem);
}
else if (xItem is FieldInfo)
{
// todo: static fields need more processing?
}
else
{
throw new Exception("Unknown item found in queue.");
}
}
}
protected void LogMapPoint(object aSrc, string aSrcType, object aItem)
{
// Keys cant be null. If null, we just say ILScanner is the source
if (aSrc == null)
{
aSrc = typeof(ILScanner);
}
var xLogItem = new LogItem()
{
SrcType = aSrcType,
Item = aItem
};
List<LogItem> xList;
if (!mLogMap.TryGetValue(aSrc, out xList))
{
xList = new List<LogItem>();
mLogMap.Add(aSrc, xList);
}
xList.Add(xLogItem);
}
/// <summary>
///
/// </summary>
/// <param name="aTargetType"></param>
/// <param name="aImpls"></param>
/// <param name="aMethod">The target method to be plugged</param>
/// <param name="aParamTypes"></param>
/// <returns></returns>
protected MethodBase ResolvePlug(Type aTargetType, List<Type> aImpls, MethodBase aMethod, Type[] aParamTypes)
{
//TODO: This method is "reversed" from old - remember that when porting
MethodBase xResult = null;
// Setup param types for search
Type[] xParamTypes;
if (aMethod.IsStatic)
{
xParamTypes = aParamTypes;
}
else
{
// If its an instance method, we have to add this to the ParamTypes to search
xParamTypes = new Type[aParamTypes.Length + 1];
if (aParamTypes.Length > 0)
{
aParamTypes.CopyTo(xParamTypes, 1);
}
xParamTypes[0] = aTargetType;
}
PlugMethodAttribute xAttrib = null;
foreach (var xImpl in aImpls)
{
// TODO: cleanup this loop, next statement shouldnt be neccessary
if (xResult != null)
{
break;
}
// Plugs methods must be static, and public
// Search for non signature matches first since signature searches are slower
xResult = xImpl.GetMethod(aMethod.Name, BindingFlags.Static | BindingFlags.Public
, null, xParamTypes, null);
if (xResult == null && aMethod.Name == ".ctor")
{
xResult = xImpl.GetMethod("Ctor", BindingFlags.Static | BindingFlags.Public
, null, xParamTypes, null);
}
if (xResult == null && aMethod.Name == ".cctor")
{
xResult = xImpl.GetMethod("CCtor", BindingFlags.Static | BindingFlags.Public
, null, xParamTypes, null);
}
if (xResult == null)
{
// Search by signature
foreach (var xSigMethod in xImpl.GetMethods(BindingFlags.Static | BindingFlags.Public))
{
// TODO: Only allow one, but this code for now takes the last one
// if there is more than one
xAttrib = null;
foreach (PlugMethodAttribute x in xSigMethod.GetCustomAttributes(typeof(PlugMethodAttribute), false))
{
xAttrib = x;
}
if (xAttrib != null && (xAttrib.IsWildcard && !xAttrib.WildcardMatchParameters))
{
MethodBase xTargetMethod = null;
if (String.Compare(xSigMethod.Name, "Ctor", true) == 0 ||
String.Compare(xSigMethod.Name, "Cctor", true) == 0)
{
xTargetMethod = aTargetType.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance).SingleOrDefault();
}
else
{
xTargetMethod = (from item in aTargetType.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance)
where item.Name == xSigMethod.Name
select item).SingleOrDefault();
}
if (xTargetMethod == aMethod)
{
xResult = xSigMethod;
}
}
else
{
var xParams = xSigMethod.GetParameters();
//TODO: Static method plugs dont seem to be separated
// from instance ones, so the only way seems to be to try
// to match instance first, and if no match try static.
// I really don't like this and feel we need to find
// an explicit way to determine or mark the method
// implementations.
//
// Plug implementations take "this" as first argument
// so when matching we don't include it in the search
Type[] xTypesInst = null;
var xActualParamCount = xParams.Length;
foreach (var xParam in xParams)
{
if (xParam.GetCustomAttributes(typeof(FieldAccessAttribute), false).Length > 0)
{
xActualParamCount--;
}
}
Type[] xTypesStatic = new Type[xActualParamCount];
// If 0 params, has to be a static plug so we skip
// any copying and leave xTypesInst = null
// If 1 params, xTypesInst must be converted to Type[0]
if (xActualParamCount == 1)
{
xTypesInst = new Type[0];
var xReplaceType = xParams[0].GetCustomAttributes(typeof(FieldTypeAttribute), false);
if (xReplaceType.Length == 1)
xTypesStatic[0] = Type.GetType(((FieldTypeAttribute)xReplaceType[0]).Name, true);
else
xTypesStatic[0] = xParams[0].ParameterType;
}
else if (xActualParamCount > 1)
{
xTypesInst = new Type[xActualParamCount - 1];
var xCurIdx = 0;
foreach (var xParam in xParams.Skip(1))
{
if (xParam.GetCustomAttributes(typeof(FieldAccessAttribute), false).Length > 0)
{
continue;
}
var xReplaceType = xParam.GetCustomAttributes(typeof(FieldTypeAttribute), false);
if (xReplaceType.Length == 1)
xTypesInst[xCurIdx] = Type.GetType(((FieldTypeAttribute)xReplaceType[0]).Name, true);
else
xTypesInst[xCurIdx] = xParam.ParameterType;
xCurIdx++;
}
xCurIdx = 0;
foreach (var xParam in xParams)
{
if (xParam.GetCustomAttributes(typeof(FieldAccessAttribute), false).Length > 0)
{
xCurIdx++;
continue;
}
if (xCurIdx >= xTypesStatic.Length)
{
break;
}
xTypesStatic[xCurIdx] = xParam.ParameterType;
xCurIdx++;
}
}
System.Reflection.MethodBase xTargetMethod = null;
// TODO: In future make rule that all ctor plugs are called
// ctor by name, or use a new attrib
//TODO: Document all the plug stuff in a document on website
//TODO: To make inclusion of plugs easy, we can make a plugs master
// that references the other default plugs so user exes only
// need to reference that one.
// TODO: Skip FieldAccessAttribute if in impl
if (xTypesInst != null)
{
if (string.Compare(xSigMethod.Name, "ctor", true) == 0)
{
xTargetMethod = aTargetType.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, CallingConventions.Any, xTypesInst, null);
}
else
{
xTargetMethod = aTargetType.GetMethod(xSigMethod.Name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, CallingConventions.Any, xTypesInst, null);
}
}
// Not an instance method, try static
if (xTargetMethod == null)
{
if (string.Compare(xSigMethod.Name, "cctor", true) == 0
|| string.Compare(xSigMethod.Name, "ctor", true) == 0)
{
xTargetMethod = aTargetType.GetConstructor(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, CallingConventions.Any, xTypesStatic, null);
}
else
{
xTargetMethod = aTargetType.GetMethod(xSigMethod.Name, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, CallingConventions.Any, xTypesStatic, null);
}
}
if (xTargetMethod == aMethod)
{
xResult = xSigMethod;
break;
}
if (xAttrib != null && xAttrib.Signature != null)
{
var xName = DataMember.FilterStringForIncorrectChars(MethodInfoLabelGenerator.GenerateFullName(aMethod));
if (string.Compare(xName, xAttrib.Signature, true) == 0)
{
xResult = xSigMethod;
break;
}
}
xAttrib = null;
}
}
}
else
{
// check if signatur is equal
var xResPara = xResult.GetParameters();
var xAMethodPara = aMethod.GetParameters();
if (aMethod.IsStatic)
{
if (xResPara.Length != xAMethodPara.Length)
return null;
}
else
{
if (xResPara.Length - 1 != xAMethodPara.Length)
return null;
}
for (int i = 0; i < xAMethodPara.Length; i++)
{
int correctIndex = aMethod.IsStatic ? i : i + 1;
if (xResPara[correctIndex].ParameterType != xAMethodPara[i].ParameterType)
return null;
}
if (xResult.Name == "Ctor" && aMethod.Name == ".ctor")
{
}
else if (xResult.Name == "CCtor" && aMethod.Name == ".cctor")
{
}
else if (xResult.Name != aMethod.Name)
return null;
}
}
if (xResult == null)
return null;
// If we found a matching method, check for attributes
// that might disable it.
//TODO: For signature ones, we could cache the attrib. Thats
// why we check for null here
if (xAttrib == null)
{
// TODO: Only allow one, but this code for now takes the last one
// if there is more than one
foreach (PlugMethodAttribute x in xResult.GetCustomAttributes(typeof(PlugMethodAttribute), false))
{
xAttrib = x;
}
}
// See if we need to disable this plug
if (xAttrib != null)
{
if (!xAttrib.Enabled)
{
xResult = null;
}
else if (xAttrib.IsMonoOnly)
{
//TODO: Check this against build options
//TODO: Two exclusive IsOnly's dont make sense
// refactor these as a positive rather than negative
// Same thing at type plug level
xResult = null;
}
//else if (xAttrib.Signature != null) {
// var xName = DataMember.FilterStringForIncorrectChars(MethodInfoLabelGenerator.GenerateFullName(xResult));
// if (string.Compare(xName, xAttrib.Signature, true) != 0) {
// xResult = null;
// }
//}
}
Queue(xResult, null, "Plug Method");
//if (xAttrib != null && xAttrib.Signature != null)
//{
// var xTargetMethods = aTargetType.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
// //System_Void__Indy_IL2CPU_Assembler_Assembler__cctor__
// //If signature exists, the search is slow. Signatures
// //are infrequent though, so for now we just go slow method
// //and have not optimized or cached this info. When we
// //redo the plugs, we can fix this.
// bool xEnabled=true;
// foreach (var xTargetMethod in xTargetMethods)
// {
// string sName = DataMember.FilterStringForIncorrectChars(MethodInfoLabelGenerator.GenerateFullName(xTargetMethod));
// if (string.Compare(sName, xAttrib.Signature, true) == 0)
// {
// //uint xUID = QueueMethod(xPlugImpl.Plug, "Plug", xMethod, true);
// //mMethodPlugs.Add(xTargetMethod, new PlugInfo(xUID, xAttrib.Assembler));
// // Mark as disabled, because we already handled it
// xEnabled = false;
// break;
// }
// }
// // if still enabled, we didn't find our method
// if (xEnabled)
// {
// // todo: more precise error: imagine having a 100K line project, and this error happens...
// throw new Exception("Plug target method not found.");
// }
//}
return xResult;
}
#region Plug Caching
private Orvid.Collections.SkipList ResolvedPlugs = new Orvid.Collections.SkipList();
private static string BuildMethodKeyName(MethodBase m)
{
return MethodInfoLabelGenerator.GenerateFullName(m);
}
#endregion
protected MethodBase ResolvePlug(MethodBase aMethod, Type[] aParamTypes)
{
MethodBase xResult = null;
if (ResolvedPlugs.Contains(BuildMethodKeyName(aMethod), out xResult))
{
return xResult;
}
else
{
if (aMethod.DeclaringType.Name == "Delegate" && aMethod.Name == "InternalAllocLike" && aMethod.GetParameters().Length > 0)
{
Console.Write("");
}
// TODO: Right now plugs are compiled in, even if they are not needed.
// Maybe change this so plugs that are not needed are not compiled in?
// To do so, maybe plugs could be marked as they are used
List<Type> xImpls;
// Check for exact type plugs first, they have precedence
if (mPlugImpls.TryGetValue(aMethod.DeclaringType, out xImpls))
{
xResult = ResolvePlug(aMethod.DeclaringType, xImpls, aMethod, aParamTypes);
}
// Check for inheritable plugs second.
// We also need to fall through at method level, not just type.
// That is a exact type plug could exist, but not method match.
// In such a case the Inheritable methods should still be searched
// if there is a inheritable type match.
if (xResult == null)
{
foreach (var xInheritable in mPlugImplsInhrt)
{
if (aMethod.DeclaringType.IsSubclassOf(xInheritable.Key))
{
xResult = ResolvePlug(aMethod.DeclaringType/*xInheritable.Key*/, xInheritable.Value, aMethod, aParamTypes);
if (xResult != null)
{
// prevent key overriding.
break;
}
}
}
}
ResolvedPlugs.Add(BuildMethodKeyName(aMethod), xResult);
return xResult;
}
}
private MethodBase GetUltimateBaseMethod(MethodBase aMethod, Type[] aMethodParams, Type aCurrentInspectedType)
{
MethodBase xBaseMethod = null;
//try {
while (true)
{
if (aCurrentInspectedType.BaseType == null)
{
break;
}
aCurrentInspectedType = aCurrentInspectedType.BaseType;
MethodBase xFoundMethod = aCurrentInspectedType.GetMethod(aMethod.Name,
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance,
Type.DefaultBinder,
aMethodParams,
new ParameterModifier[0]);
if (xFoundMethod == null)
{
break;
}
ParameterInfo[] xParams = xFoundMethod.GetParameters();
bool xContinue = true;
for (int i = 0; i < xParams.Length; i++)
{
if (xParams[i].ParameterType != aMethodParams[i])
{
xContinue = false;
continue;
}
}
if (!xContinue)
{
continue;
}
if (xFoundMethod != null)
{
xBaseMethod = xFoundMethod;
if (xFoundMethod.IsVirtual == aMethod.IsVirtual && xFoundMethod.IsPrivate == false && xFoundMethod.IsPublic == aMethod.IsPublic && xFoundMethod.IsFamily == aMethod.IsFamily && xFoundMethod.IsFamilyAndAssembly == aMethod.IsFamilyAndAssembly && xFoundMethod.IsFamilyOrAssembly == aMethod.IsFamilyOrAssembly && xFoundMethod.IsFinal == false)
{
var xFoundMethInfo = xFoundMethod as SR.MethodInfo;
var xBaseMethInfo = xBaseMethod as SR.MethodInfo;
if (xFoundMethInfo == null && xBaseMethInfo == null)
{
xBaseMethod = xFoundMethod;
}
if (xFoundMethInfo != null && xBaseMethInfo != null)
{
if (xFoundMethInfo.ReturnType.AssemblyQualifiedName.Equals(xBaseMethInfo.ReturnType.AssemblyQualifiedName))
{
xBaseMethod = xFoundMethod;
}
}
//xBaseMethod = xFoundMethod;
}
}
//else
//{
// xBaseMethod = xFoundMethod;
//}
}
//} catch (Exception) {
// todo: try to get rid of the try..catch
//}
return xBaseMethod ?? aMethod;
}
protected uint GetMethodUID(MethodBase aMethod, bool aExact)
{
if (!aExact)
{
ParameterInfo[] xParams = aMethod.GetParameters();
Type[] xParamTypes = new Type[xParams.Length];
for (int i = 0; i < xParams.Length; i++)
{
xParamTypes[i] = xParams[i].ParameterType;
}
var xBaseMethod = GetUltimateBaseMethod(aMethod, xParamTypes, aMethod.DeclaringType);
if (!mMethodUIDs.ContainsKey(xBaseMethod))
{
var xId = (uint)mMethodUIDs.Count;
mMethodUIDs.Add(xBaseMethod, xId);
}
return mMethodUIDs[xBaseMethod];
}
else
{
if (!mMethodUIDs.ContainsKey(aMethod))
{
var xId = (uint)mMethodUIDs.Count;
mMethodUIDs.Add(aMethod, xId);
}
return mMethodUIDs[aMethod];
}
}
protected uint GetTypeUID(Type aType)
{
if (!mItems.Contains(aType))
{
throw new Exception("Cannot get UID of types which are not queued!");
}
if (!mTypeUIDs.ContainsKey(aType))
{
var xId = (uint)mTypeUIDs.Count;
mTypeUIDs.Add(aType, xId);
return xId;
}
else
{
return mTypeUIDs[aType];
}
}
// === Old code and comments ======================================================
// //TODO: These store the MethodBase which also have the IL for the body in memory
// // For large asms this could eat lot of RAM. Should convert this to remove
// // items from the list after they are processed but keep them in HashSet so we
// // know they are already done. Currently HashSet uses a reference though, so we
// // need to hash on some UID instead of the refernce. Do not use strings, they are
// // super slow.
// // TODO: We need to scan for static fields too.
// private void ScanMethod(MethodInfo aMethodInfo) {
// var xMethodBase = aMethodInfo.MethodBase;
// // Assemble the method
//TODO: We have to load the opcodes twice, this might be slow,
// but loading in RAM could consume lots of RAM
// if (aMethodInfo.MethodBase.DeclaringType != mThrowHelper) {
// mAsmblr.ProcessMethod(aMethodInfo, xOpCodes);
// }
// }
// }
// private void QueueField(object aSrc, string aSrcType, Cosmos.IL2CPU.ILOpCodes.OpField xOpField) {
// // todo: add log map thing?
// if (!mStaticFields.Contains(xOpField.Value)) {
// mStaticFields.Add(xOpField.Value);
// mAsmblr.ProcessField(xOpField.Value);
// QueueType(xOpField.Value, "FieldType", xOpField.Value.FieldType);
// QueueType(xOpField.Value, "DeclaringType", xOpField.Value.FieldType);
// }
// }
// // QueueMethod should only queue the method, and do no processing of the
// // body or resolution of its contents. It is called during plug resolution
// // etc and all further resolution should wait until all plugs are loaded.
// public uint QueueMethod(object aSrc, string aSrcType, MethodBase aMethodBase
// , bool aIsPlug)
// {
// uint xResult;
// xResult = (uint)mMethodsToProcess.Count;
// mKnownMethods.Add(aMethodBase, xResult);
// MethodInfo xPlug = null;
// Type xPlugAssembler = null;
// var xMethodType = MethodInfo.TypeEnum.Normal;
// if (aIsPlug) {
// xMethodType = MethodInfo.TypeEnum.Plug;
// } else {
// xMethodType = MethodInfo.TypeEnum.Normal;
// if (xMethodType == MethodInfo.TypeEnum.NeedsPlug && xPlug == null && xPlugAssembler == null) {
// throw new Exception("Method [" + aMethodBase.DeclaringType + "." + aMethodBase.Name + "] needs to be plugged, but wasn't");
// }
// }
// var xMethod = new MethodInfo(aMethodBase, xResult, xMethodType, xPlug, xPlugAssembler);
// mMethodsToProcess.Add(xMethod);
// if(!aIsPlug) {
// // Queue Types directly related to method
// QueueType(aMethodBase, "Declaring Type", aMethodBase.DeclaringType);
// if (aMethodBase is System.Reflection.MethodInfo) {
// QueueType(aMethodBase, "Return Type", ((System.Reflection.MethodInfo)aMethodBase).ReturnType);
// }
// foreach (var xParam in aMethodBase.GetParameters()) {
// QueueType(aMethodBase, "Parameter", xParam.ParameterType);
// }
// }
// return xResult;
// }
// //protected void QueueStaticField(FieldInfo aFieldInfo) {
// // if (!mFieldsSet.Contains(aFieldInfo)) {
// // if (!aFieldInfo.IsStatic) {
// // throw new Exception("Cannot queue instance fields!");
// // }
// // mFieldsSet.Add(aFieldInfo);
// // QueueType(aFieldInfo.DeclaringType);
// // QueueType(aFieldInfo.FieldType);
// // }
// //}
}
}