123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204 |
- using dnlib.DotNet;
- using HybridCLR.Editor.Meta;
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
- using UnityEngine;
- namespace HybridCLR.Editor.MethodBridge
- {
- public class Analyzer
- {
- public class Options
- {
- public AssemblyReferenceDeepCollector Collector { get; set; }
- public int MaxIterationCount { get; set; }
- }
- private readonly int _maxInterationCount;
- private readonly AssemblyReferenceDeepCollector _assemblyCollector;
- private readonly object _lock = new object();
- private readonly List<TypeDef> _typeDefs = new List<TypeDef>();
- private readonly HashSet<GenericClass> _genericTypes = new HashSet<GenericClass>();
- private readonly HashSet<GenericMethod> _genericMethods = new HashSet<GenericMethod>();
- private List<GenericMethod> _processingMethods = new List<GenericMethod>();
- private List<GenericMethod> _newMethods = new List<GenericMethod>();
- public IReadOnlyList<TypeDef> TypeDefs => _typeDefs;
- public IReadOnlyCollection<GenericClass> GenericTypes => _genericTypes;
- public IReadOnlyCollection<GenericMethod> GenericMethods => _genericMethods;
- private readonly MethodReferenceAnalyzer _methodReferenceAnalyzer;
- public Analyzer(Options options)
- {
- _maxInterationCount = options.MaxIterationCount;
- _assemblyCollector = options.Collector;
- _methodReferenceAnalyzer = new MethodReferenceAnalyzer(this.OnNewMethod);
- }
- private void TryAddAndWalkGenericType(GenericClass gc)
- {
- if (gc == null)
- {
- return;
- }
- lock(_lock)
- {
- gc = StandardizeClass(gc);
- if (_genericTypes.Add(gc))
- {
- WalkType(gc);
- }
- }
- }
- private GenericClass StandardizeClass(GenericClass gc)
- {
- TypeDef typeDef = gc.Type;
- ICorLibTypes corLibTypes = typeDef.Module.CorLibTypes;
- List<TypeSig> klassGenericParams = gc.KlassInst != null ? MetaUtil.ToShareTypeSigs(corLibTypes, gc.KlassInst) : (typeDef.GenericParameters.Count > 0 ? MetaUtil.CreateDefaultGenericParams(typeDef.Module, typeDef.GenericParameters.Count) : null);
- return new GenericClass(typeDef, klassGenericParams);
- }
- private GenericMethod StandardizeMethod(GenericMethod gm)
- {
- TypeDef typeDef = gm.Method.DeclaringType;
- ICorLibTypes corLibTypes = typeDef.Module.CorLibTypes;
- List<TypeSig> klassGenericParams = gm.KlassInst != null ? MetaUtil.ToShareTypeSigs(corLibTypes, gm.KlassInst) : (typeDef.GenericParameters.Count > 0 ? MetaUtil.CreateDefaultGenericParams(typeDef.Module, typeDef.GenericParameters.Count) : null);
- List<TypeSig> methodGenericParams = gm.MethodInst != null ? MetaUtil.ToShareTypeSigs(corLibTypes, gm.MethodInst) : (gm.Method.GenericParameters.Count > 0 ? MetaUtil.CreateDefaultGenericParams(typeDef.Module, gm.Method.GenericParameters.Count) : null);
- return new GenericMethod(gm.Method, klassGenericParams, methodGenericParams);
- }
- private void OnNewMethod(MethodDef methodDef, List<TypeSig> klassGenericInst, List<TypeSig> methodGenericInst, GenericMethod method)
- {
- lock(_lock)
- {
- method = StandardizeMethod(method);
- if (_genericMethods.Add(method))
- {
- _newMethods.Add(method);
- }
- if (method.KlassInst != null)
- {
- TryAddAndWalkGenericType(new GenericClass(method.Method.DeclaringType, method.KlassInst));
- }
- }
- }
- private void WalkType(GenericClass gc)
- {
- //Debug.Log($"typespec:{sig} {sig.GenericType} {sig.GenericType.TypeDefOrRef.ResolveTypeDef()}");
- //Debug.Log($"== walk generic type:{new GenericInstSig(gc.Type.ToTypeSig().ToClassOrValueTypeSig(), gc.KlassInst)}");
- ITypeDefOrRef baseType = gc.Type.BaseType;
- if (baseType != null && baseType.TryGetGenericInstSig() != null)
- {
- GenericClass parentType = GenericClass.ResolveClass((TypeSpec)baseType, new GenericArgumentContext(gc.KlassInst, null));
- TryAddAndWalkGenericType(parentType);
- }
- foreach (var method in gc.Type.Methods)
- {
- var gm = StandardizeMethod(new GenericMethod(method, gc.KlassInst, null));
- //Debug.Log($"add method:{gm.Method} {gm.KlassInst}");
-
- if (_genericMethods.Add(gm))
- {
- if (method.HasBody && method.Body.Instructions != null)
- {
- _newMethods.Add(gm);
- }
- }
- }
- }
- private void WalkType(TypeDef typeDef)
- {
- _typeDefs.Add(typeDef);
- ITypeDefOrRef baseType = typeDef.BaseType;
- if (baseType != null && baseType.TryGetGenericInstSig() != null)
- {
- GenericClass gc = GenericClass.ResolveClass((TypeSpec)baseType, null);
- TryAddAndWalkGenericType(gc);
- }
- foreach (var method in typeDef.Methods)
- {
- // 对于带泛型的参数,统一泛型共享为object
- var gm = StandardizeMethod(new GenericMethod(method, null, null));
- _genericMethods.Add(gm);
- }
- }
- private void Prepare()
- {
- // 将所有非泛型函数全部加入函数列表,同时立马walk这些method。
- // 后续迭代中将只遍历MethodSpec
- foreach (var ass in _assemblyCollector.GetLoadedModules())
- {
- foreach (TypeDef typeDef in ass.GetTypes())
- {
- WalkType(typeDef);
- }
- for (uint rid = 1, n = ass.Metadata.TablesStream.TypeSpecTable.Rows; rid <= n; rid++)
- {
- var ts = ass.ResolveTypeSpec(rid);
- var cs = GenericClass.ResolveClass(ts, null);
- if (cs != null)
- {
- TryAddAndWalkGenericType(cs);
- }
- }
- for (uint rid = 1, n = ass.Metadata.TablesStream.MethodSpecTable.Rows; rid <= n; rid++)
- {
- var ms = ass.ResolveMethodSpec(rid);
- var gm = GenericMethod.ResolveMethod(ms, null)?.ToGenericShare();
- if (gm == null)
- {
- continue;
- }
- gm = StandardizeMethod(gm);
- if (_genericMethods.Add(gm))
- {
- _newMethods.Add(gm);
- }
- }
- }
- Debug.Log($"PostPrepare allMethods:{_genericMethods.Count} newMethods:{_newMethods.Count}");
- }
- private void RecursiveCollect()
- {
- for (int i = 0; i < _maxInterationCount && _newMethods.Count > 0; i++)
- {
- var temp = _processingMethods;
- _processingMethods = _newMethods;
- _newMethods = temp;
- _newMethods.Clear();
- Task.WaitAll(_processingMethods.Select(method => Task.Run(() =>
- {
- _methodReferenceAnalyzer.WalkMethod(method.Method, method.KlassInst, method.MethodInst);
- })).ToArray());
- Debug.Log($"iteration:[{i}] genericClass:{_genericTypes.Count} genericMethods:{_genericMethods.Count} newMethods:{_newMethods.Count}");
- }
- }
- public void Run()
- {
- Prepare();
- RecursiveCollect();
- }
- }
- }
|