Generator.cs 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. using dnlib.DotNet;
  2. using HybridCLR.Editor.ABI;
  3. using HybridCLR.Editor.Meta;
  4. using HybridCLR.Editor.Template;
  5. using System;
  6. using System.Collections.Generic;
  7. using System.IO;
  8. using System.Linq;
  9. using System.Reflection;
  10. using System.Text;
  11. using System.Threading.Tasks;
  12. using UnityEditor;
  13. using UnityEngine;
  14. using TypeInfo = HybridCLR.Editor.ABI.TypeInfo;
  15. namespace HybridCLR.Editor.MethodBridge
  16. {
  17. public class Generator
  18. {
  19. public class Options
  20. {
  21. public PlatformABI PlatformABI { get; set; }
  22. public string TemplateCode { get; set; }
  23. public string OutputFile { get; set; }
  24. public IReadOnlyList<MethodDef> NotGenericMethods { get; set; }
  25. public IReadOnlyCollection<GenericMethod> GenericMethods { get; set; }
  26. }
  27. private PlatformABI _platformABI;
  28. private readonly IReadOnlyList<MethodDef> _notGenericMethods;
  29. private readonly IReadOnlyCollection<GenericMethod> _genericMethods;
  30. private readonly string _templateCode;
  31. private readonly string _outputFile;
  32. private readonly PlatformGeneratorBase _platformAdaptor;
  33. private readonly TypeCreatorBase _typeCreator;
  34. private readonly HashSet<MethodDesc> _managed2nativeMethodSet = new HashSet<MethodDesc>();
  35. private List<MethodDesc> _managed2nativeMethodList;
  36. private readonly HashSet<MethodDesc> _native2managedMethodSet = new HashSet<MethodDesc>();
  37. private List<MethodDesc> _native2managedMethodList;
  38. private readonly HashSet<MethodDesc> _adjustThunkMethodSet = new HashSet<MethodDesc>();
  39. private List<MethodDesc> _adjustThunkMethodList;
  40. public Generator(Options options)
  41. {
  42. _platformABI = options.PlatformABI;
  43. _notGenericMethods = options.NotGenericMethods;
  44. _genericMethods = options.GenericMethods;
  45. _templateCode = options.TemplateCode;
  46. _outputFile = options.OutputFile;
  47. _platformAdaptor = CreatePlatformAdaptor(options.PlatformABI);
  48. _typeCreator = TypeCreatorFactory.CreateTypeCreator(options.PlatformABI);
  49. }
  50. private static PlatformGeneratorBase CreatePlatformAdaptor(PlatformABI type)
  51. {
  52. switch (type)
  53. {
  54. case PlatformABI.Universal32: return new PlatformGeneratorUniversal32();
  55. case PlatformABI.Universal64: return new PlatformGeneratorUniversal64();
  56. case PlatformABI.Arm64: return new PlatformGeneratorArm64();
  57. case PlatformABI.WebGL32: return new PlatformGeneratorWebGL32();
  58. default: throw new NotSupportedException();
  59. }
  60. }
  61. private MethodDesc CreateMethodDesc(MethodDef methodDef, bool forceRemoveThis, TypeSig returnType, List<TypeSig> parameters)
  62. {
  63. var paramInfos = new List<ParamInfo>();
  64. if (forceRemoveThis && !methodDef.IsStatic)
  65. {
  66. parameters.RemoveAt(0);
  67. }
  68. foreach (var paramInfo in parameters)
  69. {
  70. paramInfos.Add(new ParamInfo() { Type = _typeCreator.CreateTypeInfo(paramInfo) });
  71. }
  72. var mbs = new MethodDesc()
  73. {
  74. MethodDef = methodDef,
  75. ReturnInfo = new ReturnInfo() { Type = returnType != null ? _typeCreator.CreateTypeInfo(returnType) : TypeInfo.s_void },
  76. ParamInfos = paramInfos,
  77. };
  78. _typeCreator.OptimizeMethod(mbs);
  79. return mbs;
  80. }
  81. private void AddManaged2NativeMethod(MethodDesc method)
  82. {
  83. method.Init();
  84. _managed2nativeMethodSet.Add(method);
  85. }
  86. private void AddNative2ManagedMethod(MethodDesc method)
  87. {
  88. method.Init();
  89. _native2managedMethodSet.Add(method);
  90. }
  91. private void AddAdjustThunkMethod(MethodDesc method)
  92. {
  93. method.Init();
  94. _adjustThunkMethodSet.Add(method);
  95. }
  96. private void ProcessMethod(MethodDef method, List<TypeSig> klassInst, List<TypeSig> methodInst)
  97. {
  98. if (method.IsPrivate || (method.IsAssembly && !method.IsPublic && !method.IsFamily))
  99. {
  100. return;
  101. }
  102. TypeSig returnType;
  103. List<TypeSig> parameters;
  104. if (klassInst == null && methodInst == null)
  105. {
  106. returnType = method.ReturnType;
  107. parameters = method.Parameters.Select(p => p.Type).ToList();
  108. }
  109. else
  110. {
  111. var gc = new GenericArgumentContext(klassInst, methodInst);
  112. returnType = MetaUtil.Inflate(method.ReturnType, gc);
  113. parameters = method.Parameters.Select(p => MetaUtil.Inflate(p.Type, gc)).ToList();
  114. }
  115. var m2nMethod = CreateMethodDesc(method, false, returnType, parameters);
  116. AddManaged2NativeMethod(m2nMethod);
  117. if (method.IsVirtual)
  118. {
  119. if (method.DeclaringType.IsInterface)
  120. {
  121. AddAdjustThunkMethod(m2nMethod);
  122. }
  123. //var adjustThunkMethod = CreateMethodDesc(method, true, returnType, parameters);
  124. AddNative2ManagedMethod(m2nMethod);
  125. }
  126. if (method.Name == "Invoke" && method.DeclaringType.IsDelegate)
  127. {
  128. var openMethod = CreateMethodDesc(method, true, returnType, parameters);
  129. AddNative2ManagedMethod(openMethod);
  130. }
  131. }
  132. public void PrepareMethods()
  133. {
  134. foreach(var method in _notGenericMethods)
  135. {
  136. ProcessMethod(method, null, null);
  137. }
  138. foreach(var method in _genericMethods)
  139. {
  140. ProcessMethod(method.Method, method.KlassInst, method.MethodInst);
  141. }
  142. {
  143. var sortedMethods = new SortedDictionary<string, MethodDesc>();
  144. foreach (var method in _managed2nativeMethodSet)
  145. {
  146. sortedMethods.Add(method.CreateCallSigName(), method);
  147. }
  148. _managed2nativeMethodList = sortedMethods.Values.ToList();
  149. }
  150. {
  151. var sortedMethods = new SortedDictionary<string, MethodDesc>();
  152. foreach (var method in _native2managedMethodSet)
  153. {
  154. sortedMethods.Add(method.CreateCallSigName(), method);
  155. }
  156. _native2managedMethodList = sortedMethods.Values.ToList();
  157. }
  158. {
  159. var sortedMethods = new SortedDictionary<string, MethodDesc>();
  160. foreach (var method in _adjustThunkMethodSet)
  161. {
  162. sortedMethods.Add(method.CreateCallSigName(), method);
  163. }
  164. _adjustThunkMethodList = sortedMethods.Values.ToList();
  165. }
  166. }
  167. public void Generate()
  168. {
  169. var frr = new FileRegionReplace(_templateCode.Replace("{PLATFORM_ABI}", ABIUtil.GetHybridCLRPlatformMacro(_platformABI)));
  170. List<string> lines = new List<string>(20_0000);
  171. Debug.LogFormat("== managed2native:{0} native2managed:{1} adjustThunk:{2}",
  172. _managed2nativeMethodList.Count, _native2managedMethodList.Count, _adjustThunkMethodList.Count);
  173. foreach(var method in _managed2nativeMethodList)
  174. {
  175. _platformAdaptor.GenerateManaged2NativeMethod(method, lines);
  176. }
  177. _platformAdaptor.GenerateManaged2NativeStub(_managed2nativeMethodList, lines);
  178. foreach (var method in _native2managedMethodList)
  179. {
  180. _platformAdaptor.GenerateNative2ManagedMethod(method, lines);
  181. }
  182. _platformAdaptor.GenerateNative2ManagedStub(_native2managedMethodList, lines);
  183. foreach (var method in _adjustThunkMethodList)
  184. {
  185. _platformAdaptor.GenerateAdjustThunkMethod(method, lines);
  186. }
  187. _platformAdaptor.GenerateAdjustThunkStub(_adjustThunkMethodList, lines);
  188. frr.Replace("CODE", string.Join("\n", lines));
  189. Directory.CreateDirectory(Path.GetDirectoryName(_outputFile));
  190. frr.Commit(_outputFile);
  191. }
  192. }
  193. }