PageRenderTime 52ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/source2/IL2CPU/Cosmos.IL2CPU/ILScanner.cs

https://bitbucket.org/mvptracker/cosmos
C# | 1211 lines | 813 code | 87 blank | 311 comment | 307 complexity | 0bb1268037ae2f5ebd7d910e0822d6f7 MD5 | raw file
Possible License(s): BSD-2-Clause

Large files files are truncated, but you can click here to view the full file

  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Linq;
  5. using System.Reflection;
  6. using System.Text;
  7. using Cosmos.IL2CPU;
  8. using Cosmos.IL2CPU.Plugs;
  9. using Cosmos.IL2CPU.IL;
  10. using SR = System.Reflection;
  11. using Cosmos.Assembler;
  12. using System.Reflection.Emit;
  13. using _MemberInfo = System.Runtime.InteropServices._MemberInfo;
  14. namespace Cosmos.IL2CPU {
  15. // This is necessary because HashSet and Dictionary
  16. // have troubles when different types of objects are stored
  17. // in them. I dont remember the exact problem, but something
  18. // with how it compares objects. ie when HashSet<object> is used, this is necessary.
  19. /*public class HashcodeComparer<T> : IEqualityComparer<T> {
  20. public bool Equals(T x, T y) {
  21. return internalEqualsSinceNET40(x, y);// x.GetHashCode() == y.GetHashCode();
  22. }
  23. public bool internalEqualsSinceNET40(T left, T right)
  24. {
  25. var methodDeclaringType = left.GetType().GetMethod("get_DeclaringType");
  26. var leftDeclaringType = methodDeclaringType.Invoke(left, null);
  27. var method = right.GetType().GetMethod("get_DeclaringType");
  28. var rightDeclaringType = method.Invoke(right, null);
  29. if (left.ToString() == right.ToString()
  30. && leftDeclaringType == rightDeclaringType)
  31. {
  32. return true;
  33. }
  34. return false;
  35. }
  36. public int GetHashCode(T obj) {
  37. return obj.GetHashCode();
  38. }
  39. }*/
  40. public class ScannerQueueItem {
  41. public _MemberInfo Item;
  42. public string SourceItem;
  43. public string QueueReason;
  44. public override string ToString() {
  45. return Item.MemberType + " " + Item.ToString();
  46. }
  47. }
  48. public class ILScanner : IDisposable {
  49. protected ILReader mReader;
  50. protected AppAssembler mAsmblr;
  51. // List of asssemblies found during scan. We cannot use the list of loaded
  52. // assemblies because the loaded list includes compilers, etc, and also possibly
  53. // other unused assemblies. So instead we collect a list of assemblies as we scan.
  54. protected List<Assembly> mUsedAssemblies = new List<Assembly>();
  55. protected OurHashSet<object> mItems = new OurHashSet<object>();
  56. protected List<object> mItemsList = new List<object>();
  57. // Contains items to be scanned, both types and methods
  58. protected Queue<ScannerQueueItem> mQueue = new Queue<ScannerQueueItem>();
  59. // Virtual methods are nasty and constantly need to be rescanned for
  60. // overriding methods in new types, so we keep track of them separately.
  61. // They are also in the main mItems and mQueue.
  62. protected HashSet<MethodBase> mVirtuals = new HashSet<MethodBase>();
  63. protected IDictionary<MethodBase, uint> mMethodUIDs = new Dictionary<MethodBase, uint>();
  64. protected IDictionary<Type, uint> mTypeUIDs = new Dictionary<Type, uint>();
  65. // Contains a list of plug implementor classes
  66. // Key = Target Class
  67. // Value = List of Implementors. There may be more than one
  68. protected Dictionary<Type, List<Type>> mPlugImpls = new Dictionary<Type, List<Type>>();
  69. // List of inheritable plugs. Plugs that start at an ancestor and plug all
  70. // descendants. For example, delegates
  71. protected Dictionary<Type, List<Type>> mPlugImplsInhrt = new Dictionary<Type, List<Type>>();
  72. // list of field plugs
  73. protected IDictionary<Type, IDictionary<string, PlugFieldAttribute>> mPlugFields = new Dictionary<Type, IDictionary<string, PlugFieldAttribute>>();
  74. // Logging
  75. // Only use for debugging and profiling.
  76. protected bool mLogEnabled = false;
  77. protected string mMapPathname;
  78. protected TextWriter mLogWriter;
  79. protected struct LogItem {
  80. public string SrcType;
  81. public object Item;
  82. }
  83. protected Dictionary<object, List<LogItem>> mLogMap;
  84. //TODO: Look for Field plugs
  85. public ILScanner(AppAssembler aAsmblr) {
  86. mAsmblr = aAsmblr;
  87. mReader = new ILReader();
  88. }
  89. public void EnableLogging(string aPathname) {
  90. mLogMap = new Dictionary<object, List<LogItem>>();
  91. mMapPathname = aPathname;
  92. mLogEnabled = true;
  93. }
  94. protected void Queue(_MemberInfo aItem, object aSrc, string aSrcType, object sourceItem = null) {
  95. var xMemInfo = aItem as MemberInfo;
  96. //TODO: fix this, as each label/symbol should also contain an assembly specifier.
  97. if (xMemInfo != null && xMemInfo.DeclaringType != null
  98. && xMemInfo.DeclaringType.FullName == "System.ThrowHelper"
  99. && xMemInfo.DeclaringType.Assembly.GetName().Name != "mscorlib") {
  100. // System.ThrowHelper exists in MS .NET twice...
  101. // Its an internal class that exists in both mscorlib and system assemblies.
  102. // They are separate types though, so normally the scanner scans both and
  103. // then we get conflicting labels. MS included it twice to make exception
  104. // throwing code smaller. They are internal though, so we cannot
  105. // reference them directly and only via finding them as they come along.
  106. // We find it here, not via QueueType so we only check it here. Later
  107. // we might have to checkin QueueType also.
  108. // So now we accept both types, but emit code for only one. This works
  109. // with the current Nasm assembler as we resolve by name in the assembler.
  110. // However with other assemblers this approach may not work.
  111. // If AssemblerNASM adds assembly name to the label, this will allow
  112. // both to exist as they do in BCL.
  113. // So in the future we might be able to remove this hack, or change
  114. // how it works.
  115. //
  116. // Do nothing
  117. //
  118. } else if (!mItems.Contains(aItem)) {
  119. if (mLogEnabled) {
  120. LogMapPoint(aSrc, aSrcType, aItem);
  121. }
  122. mItems.Add(aItem);
  123. mItemsList.Add(aItem);
  124. mQueue.Enqueue(new ScannerQueueItem() { Item = aItem, QueueReason = aSrcType, SourceItem = aSrc + Environment.NewLine + sourceItem });
  125. }
  126. }
  127. protected void ScanPlugs(Dictionary<Type, List<Type>> aPlugs) {
  128. foreach (var xPlug in aPlugs) {
  129. var xImpls = xPlug.Value;
  130. foreach (var xImpl in xImpls) {
  131. #region PlugMethods scan
  132. foreach (var xMethod in xImpl.GetMethods(BindingFlags.Public | BindingFlags.Static)) {
  133. PlugMethodAttribute xAttrib = null;
  134. foreach (PlugMethodAttribute x in xMethod.GetCustomAttributes(typeof(PlugMethodAttribute), false)) {
  135. xAttrib = x;
  136. }
  137. if (xAttrib == null) {
  138. ScanMethod(xMethod, true, "Plug Sub Method");
  139. } else {
  140. if (xAttrib.IsWildcard && xAttrib.Assembler == null) {
  141. throw new Exception("Wildcard PlugMethods need to use an assembler for now.");
  142. }
  143. if (xAttrib.Enabled && !xAttrib.IsMonoOnly) {
  144. ScanMethod(xMethod, true, ".Net plug Method");
  145. }
  146. }
  147. }
  148. #endregion
  149. #region PlugFields scan
  150. foreach (var xField in xImpl.GetCustomAttributes(typeof(PlugFieldAttribute), true).Cast<PlugFieldAttribute>()) {
  151. IDictionary<string, PlugFieldAttribute> xFields = null;
  152. if (!mPlugFields.TryGetValue(xPlug.Key, out xFields)) {
  153. xFields = new Dictionary<string, PlugFieldAttribute>();
  154. mPlugFields.Add(xPlug.Key, xFields);
  155. }
  156. if (xFields.ContainsKey(xField.FieldId)) {
  157. throw new Exception("Duplicate PlugField found for field '" + xField.FieldId + "'!");
  158. }
  159. xFields.Add(xField.FieldId, xField);
  160. }
  161. #endregion
  162. }
  163. }
  164. }
  165. public event Action<string> TempDebug;
  166. private void DoTempDebug(string message) {
  167. if (TempDebug != null) {
  168. TempDebug(message);
  169. } else {
  170. System.Diagnostics.Debug.WriteLine(message);
  171. }
  172. }
  173. public void Execute(System.Reflection.MethodBase aStartMethod) {
  174. if (aStartMethod == null) {
  175. throw new ArgumentNullException("aStartMethod");
  176. }
  177. // TODO: Investigate using MS CCI
  178. // Need to check license, as well as in profiler
  179. // http://cciast.codeplex.com/
  180. #region Description
  181. // Methodology
  182. //
  183. // Ok - we've done the scanner enough times to know it needs to be
  184. // documented super well so that future changes won't inadvertently
  185. // break undocumented and unseen requirements.
  186. //
  187. // We've tried many approaches including recursive and additive scanning.
  188. // They typically end up being inefficient, overly complex, or both.
  189. //
  190. // -We would like to scan all types/methods so we can plug them.
  191. // -But we can't scan them utnil we plug them, becuase we will scan things
  192. // that plugs would remove/change the paths of.
  193. // -Plugs may also call methods which are also plugged.
  194. // -We cannot resolve plugs ahead of time but must do on the fly during
  195. // scanning.
  196. // -TODO: Because we do on the fly resolution, we need to add explicit
  197. // checking of plug classes and err when public methods are found that
  198. // do not resolve. Maybe we can make a list and mark, or rescan. Can be done
  199. // later or as an optional auditing step.
  200. //
  201. // This why in the past we had repetitive scans.
  202. //
  203. // Now we focus on more passes, but simpler execution. In the end it should
  204. // be eaiser to optmize and yield overall better performance. Most of the
  205. // passes should be low overhead versus an integrated system which often
  206. // would need to reiterate over items multiple times. So we do more loops on
  207. // with less repetitive analysis, instead of fewer loops but more repetition.
  208. //
  209. // -Locate all plug classes
  210. // -Scan from entry point collecting all types and methods while checking
  211. // for and following plugs
  212. // -For each type
  213. // -Include all ancestors
  214. // -Include all static constructors
  215. // -For each virtual method
  216. // -Scan overloads in descendants until IsFinal, IsSealed or end
  217. // -Scan base in ancestors until top or IsAbstract
  218. // -Go to scan types again, until no new ones found.
  219. // -Because the virtual method scanning will add to the list as it goes, maintain
  220. // 2 lists.
  221. // -Known Types and Methods
  222. // -Types and Methods in Queue - to be scanned
  223. // -Finally, do compilation
  224. #endregion
  225. FindPlugImpls();
  226. // Now that we found all plugs, scan them.
  227. // We have to scan them after we find all plugs, but because
  228. // plugs can use other plugs
  229. ScanPlugs(mPlugImpls);
  230. ScanPlugs(mPlugImplsInhrt);
  231. foreach (var xPlug in mPlugImpls) {
  232. DoTempDebug(String.Format("Plug found: '{0}'", xPlug.Key.FullName));
  233. }
  234. ILOp.mPlugFields = mPlugFields;
  235. // Pull in extra implementations, GC etc.
  236. Queue(RuntimeEngineRefs.InitializeApplicationRef, null, "Explicit Entry");
  237. Queue(RuntimeEngineRefs.FinalizeApplicationRef, null, "Explicit Entry");
  238. //Queue(typeof(CosmosAssembler).GetMethod("PrintException"), null, "Explicit Entry");
  239. Queue(VTablesImplRefs.LoadTypeTableRef, null, "Explicit Entry");
  240. Queue(VTablesImplRefs.SetMethodInfoRef, null, "Explicit Entry");
  241. Queue(VTablesImplRefs.IsInstanceRef, null, "Explicit Entry");
  242. Queue(VTablesImplRefs.SetTypeInfoRef, null, "Explicit Entry");
  243. Queue(VTablesImplRefs.GetMethodAddressForTypeRef, null, "Explicit Entry");
  244. Queue(GCImplementationRefs.IncRefCountRef, null, "Explicit Entry");
  245. Queue(GCImplementationRefs.DecRefCountRef, null, "Explicit Entry");
  246. Queue(GCImplementationRefs.AllocNewObjectRef, null, "Explicit Entry");
  247. // for now, to ease runtime exception throwing
  248. Queue(typeof(ExceptionHelper).GetMethod("ThrowNotImplemented", BindingFlags.Static | BindingFlags.Public, null, new Type[] { typeof(string) }, null), null, "Explicit Entry");
  249. Queue(typeof(ExceptionHelper).GetMethod("ThrowOverflow", BindingFlags.Static | BindingFlags.Public, null, new Type[] { }, null), null, "Explicit Entry");
  250. Queue(RuntimeEngineRefs.InitializeApplicationRef, null, "Explicit Entry");
  251. Queue(RuntimeEngineRefs.FinalizeApplicationRef, null, "Explicit Entry");
  252. // register system types:
  253. Queue(typeof(Array), null, "Explicit Entry");
  254. Queue(typeof(Array).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, Type.EmptyTypes, null), null, "Explicit Entry");
  255. var xThrowHelper = Type.GetType("System.ThrowHelper", true);
  256. Queue(xThrowHelper.GetMethod("ThrowInvalidOperationException", BindingFlags.NonPublic | BindingFlags.Static), null, "Explicit Entry");
  257. Queue(typeof(MulticastDelegate).GetMethod("GetInvocationList"), null, "Explicit Entry");
  258. Queue(ExceptionHelperRefs.CurrentExceptionRef, null, "Explicit Entry");
  259. //System_Delegate____System_MulticastDelegate_GetInvocationList__
  260. // Start from entry point of this program
  261. Queue(aStartMethod, null, "Entry Point");
  262. ScanQueue();
  263. UpdateAssemblies();
  264. Assemble();
  265. mAsmblr.EmitEntrypoint(aStartMethod);
  266. }
  267. public void QueueMethod(MethodBase method) {
  268. Queue(method, null, "Explicit entry via QueueMethod");
  269. }
  270. /// This method changes the opcodes. Changes are:
  271. /// * inserting the ValueUID for method ops.
  272. private void ProcessInstructions(List<ILOpCode> aOpCodes) {
  273. foreach (var xOpCode in aOpCodes) {
  274. var xOpMethod = xOpCode as ILOpCodes.OpMethod;
  275. if (xOpMethod != null) {
  276. xOpMethod.Value = (MethodBase)mItems.GetItemInList(xOpMethod.Value);
  277. xOpMethod.ValueUID = (uint)GetMethodUID(xOpMethod.Value, true);
  278. xOpMethod.BaseMethodUID = GetMethodUID(xOpMethod.Value, false);
  279. }
  280. }
  281. }
  282. public void Dispose() {
  283. if (mLogEnabled) {
  284. // Create bookmarks, but also a dictionary that
  285. // we can find the items in
  286. var xBookmarks = new Dictionary<object, int>();
  287. int xBookmark = 0;
  288. foreach (var xList in mLogMap) {
  289. foreach (var xItem in xList.Value) {
  290. xBookmarks.Add(xItem.Item, xBookmark);
  291. xBookmark++;
  292. }
  293. }
  294. using (mLogWriter = new StreamWriter(mMapPathname, false)) {
  295. mLogWriter.WriteLine("<html><body>");
  296. foreach (var xList in mLogMap) {
  297. mLogWriter.WriteLine("<hr>");
  298. // Emit bookmarks above source, so when clicking links user doesn't need
  299. // to constantly scroll up.
  300. foreach (var xItem in xList.Value) {
  301. mLogWriter.WriteLine("<a name=\"Item" + xBookmarks[xItem.Item].ToString() + "\"></a>");
  302. }
  303. int xHref;
  304. if (!xBookmarks.TryGetValue(xList.Key, out xHref)) {
  305. xHref = -1;
  306. }
  307. mLogWriter.Write("<p>");
  308. if (xHref >= 0) {
  309. mLogWriter.WriteLine("<a href=\"#Item" + xHref.ToString() + "\">");
  310. }
  311. if (xList.Key == null) {
  312. mLogWriter.WriteLine("Unspecified Source");
  313. } else {
  314. mLogWriter.WriteLine(LogItemText(xList.Key));
  315. }
  316. if (xHref >= 0) {
  317. mLogWriter.Write("</a>");
  318. }
  319. mLogWriter.WriteLine("</a></p>");
  320. mLogWriter.WriteLine("<ul>");
  321. foreach (var xItem in xList.Value) {
  322. mLogWriter.Write("<li>" + LogItemText(xItem.Item) + "</li>");
  323. mLogWriter.WriteLine("<ul>");
  324. mLogWriter.WriteLine("<li>" + xItem.SrcType + "</<li>");
  325. mLogWriter.WriteLine("</ul>");
  326. }
  327. mLogWriter.WriteLine("</ul>");
  328. }
  329. mLogWriter.WriteLine("</body></html>");
  330. }
  331. }
  332. }
  333. public int MethodCount {
  334. get {
  335. return mMethodUIDs.Count;
  336. }
  337. }
  338. protected string LogItemText(object aItem) {
  339. if (aItem is MethodBase) {
  340. var x = (MethodBase)aItem;
  341. return "Method: " + x.DeclaringType + "." + x.Name + "<br>" + x.GetFullName();
  342. } else if (aItem is Type) {
  343. var x = (Type)aItem;
  344. return "Type: " + x.FullName;
  345. } else {
  346. return "Other: " + aItem.ToString();
  347. }
  348. }
  349. protected void FindPlugImpls() {
  350. // TODO: Cache method list with info - so we dont have to keep
  351. // scanning attributes for enabled etc repeatedly
  352. // TODO: New plug system, common plug base which all descend from
  353. // It can have a "this" member and then we
  354. // can separate static from instance by the static keyword
  355. // and ctors can be static "ctor" by name
  356. // Will still need plug attrib though to specify target
  357. // Also need to handle asm plugs, but those will be different anyways
  358. // TODO: Allow whole class plugs? ie, a class that completely replaces another class
  359. // and is substituted on the fly? Plug scanner would direct all access to that
  360. // class and throw an exception if any method, field, member etc is missing.
  361. foreach (var xAsm in AppDomain.CurrentDomain.GetAssemblies()) {
  362. if (!xAsm.GlobalAssemblyCache) {
  363. //if (xAsm.GetName().Name == "Cosmos.IL2CPU.X86") {
  364. // // skip this assembly for now. at the moment we introduced the AssemblerMethod.AssembleNew method, for allowing those to work
  365. // // with the Cosmos.IL2CPU* stack, we found we could not use the Cosmos.IL2CPU.X86 plugs, as they contained some AssemblerMethods.
  366. // // This would result in a circular reference, thus we copied them to a new assembly. While the Cosmos.IL2CPU.X86 assembly is being
  367. // // referenced, we need to skip it here.
  368. // continue;
  369. //}
  370. // Find all classes marked as a Plug
  371. foreach (var xPlugType in xAsm.GetTypes()) {
  372. // Foreach, it is possible there could be one plug class with mult plug targets
  373. foreach (PlugAttribute xAttrib in xPlugType.GetCustomAttributes(typeof(PlugAttribute), false)) {
  374. var xTargetType = xAttrib.Target;
  375. // If no type is specified, try to find by a specified name.
  376. // This is needed in cross assembly references where the
  377. // plug cannot reference the assembly of the target type
  378. if (xTargetType == null) {
  379. try {
  380. xTargetType = Type.GetType(xAttrib.TargetName, true, false);
  381. } catch (Exception ex) {
  382. throw new Exception("Error", ex);
  383. }
  384. }
  385. // Only keep this plug if its for MS.NET.
  386. // TODO: Integrate with builder options to allow Mono support again.
  387. if (!xAttrib.IsMonoOnly) {
  388. var mPlugs = xAttrib.Inheritable ? mPlugImplsInhrt : mPlugImpls;
  389. List<Type> xImpls;
  390. if (mPlugs.TryGetValue(xTargetType, out xImpls)) {
  391. xImpls.Add(xPlugType);
  392. } else {
  393. xImpls = new List<Type>();
  394. xImpls.Add(xPlugType);
  395. mPlugs.Add(xTargetType, xImpls);
  396. }
  397. }
  398. }
  399. }
  400. }
  401. }
  402. }
  403. protected void ScanMethod(MethodBase aMethod, bool aIsPlug, object sourceItem) {
  404. var xParams = aMethod.GetParameters();
  405. var xParamTypes = new Type[xParams.Length];
  406. // Dont use foreach, enum generaly keeps order but
  407. // isn't guaranteed.
  408. for (int i = 0; i < xParams.Length; i++) {
  409. xParamTypes[i] = xParams[i].ParameterType;
  410. Queue(xParamTypes[i], LabelName.GenerateFullName(aMethod), "Parameter");
  411. }
  412. var xIsDynamicMethod = aMethod.DeclaringType == null;
  413. // Queue Types directly related to method
  414. if (!aIsPlug) {
  415. // Don't queue declaring types of plugs
  416. if (!xIsDynamicMethod) {
  417. // dont queue declaring types of dynamic methods either, those dont have a declaring type
  418. Queue(aMethod.DeclaringType, LabelName.GenerateFullName(aMethod), "Declaring Type");
  419. }
  420. }
  421. if (aMethod is System.Reflection.MethodInfo) {
  422. Queue(((System.Reflection.MethodInfo)aMethod).ReturnType, LabelName.GenerateFullName(aMethod), "Return Type");
  423. }
  424. // Scan virtuals
  425. #region Virtuals scan
  426. if (!xIsDynamicMethod && aMethod.IsVirtual) {
  427. // For virtuals we need to climb up the type tree
  428. // and find the top base method. We then add that top
  429. // node to the mVirtuals list. We don't need to add the
  430. // types becuase adding DeclaringType will already cause
  431. // all ancestor types to be added.
  432. var xVirtMethod = aMethod;
  433. var xVirtType = aMethod.DeclaringType;
  434. MethodBase xNewVirtMethod;
  435. while (true) {
  436. xVirtType = xVirtType.BaseType;
  437. if (xVirtType == null) {
  438. // We've reached object, can't go farther
  439. xNewVirtMethod = null;
  440. } else {
  441. xNewVirtMethod = xVirtType.GetMethod(aMethod.Name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, xParamTypes, null);
  442. if (xNewVirtMethod != null) {
  443. if (!xNewVirtMethod.IsVirtual) {
  444. // This can happen if a virtual "replaces" a non virtual
  445. // above it that is not virtual.
  446. xNewVirtMethod = null;
  447. }
  448. }
  449. }
  450. // We dont bother to add these to Queue, because we have to do a
  451. // full downlevel scan if its a new base virtual anyways.
  452. if (xNewVirtMethod == null) {
  453. // If its already in the list, we mark it null
  454. // so we dont do a full downlevel scan.
  455. if (mVirtuals.Contains(xVirtMethod)) {
  456. xVirtMethod = null;
  457. }
  458. break;
  459. }
  460. xVirtMethod = xNewVirtMethod;
  461. }
  462. // New virtual base found, we need to downscan it
  463. // If it was already in mVirtuals, then ScanType will take
  464. // care of new additions.
  465. if (xVirtMethod != null) {
  466. Queue(xVirtMethod, LabelName.GenerateFullName(aMethod), "Virtual Base");
  467. mVirtuals.Add(xVirtMethod);
  468. if (aMethod.Name == "ToString") {
  469. Console.Write("");
  470. }
  471. // List changes as we go, cant be foreach
  472. for (int i = 0; i < mItemsList.Count; i++) {
  473. if (mItemsList[i] is Type) {
  474. var xType = (Type)mItemsList[i];
  475. if (xType.IsSubclassOf(xVirtMethod.DeclaringType)) {
  476. var xNewMethod = xType.GetMethod(aMethod.Name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, xParamTypes, null);
  477. if (xNewMethod != null) {
  478. // We need to check IsVirtual, a non virtual could
  479. // "replace" a virtual above it?
  480. if (xNewMethod.IsVirtual) {
  481. Queue(xNewMethod, LabelName.GenerateFullName(aMethod), "Virtual Downscan");
  482. }
  483. }
  484. }
  485. }
  486. }
  487. }
  488. }
  489. #endregion
  490. MethodBase xPlug = null;
  491. // Plugs may use plugs, but plugs won't be plugged over themself
  492. if (!aIsPlug && !xIsDynamicMethod) {
  493. // Check to see if method is plugged, if it is we don't scan body
  494. xPlug = ResolvePlug(aMethod, xParamTypes);
  495. }
  496. if (xPlug == null) {
  497. bool xNeedsPlug = false;
  498. if ((aMethod.Attributes & MethodAttributes.PinvokeImpl) != 0) {
  499. // pinvoke methods dont have an embedded implementation
  500. xNeedsPlug = true;
  501. } else {
  502. var xImplFlags = aMethod.GetMethodImplementationFlags();
  503. // todo: prob even more
  504. if ((xImplFlags & MethodImplAttributes.Native) != 0 ||
  505. (xImplFlags & MethodImplAttributes.InternalCall) != 0) {
  506. // native implementations cannot be compiled
  507. xNeedsPlug = true;
  508. }
  509. }
  510. if (xNeedsPlug) {
  511. throw new Exception("Native code encountered, plug required. Please see http://cosmos.codeplex.com/wikipage?title=Plugs). " + LabelName.GenerateFullName(aMethod) + "." + Environment.NewLine + " Called from :" + Environment.NewLine + sourceItem);
  512. }
  513. //TODO: As we scan each method, we could update or put in a new list
  514. // that has the resolved plug so we don't have to reresolve it again
  515. // later for compilation.
  516. // Scan the method body for more type and method refs
  517. //TODO: Dont queue new items if they are plugged
  518. // or do we need to queue them with a resolved ref in a new list?
  519. InlineAttribute inl = null;
  520. foreach (InlineAttribute inli in aMethod.GetCustomAttributes(typeof(InlineAttribute), false)) {
  521. inl = inli;
  522. }
  523. if (inl != null)
  524. return; // cancel inline
  525. List<ILOpCode> xOpCodes;
  526. xOpCodes = mReader.ProcessMethod(aMethod);
  527. if (xOpCodes != null) {
  528. ProcessInstructions(xOpCodes);
  529. foreach (var xOpCode in xOpCodes) {
  530. if (xOpCode is ILOpCodes.OpMethod) {
  531. Queue(((ILOpCodes.OpMethod)xOpCode).Value, LabelName.GenerateFullName(aMethod), "Call", sourceItem);
  532. } else if (xOpCode is ILOpCodes.OpType) {
  533. Queue(((ILOpCodes.OpType)xOpCode).Value, LabelName.GenerateFullName(aMethod), "OpCode Value");
  534. } else if (xOpCode is ILOpCodes.OpField) {
  535. var xOpField = (ILOpCodes.OpField)xOpCode;
  536. //TODO: Need to do this? Will we get a ILOpCodes.OpType as well?
  537. Queue(xOpField.Value.DeclaringType, LabelName.GenerateFullName(aMethod), "OpCode Value");
  538. if (xOpField.Value.IsStatic) {
  539. //TODO: Why do we add static fields, but not instance?
  540. // AW: instance fields are "added" always, as part of a type, but for static fields, we need to emit a datamember
  541. Queue(xOpField.Value, LabelName.GenerateFullName(aMethod), "OpCode Value");
  542. }
  543. } else if (xOpCode is ILOpCodes.OpToken) {
  544. var xTokenOp = (ILOpCodes.OpToken)xOpCode;
  545. if (xTokenOp.ValueIsType) {
  546. Queue(xTokenOp.ValueType, LabelName.GenerateFullName(aMethod), "OpCode Value");
  547. }
  548. if (xTokenOp.ValueIsField) {
  549. Queue(xTokenOp.ValueField.DeclaringType, LabelName.GenerateFullName(aMethod), "OpCode Value");
  550. if (xTokenOp.ValueField.IsStatic) {
  551. //TODO: Why do we add static fields, but not instance?
  552. // AW: instance fields are "added" always, as part of a type, but for static fields, we need to emit a datamember
  553. Queue(xTokenOp.ValueField, LabelName.GenerateFullName(aMethod), "OpCode Value");
  554. }
  555. }
  556. }
  557. }
  558. }
  559. }
  560. }
  561. protected void ScanType(Type aType) {
  562. if (aType.IsArray) {
  563. Console.Write("");
  564. }
  565. // Add immediate ancestor type
  566. // We dont need to crawl up farther, when the BaseType is scanned
  567. // it will add its BaseType, and so on.
  568. if (aType.BaseType != null) {
  569. Queue(aType.BaseType, aType, "Base Type");
  570. }
  571. // Queue static ctors
  572. // We always need static ctors, else the type cannot
  573. // be created.
  574. foreach (var xCctor in aType.GetConstructors(BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public)) {
  575. if (xCctor.DeclaringType == aType) {
  576. Queue(xCctor, aType, "Static Constructor");
  577. }
  578. }
  579. // For each new type, we need to scan for possible new virtuals
  580. // in our new type if its a descendant of something in
  581. // mVirtuals.
  582. foreach (var xVirt in mVirtuals) {
  583. // See if our new type is a subclass of any virt's DeclaringTypes
  584. // If so our new type might have some virtuals
  585. if (aType.IsSubclassOf(xVirt.DeclaringType)) {
  586. var xParams = xVirt.GetParameters();
  587. var xParamTypes = new Type[xParams.Length];
  588. // Dont use foreach, enum generaly keeps order but
  589. // isn't guaranteed.
  590. for (int i = 0; i < xParams.Length; i++) {
  591. xParamTypes[i] = xParams[i].ParameterType;
  592. }
  593. var xMethod = aType.GetMethod(xVirt.Name, xParamTypes);
  594. if (xMethod != null) {
  595. // We need to check IsVirtual, a non virtual could
  596. // "replace" a virtual above it?
  597. if (xMethod.IsVirtual) {
  598. Queue(xMethod, aType, "Virtual");
  599. }
  600. }
  601. }
  602. if (!aType.IsGenericParameter && xVirt.DeclaringType.IsInterface) {
  603. if (aType.GetInterfaces().Contains(xVirt.DeclaringType)) {
  604. var xIntfMapping = aType.GetInterfaceMap(xVirt.DeclaringType);
  605. if (xIntfMapping.InterfaceMethods != null && xIntfMapping.TargetMethods != null) {
  606. var xIdx = Array.IndexOf(xIntfMapping.InterfaceMethods, xVirt);
  607. if (xIdx != -1) {
  608. Queue(xIntfMapping.TargetMethods[xIdx], aType, "Virtual");
  609. }
  610. }
  611. }
  612. }
  613. }
  614. }
  615. protected void ScanQueue() {
  616. while (mQueue.Count > 0) {
  617. var xItem = mQueue.Dequeue();
  618. // Check for MethodBase first, they are more numerous
  619. // and will reduce compares
  620. if (xItem.Item is MethodBase) {
  621. ScanMethod((MethodBase)xItem.Item, false, xItem.SourceItem);
  622. } else if (xItem.Item is Type) {
  623. var xType = (Type)xItem.Item;
  624. ScanType(xType);
  625. // Methods and fields cant exist without types, so we only update
  626. // mUsedAssemblies in type branch.
  627. if (!mUsedAssemblies.Contains(xType.Assembly)) {
  628. mUsedAssemblies.Add(xType.Assembly);
  629. }
  630. } else if (xItem.Item is FieldInfo) {
  631. // todo: static fields need more processing?
  632. } else {
  633. throw new Exception("Unknown item found in queue.");
  634. }
  635. }
  636. }
  637. protected void LogMapPoint(object aSrc, string aSrcType, object aItem) {
  638. // Keys cant be null. If null, we just say ILScanner is the source
  639. if (aSrc == null) {
  640. aSrc = typeof(ILScanner);
  641. }
  642. var xLogItem = new LogItem() {
  643. SrcType = aSrcType,
  644. Item = aItem
  645. };
  646. List<LogItem> xList;
  647. if (!mLogMap.TryGetValue(aSrc, out xList)) {
  648. xList = new List<LogItem>();
  649. mLogMap.Add(aSrc, xList);
  650. }
  651. xList.Add(xLogItem);
  652. }
  653. protected MethodBase ResolvePlug(Type aTargetType, List<Type> aImpls, MethodBase aMethod, Type[] aParamTypes) {
  654. //TODO: This method is "reversed" from old - remember that when porting
  655. MethodBase xResult = null;
  656. // Setup param types for search
  657. Type[] xParamTypes;
  658. if (aMethod.IsStatic) {
  659. xParamTypes = aParamTypes;
  660. } else {
  661. // If its an instance method, we have to add this to the ParamTypes to search
  662. xParamTypes = new Type[aParamTypes.Length + 1];
  663. if (aParamTypes.Length > 0) {
  664. aParamTypes.CopyTo(xParamTypes, 1);
  665. }
  666. xParamTypes[0] = aTargetType;
  667. }
  668. PlugMethodAttribute xAttrib = null;
  669. foreach (var xImpl in aImpls) {
  670. // TODO: cleanup this loop, next statement shouldnt be neccessary
  671. if (xResult != null) {
  672. break;
  673. }
  674. // Plugs methods must be static, and public
  675. // Search for non signature matches first since signature searches are slower
  676. xResult = xImpl.GetMethod(aMethod.Name, BindingFlags.Static | BindingFlags.Public
  677. , null, xParamTypes, null);
  678. if (xResult == null && aMethod.Name == ".ctor") {
  679. xResult = xImpl.GetMethod("Ctor", BindingFlags.Static | BindingFlags.Public
  680. , null, xParamTypes, null);
  681. }
  682. if (xResult == null && aMethod.Name == ".cctor") {
  683. xResult = xImpl.GetMethod("CCtor", BindingFlags.Static | BindingFlags.Public
  684. , null, xParamTypes, null);
  685. }
  686. if (xResult == null) {
  687. // Search by signature
  688. foreach (var xSigMethod in xImpl.GetMethods(BindingFlags.Static | BindingFlags.Public)) {
  689. // TODO: Only allow one, but this code for now takes the last one
  690. // if there is more than one
  691. xAttrib = null;
  692. foreach (PlugMethodAttribute x in xSigMethod.GetCustomAttributes(typeof(PlugMethodAttribute), false)) {
  693. xAttrib = x;
  694. }
  695. if (xAttrib != null && (xAttrib.IsWildcard && !xAttrib.WildcardMatchParameters)) {
  696. MethodBase xTargetMethod = null;
  697. if (String.Compare(xSigMethod.Name, "Ctor", true) == 0 ||
  698. String.Compare(xSigMethod.Name, "Cctor", true) == 0) {
  699. xTargetMethod = aTargetType.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance).SingleOrDefault();
  700. } else {
  701. xTargetMethod = (from item in aTargetType.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance)
  702. where item.Name == xSigMethod.Name
  703. select item).SingleOrDefault();
  704. }
  705. if (xTargetMethod == aMethod) {
  706. xResult = xSigMethod;
  707. }
  708. } else {
  709. var xParams = xSigMethod.GetParameters();
  710. //TODO: Static method plugs dont seem to be separated
  711. // from instance ones, so the only way seems to be to try
  712. // to match instance first, and if no match try static.
  713. // I really don't like this and feel we need to find
  714. // an explicit way to determine or mark the method
  715. // implementations.
  716. //
  717. // Plug implementations take "this" as first argument
  718. // so when matching we don't include it in the search
  719. Type[] xTypesInst = null;
  720. var xActualParamCount = xParams.Length;
  721. foreach (var xParam in xParams) {
  722. if (xParam.GetCustomAttributes(typeof(FieldAccessAttribute), false).Length > 0) {
  723. xActualParamCount--;
  724. }
  725. }
  726. Type[] xTypesStatic = new Type[xActualParamCount];
  727. // If 0 params, has to be a static plug so we skip
  728. // any copying and leave xTypesInst = null
  729. // If 1 params, xTypesInst must be converted to Type[0]
  730. if (xActualParamCount == 1) {
  731. xTypesInst = new Type[0];
  732. var xReplaceType = xParams[0].GetCustomAttributes(typeof(FieldTypeAttribute), false);
  733. if (xReplaceType.Length == 1)
  734. xTypesStatic[0] = Type.GetType(((FieldTypeAttribute)xReplaceType[0]).Name, true);
  735. else
  736. xTypesStatic[0] = xParams[0].ParameterType;
  737. } else if (xActualParamCount > 1) {
  738. xTypesInst = new Type[xActualParamCount - 1];
  739. var xCurIdx = 0;
  740. foreach (var xParam in xParams.Skip(1)) {
  741. if (xParam.GetCustomAttributes(typeof(FieldAccessAttribute), false).Length > 0) {
  742. continue;
  743. }
  744. var xReplaceType = xParam.GetCustomAttributes(typeof(FieldTypeAttribute), false);
  745. if (xReplaceType.Length == 1)
  746. xTypesInst[xCurIdx] = Type.GetType(((FieldTypeAttribute)xReplaceType[0]).Name, true);
  747. else
  748. xTypesInst[xCurIdx] = xParam.ParameterType;
  749. xCurIdx++;
  750. }
  751. xCurIdx = 0;
  752. foreach (var xParam in xParams) {
  753. if (xParam.GetCustomAttributes(typeof(FieldAccessAttribute), false).Length > 0) {
  754. xCurIdx++;
  755. continue;
  756. }
  757. if (xCurIdx >= xTypesStatic.Length) {
  758. break;
  759. }
  760. xTypesStatic[xCurIdx] = xParam.ParameterType;
  761. xCurIdx++;
  762. }
  763. }
  764. System.Reflection.MethodBase xTargetMethod = null;
  765. // TODO: In future make rule that all ctor plugs are called
  766. // ctor by name, or use a new attrib
  767. //TODO: Document all the plug stuff in a document on website
  768. //TODO: To make inclusion of plugs easy, we can make a plugs master
  769. // that references the other default plugs so user exes only
  770. // need to reference that one.
  771. // TODO: Skip FieldAccessAttribute if in impl
  772. if (xTypesInst != null) {
  773. if (string.Compare(xSigMethod.Name, "ctor", true) == 0) {
  774. xTargetMethod = aTargetType.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, CallingConventions.Any, xTypesInst, null);
  775. } else {
  776. xTargetMethod = aTargetType.GetMethod(xSigMethod.Name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, CallingConventions.Any, xTypesInst, null);
  777. }
  778. }
  779. // Not an instance method, try static
  780. if (xTargetMethod == null) {
  781. if (string.Compare(xSigMethod.Name, "cctor", true) == 0
  782. || string.Compare(xSigMethod.Name, "ctor", true) == 0) {
  783. xTargetMethod = aTargetType.GetConstructor(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, CallingConventions.Any, xTypesStatic, null);
  784. } else {
  785. xTargetMethod = aTargetType.GetMethod(xSigMethod.Name, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, CallingConventions.Any, xTypesStatic, null);
  786. }
  787. }
  788. if (xTargetMethod == aMethod) {
  789. xResult = xSigMethod;
  790. break;
  791. }
  792. if (xAttrib != null && xAttrib.Signature != null) {
  793. var xName = DataMember.FilterStringForIncorrectChars(LabelName.GenerateFullName(aMethod));
  794. if (string.Compare(xName, xAttrib.Signature, true) == 0) {
  795. xResult = xSigMethod;
  796. break;
  797. }
  798. }
  799. xAttrib = null;
  800. }
  801. }
  802. } else {
  803. // check if signatur is equal
  804. var xResPara = xResult.GetParameters();
  805. var xAMethodPara = aMethod.GetParameters();
  806. if (aMethod.IsStatic) {
  807. if (xResPara.Length != xAMethodPara.Length)
  808. return null;
  809. } else {
  810. if (xResPara.Length - 1 != xAMethodPara.Length)
  811. return null;
  812. }
  813. for (int i = 0; i < xAMethodPara.Length; i++) {
  814. int correctIndex = aMethod.IsStatic ? i : i + 1;
  815. if (xResPara[correctIndex].ParameterType != xAMethodPara[i].ParameterType)
  816. return null;
  817. }
  818. if (xResult.Name == "Ctor" && aMethod.Name == ".ctor") {
  819. } else if (xResult.Name == "CCtor" && aMethod.Name == ".cctor") {
  820. } else if (xResult.Name != aMethod.Name)
  821. return null;
  822. }
  823. }
  824. if (xResult == null)
  825. return null;
  826. // If we found a matching method, check for attributes
  827. // that might disable it.
  828. //TODO: For signature ones, we could cache the attrib. Thats
  829. // why we check for null here
  830. if (xAttrib == null) {
  831. // TODO: Only allow one, but this code for now takes the last one
  832. // if there is more than one
  833. foreach (PlugMethodAttribute x in xResult.GetCustomAttributes(typeof(PlugMethodAttribute), false)) {
  834. xAttrib = x;
  835. }
  836. }
  837. // See if we need to disable this plug
  838. if (xAttrib != null) {
  839. if (!xAttrib.Enabled) {
  840. //xResult = null;
  841. return null;
  842. } else if (xAttrib.IsMonoOnly) {
  843. //TODO: Check this against build options
  844. //TODO: Two exclusive IsOnly's dont make sense
  845. // refactor these as a positive rather than negative
  846. // Same thing at type plug level
  847. //xResult = null;
  848. return null;
  849. }
  850. //else if (xAttrib.Signature != null) {
  851. // var xName = DataMember.FilterStringForIncorrectChars(MethodInfoLabelGenerator.GenerateFullName(xResult));
  852. // if (string.Compare(xName, xAttrib.Signature, true) != 0) {
  853. // xResult = null;
  854. // }
  855. //}
  856. }
  857. InlineAttribute xInlineAttrib = null;
  858. foreach (InlineAttribute inli in xResult.GetCustomAttributes(typeof(InlineAttribute), false)) {
  859. xInlineAttrib = inli;
  860. }
  861. if (xInlineAttrib == null)
  862. Queue(xResult, null, "Plug Method");
  863. //if (xAttrib != null && xAttrib.Signature != null)
  864. //{
  865. // var xTargetMethods = aTargetType.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
  866. // //System_Void__Indy_IL2CPU_Assembler_Assembler__cctor__
  867. // //If signature exists, the search is slow. Signatures
  868. // //are infrequent though, so for now we just go slow method
  869. // //and have not optimized or cached this info. When we
  870. // //redo the plugs, we can fix this.
  871. // bool xEnabled=true;
  872. // foreach (var xTargetMethod in xTargetMethods)
  873. // {
  874. // string sName = DataMember.FilterStringForIncorrectChars(MethodInfoLabelGenerator.GenerateFullName(xTargetMethod));
  875. // if (string.Compare(sName, xAttrib.Signature, true) == 0)
  876. // {
  877. // //uint xUID = QueueMethod(xPlugImpl.Plug, "Plug", xMethod, true);
  878. // //mMethodPlugs.Add(xTargetMethod, new PlugInfo(xUID, xAttrib.Assembler));
  879. // // Mark as disabled, because we already handled it
  880. // xEnabled = false;
  881. // break;
  882. // }
  883. // }
  884. // // if still enabled, we didn't find our method
  885. // if (xEnabled)
  886. // {
  887. // // todo: more precise error: imagine having a 100K line project, and this error happens...
  888. // throw new Exception("Plug target method not found.");
  889. // }
  890. //}
  891. return xResult;
  892. }
  893. #region Plug Caching
  894. private Orvid.Collections.SkipList ResolvedPlugs = new Orvid.Collections.SkipList();
  895. private static string BuildMethodKeyName(MethodBase m) {
  896. return LabelName.GenerateFullName(m);
  897. }
  898. #endregion
  899. protected MethodBase ResolvePlug(MethodBase aMethod, Type[] aParamTypes) {
  900. MethodBase xResult = null;
  901. if (ResolvedPlugs.Contains(BuildMethodKeyName(aMethod), out xResult)) {
  902. return xResult;
  903. } else {
  904. if (aMethod.DeclaringType.Name == "Delegate" && aMethod.Name == "InternalAllocLike" && aMethod.GetParameters().Length > 0) {
  905. Console.Write("");
  906. }
  907. // TODO: Right now plugs are compiled in, even if they are not needed.
  908. // Maybe change this so plugs that are not needed are not compiled in?
  909. // To do so, maybe plugs could be marked as they are used
  910. List<Type> xImpls;
  911. // Check for exact type plugs first, they have precedence
  912. if (mPlugImpls.TryGetValue(aMethod.DeclaringType, out xImpls)) {
  913. xResult = ResolvePlug(aMethod.DeclaringType, xImpls, aMethod, aParamTypes);
  914. }
  915. // Check for inheritable plugs second.
  916. // We also need to fall through at method level, not just type.
  917. // That is a exact type plug could exist, but not method match.
  918. // In such a case the Inheritable methods should still be searched
  919. // if there is a inheritable type match.
  920. if (xResult == null) {
  921. foreach (var xInheritable in mPlugImplsInhrt) {
  922. if (aMethod.DeclaringType.IsSubclassOf(xInheritable.Key)) {
  923. xResult = ResolvePlug(aMethod.DeclaringType/*xInheritable.Key*/, xInheritable.Value, aMethod, aParamTypes);
  924. if (xResult != null) {
  925. // prevent key overriding.
  926. break;
  927. }
  928. }
  929. }
  930. }
  931. ResolvedPlugs.Add(BuildMethodKeyName(aMethod), xResult);
  932. return xResult;
  933. }
  934. }
  935. private MethodBase GetUltimateBaseMethod(MethodBase aMethod, Type[] aMethodParams, Type aCurrentInspectedType) {
  936. MethodBase xBaseMethod = null;
  937. //try {
  938. while (true) {
  939. if (aCurrentInspectedType.BaseType == null) {
  940. break;
  941. }
  942. aCurrentInspectedType = aCurrentInspectedType.BaseType;
  943. MethodBase xFoundMethod = aCurrentInspectedType.GetMethod(aMethod.Name,
  944. BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance,
  945. Type.DefaultBinder,
  946. aMethodParams,
  947. new ParameterModifier[0]);
  948. if (xFoundMethod == null) {
  949. break;
  950. }
  951. ParameterInfo[] xParams = xFoundMethod.GetParameters();
  952. bool xContinue = true;
  953. for (int i = 0; i < xParams.Length; i++) {
  954. if (xParams[i].ParameterType != aMethodParams[i]) {
  955. xContinue = false;
  956. continue;
  957. }
  958. }
  959. if (!xContinue) {
  960. continue;
  961. }
  962. if (xFoundMethod != null) {
  963. xBaseMethod = xFoundMethod;
  964. 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) {
  965. var xFoundMethInfo = xFoundMethod as SR.MethodInfo;
  966. var xBaseMethInfo = xBaseMethod as SR.MethodInfo;
  967. if (xFoundMethInfo == null && xBaseMethInfo == null) {
  968. xBaseMethod = xFoundMethod;
  969. }
  970. if (xFoundMethInfo != null && xBaseMethInfo != null) {
  971. if (xFoundMethInfo.ReturnType.AssemblyQualifiedName.Equals(xBaseMethInfo.ReturnType.AssemblyQualifiedName)) {
  972. xBaseMethod = xFoundMethod;
  973. }
  974. }
  975. //xBaseMethod = xFoundMethod;
  976. }
  977. }
  978. //else
  979. //{
  980. // xBaseMethod = xFoundMethod;
  981. //}
  982. }
  983. //} catch (Exception) {
  984. // todo: try to get rid of the try..catch
  985. //}
  986. return xBaseMethod ?? aMethod;
  987. }
  988. protected uint GetMethodUID(MethodBase aMethod, bool aExact) {
  989. if (!aExact) {
  990. ParameterInfo[] xParams = aMethod.GetParameters();
  991. Type[] xParamTypes = new Type[xParams.Length];
  992. for (int i = 0; i < xParams.Length; i++) {
  993. xParamTypes[i] = xParams[i].ParameterType;
  994. }
  995. var xBaseMethod = GetUltimateBaseMethod(aMethod, xParamTypes, aMethod.DeclaringType);
  996. if (!mMethodUIDs.ContainsKey(xBaseMethod)) {
  997. var xId = (uint)mMethodUIDs.Count;
  998. mMethodUIDs.Add(xBaseMethod, xId);
  999. }
  1000. return mMethodUIDs[xBaseMethod];
  1001. } else {
  1002. if (!mMethodUIDs.ContainsKey(aMethod)) {
  1003. var xId = (uint)mMethodUIDs.Count;
  1004. mMethodUIDs.Add(aMethod, xId);
  1005. }
  1006. return mMethodUIDs[aMethod];
  1007. }
  1008. }
  1009. protected uint GetTypeUID(Type aType) {
  1010. if (!mItems.Contains(aType)) {
  1011. throw new Exception("Cannot get UID of types which are not queued!");
  1012. }
  1013. if (!mTypeUIDs.ContainsKey(aType)) {
  1014. var xId = (uint)mTypeUIDs.Count;
  1015. mTypeUIDs.Add(aType, xId);
  1016. return xId;
  1017. } else {
  1018. return mTypeUIDs[aType];
  1019. }
  1020. }
  1021. protected void UpdateAssemblies() {
  1022. // It would be nice to keep DebugInfo output into assembler only but
  1023. // there is so much info that is available in scanner that is needed
  1024. // or can be used in a more efficient manner. So we output in both
  1025. // scanner and assembler as needed.
  1026. mAsmblr.DebugInfo.AddAssemblies(mUsedAssemblies);
  1027. }
  1028. protected void Assemble() {
  1029. foreach (var xItem in mItems) {
  1030. if (xItem is MethodBase) {
  1031. var xMethod = (MethodBase)xItem;
  1032. var xParams = xMethod.GetParameter

Large files files are truncated, but you can click here to view the full file