Analyzer.cs 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. using dnlib.DotNet;
  2. using HybridCLR.Editor.Meta;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Linq;
  6. using System.Text;
  7. using System.Threading.Tasks;
  8. using UnityEngine;
  9. namespace HybridCLR.Editor.AOT
  10. {
  11. public class Analyzer
  12. {
  13. public class Options
  14. {
  15. public AssemblyReferenceDeepCollector Collector { get; set; }
  16. public int MaxIterationCount { get; set; }
  17. public bool ComputeAotAssembly { get; set; }
  18. }
  19. private readonly int _maxInterationCount;
  20. private readonly AssemblyReferenceDeepCollector _assemblyCollector;
  21. private readonly bool _computeAotAssembly;
  22. private readonly HashSet<GenericClass> _genericTypes = new HashSet<GenericClass>();
  23. private readonly HashSet<GenericMethod> _genericMethods = new HashSet<GenericMethod>();
  24. private List<GenericMethod> _processingMethods = new List<GenericMethod>();
  25. private List<GenericMethod> _newMethods = new List<GenericMethod>();
  26. public IReadOnlyCollection<GenericClass> GenericTypes => _genericTypes;
  27. public IReadOnlyCollection<GenericMethod> GenericMethods => _genericMethods;
  28. private readonly MethodReferenceAnalyzer _methodReferenceAnalyzer;
  29. private readonly HashSet<string> _hotUpdateAssemblyFiles;
  30. public ConstraintContext ConstraintContext { get; } = new ConstraintContext();
  31. public List<GenericClass> AotGenericTypes { get; } = new List<GenericClass>();
  32. public List<GenericMethod> AotGenericMethods { get; } = new List<GenericMethod>();
  33. public Analyzer(Options options)
  34. {
  35. _assemblyCollector = options.Collector;
  36. _maxInterationCount = options.MaxIterationCount;
  37. _computeAotAssembly = options.ComputeAotAssembly;
  38. _methodReferenceAnalyzer = new MethodReferenceAnalyzer(this.OnNewMethod);
  39. _hotUpdateAssemblyFiles = new HashSet<string>(options.Collector.GetRootAssemblyNames().Select(assName => assName + ".dll"));
  40. }
  41. private void TryAddAndWalkGenericType(GenericClass gc)
  42. {
  43. if (gc == null)
  44. {
  45. return;
  46. }
  47. gc = gc.ToGenericShare();
  48. if (_genericTypes.Add(gc) && NeedWalk(null, gc.Type))
  49. {
  50. WalkType(gc);
  51. }
  52. }
  53. private bool NeedWalk(MethodDef callFrom, TypeDef type)
  54. {
  55. return _hotUpdateAssemblyFiles.Contains(type.Module.Name) || callFrom == null || callFrom.HasGenericParameters;
  56. }
  57. private bool IsAotType(TypeDef type)
  58. {
  59. return _computeAotAssembly || !_hotUpdateAssemblyFiles.Contains(type.Module.Name);
  60. }
  61. private bool IsAotGenericMethod(MethodDef method)
  62. {
  63. return IsAotType(method.DeclaringType) && method.HasGenericParameters;
  64. }
  65. private void OnNewMethod(MethodDef methodDef, List<TypeSig> klassGenericInst, List<TypeSig> methodGenericInst, GenericMethod method)
  66. {
  67. if(method == null)
  68. {
  69. return;
  70. }
  71. if (NeedWalk(methodDef, method.Method.DeclaringType) && _genericMethods.Add(method))
  72. {
  73. _newMethods.Add(method);
  74. }
  75. if (method.KlassInst != null)
  76. {
  77. TryAddAndWalkGenericType(new GenericClass(method.Method.DeclaringType, method.KlassInst));
  78. }
  79. }
  80. private void TryAddMethodNotWalkType(GenericMethod method)
  81. {
  82. if (method == null)
  83. {
  84. return;
  85. }
  86. if (NeedWalk(null, method.Method.DeclaringType) && _genericMethods.Add(method))
  87. {
  88. _newMethods.Add(method);
  89. }
  90. }
  91. private void WalkType(GenericClass gc)
  92. {
  93. //Debug.Log($"typespec:{sig} {sig.GenericType} {sig.GenericType.TypeDefOrRef.ResolveTypeDef()}");
  94. //Debug.Log($"== walk generic type:{new GenericInstSig(gc.Type.ToTypeSig().ToClassOrValueTypeSig(), gc.KlassInst)}");
  95. ITypeDefOrRef baseType = gc.Type.BaseType;
  96. if (baseType != null && baseType.TryGetGenericInstSig() != null)
  97. {
  98. GenericClass parentType = GenericClass.ResolveClass((TypeSpec)baseType, new GenericArgumentContext(gc.KlassInst, null));
  99. TryAddAndWalkGenericType(parentType);
  100. }
  101. foreach (var method in gc.Type.Methods)
  102. {
  103. if (method.HasGenericParameters || !method.HasBody || method.Body.Instructions == null)
  104. {
  105. continue;
  106. }
  107. var gm = new GenericMethod(method, gc.KlassInst, null).ToGenericShare();
  108. //Debug.Log($"add method:{gm.Method} {gm.KlassInst}");
  109. TryAddMethodNotWalkType(gm);
  110. }
  111. }
  112. private void WalkType(TypeDef typeDef)
  113. {
  114. if (typeDef.HasGenericParameters)
  115. {
  116. return;
  117. }
  118. ITypeDefOrRef baseType = typeDef.BaseType;
  119. if (baseType != null && baseType.TryGetGenericInstSig() != null)
  120. {
  121. GenericClass gc = GenericClass.ResolveClass((TypeSpec)baseType, null);
  122. TryAddAndWalkGenericType(gc);
  123. }
  124. }
  125. private void Prepare()
  126. {
  127. // 将所有非泛型函数全部加入函数列表,同时立马walk这些method。
  128. // 后续迭代中将只遍历MethodSpec
  129. foreach (var ass in _assemblyCollector.GetLoadedModulesOfRootAssemblies())
  130. {
  131. foreach (TypeDef typeDef in ass.GetTypes())
  132. {
  133. WalkType(typeDef);
  134. }
  135. for (uint rid = 1, n = ass.Metadata.TablesStream.TypeSpecTable.Rows; rid <= n; rid++)
  136. {
  137. var ts = ass.ResolveTypeSpec(rid);
  138. var cs = GenericClass.ResolveClass(ts, null)?.ToGenericShare();
  139. if (cs != null)
  140. {
  141. TryAddAndWalkGenericType(cs);
  142. }
  143. }
  144. for (uint rid = 1, n = ass.Metadata.TablesStream.MethodSpecTable.Rows; rid <= n; rid++)
  145. {
  146. var ms = ass.ResolveMethodSpec(rid);
  147. var gm = GenericMethod.ResolveMethod(ms, null)?.ToGenericShare();
  148. TryAddMethodNotWalkType(gm);
  149. }
  150. }
  151. Debug.Log($"PostPrepare genericTypes:{_genericTypes.Count} genericMethods:{_genericMethods.Count} newMethods:{_newMethods.Count}");
  152. }
  153. private void RecursiveCollect()
  154. {
  155. for (int i = 0; i < _maxInterationCount && _newMethods.Count > 0; i++)
  156. {
  157. var temp = _processingMethods;
  158. _processingMethods = _newMethods;
  159. _newMethods = temp;
  160. _newMethods.Clear();
  161. foreach (var method in _processingMethods)
  162. {
  163. _methodReferenceAnalyzer.WalkMethod(method.Method, method.KlassInst, method.MethodInst);
  164. }
  165. Debug.Log($"iteration:[{i}] genericClass:{_genericTypes.Count} genericMethods:{_genericMethods.Count} newMethods:{_newMethods.Count}");
  166. }
  167. }
  168. private bool IsNotShareableAOTGenericType(TypeDef typeDef)
  169. {
  170. if (!IsAotType(typeDef))
  171. {
  172. return false;
  173. }
  174. return typeDef.GenericParameters.Any(c => !c.HasReferenceTypeConstraint);
  175. }
  176. private bool IsNotShareableAOTGenericMethod(MethodDef method)
  177. {
  178. if (!IsAotGenericMethod(method))
  179. {
  180. return false;
  181. }
  182. return method.GenericParameters.Concat(method.DeclaringType.GenericParameters).Any(c => !c.HasReferenceTypeConstraint);
  183. }
  184. private void FilterAOTGenericTypeAndMethods()
  185. {
  186. ConstraintContext cc = this.ConstraintContext;
  187. AotGenericTypes.AddRange(_genericTypes.Where(type => IsNotShareableAOTGenericType(type.Type)).Select(gc => cc.ApplyConstraints(gc)));
  188. AotGenericMethods.AddRange(_genericMethods.Where(method => IsNotShareableAOTGenericMethod(method.Method)).Select(gm => cc.ApplyConstraints(gm)));
  189. }
  190. public void Run()
  191. {
  192. Prepare();
  193. RecursiveCollect();
  194. FilterAOTGenericTypeAndMethods();
  195. }
  196. }
  197. }