MethodBridgeGenerator.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  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 System.Threading.Tasks;
  8. using UnityEditor;
  9. using UnityEngine;
  10. namespace HybridCLR.Generators.MethodBridge
  11. {
  12. public class TypeGenInfo
  13. {
  14. public Type Type { get; set; }
  15. public List<MethodInfo> GenericMethods { get; set; }
  16. }
  17. public class MethodBridgeGeneratorOptions
  18. {
  19. public List<Assembly> Assemblies { get; set; }
  20. public PlatformABI CallConvention { get; set; }
  21. public string OutputFile { get; set; }
  22. }
  23. public class MethodBridgeGenerator
  24. {
  25. private readonly List<Assembly> _assemblies;
  26. private readonly PlatformABI _callConvention;
  27. private readonly string _outputFile;
  28. private readonly IPlatformAdaptor _platformAdaptor;
  29. private readonly HashSet<MethodBridgeSig> _callMethodSet = new HashSet<MethodBridgeSig>();
  30. private List<MethodBridgeSig> _callMethodList;
  31. private readonly HashSet<MethodBridgeSig> _invokeMethodSet = new HashSet<MethodBridgeSig>();
  32. private List<MethodBridgeSig> _invokeMethodList;
  33. public MethodBridgeGenerator(MethodBridgeGeneratorOptions options)
  34. {
  35. _assemblies = options.Assemblies;
  36. _callConvention = options.CallConvention;
  37. _outputFile = options.OutputFile;
  38. _platformAdaptor = CreatePlatformAdaptor(options.CallConvention);
  39. }
  40. private static IPlatformAdaptor CreatePlatformAdaptor(PlatformABI type)
  41. {
  42. return type switch
  43. {
  44. PlatformABI.Universal32 => new PlatformAdaptor_Universal32(),
  45. PlatformABI.Universal64 => new PlatformAdaptor_Universal64(),
  46. PlatformABI.Arm64 => new PlatformAdaptor_Arm64(),
  47. _ => throw new NotSupportedException(),
  48. };
  49. }
  50. private string GetTemplateFile()
  51. {
  52. string tplFile = _callConvention switch
  53. {
  54. PlatformABI.Universal32 => "Universal32",
  55. PlatformABI.Universal64 => "Universal64",
  56. PlatformABI.Arm64 => "Arm64",
  57. _ => throw new NotSupportedException(),
  58. };
  59. return $"{Application.dataPath}/Editor/HybridCLR/Generators/Templates/MethodBridge_{tplFile}.cpp";
  60. }
  61. public IEnumerable<TypeGenInfo> GetGenerateTypes()
  62. {
  63. return new List<TypeGenInfo>();
  64. }
  65. private MethodBridgeSig CreateMethodBridgeSig(bool isStatic, ParameterInfo returnType, ParameterInfo[] parameters)
  66. {
  67. var paramInfos = new List<ParamInfo>();
  68. if (!isStatic)
  69. {
  70. // FIXME arm32 is s_i4u4
  71. paramInfos.Add(new ParamInfo() { Type = _platformAdaptor.IsArch32 ? TypeInfo.s_i4u4 : TypeInfo.s_i8u8 });
  72. }
  73. foreach (var paramInfo in parameters)
  74. {
  75. paramInfos.Add(new ParamInfo() { Type = _platformAdaptor.CreateTypeInfo(paramInfo.ParameterType, false) });
  76. }
  77. var mbs = new MethodBridgeSig()
  78. {
  79. ReturnInfo = new ReturnInfo() { Type = returnType != null ? _platformAdaptor.CreateTypeInfo(returnType.ParameterType, true) : TypeInfo.s_void },
  80. ParamInfos = paramInfos,
  81. };
  82. return mbs;
  83. }
  84. private void AddCallMethod(MethodBridgeSig method)
  85. {
  86. if (_callMethodSet.Add(method))
  87. {
  88. method.Init();
  89. }
  90. }
  91. private void AddInvokeMethod(MethodBridgeSig method)
  92. {
  93. if (_invokeMethodSet.Add(method))
  94. {
  95. method.Init();
  96. }
  97. }
  98. private void ScanType(Type type)
  99. {
  100. if (type.IsGenericTypeDefinition)
  101. {
  102. return;
  103. }
  104. var typeDel = typeof(MulticastDelegate);
  105. if (typeDel.IsAssignableFrom(type))
  106. {
  107. var method = type.GetMethod("Invoke");
  108. if (method == null)
  109. {
  110. //Debug.LogError($"delegate:{typeDel.FullName} Invoke not exists");
  111. return;
  112. }
  113. var instanceCallMethod = CreateMethodBridgeSig(false, method.ReturnParameter, method.GetParameters());
  114. AddCallMethod(instanceCallMethod);
  115. var staticCallMethod = CreateMethodBridgeSig(true, method.ReturnParameter, method.GetParameters());
  116. AddCallMethod(staticCallMethod);
  117. var invokeMethod = CreateMethodBridgeSig(true, method.ReturnParameter, method.GetParameters());
  118. AddInvokeMethod(invokeMethod);
  119. return;
  120. }
  121. foreach (var method in type.GetMethods(BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public
  122. | BindingFlags.NonPublic | BindingFlags.CreateInstance | BindingFlags.InvokeMethod | BindingFlags.FlattenHierarchy))
  123. {
  124. if (method.IsGenericMethodDefinition)
  125. {
  126. continue;
  127. }
  128. var callMethod = CreateMethodBridgeSig(method.IsStatic, method.ReturnParameter, method.GetParameters());
  129. AddCallMethod(callMethod);
  130. var invokeMethod = CreateMethodBridgeSig(true, method.ReturnParameter, method.GetParameters());
  131. AddInvokeMethod(invokeMethod);
  132. }
  133. foreach (var method in type.GetConstructors(BindingFlags.Instance | BindingFlags.Public
  134. | BindingFlags.NonPublic | BindingFlags.CreateInstance | BindingFlags.InvokeMethod | BindingFlags.FlattenHierarchy))
  135. {
  136. var callMethod = CreateMethodBridgeSig(false, null, method.GetParameters());
  137. AddCallMethod(callMethod);
  138. var invokeMethod = CreateMethodBridgeSig(true, null, method.GetParameters());
  139. AddInvokeMethod(invokeMethod);
  140. }
  141. foreach (var subType in type.GetNestedTypes(BindingFlags.Public | BindingFlags.NonPublic))
  142. {
  143. ScanType(subType);
  144. }
  145. }
  146. public void PrepareFromAssemblies()
  147. {
  148. foreach (var ass in _assemblies)
  149. {
  150. //Debug.Log("prepare assembly:" + ass.FullName);
  151. foreach (var type in ass.GetTypes())
  152. {
  153. ScanType(type);
  154. }
  155. }
  156. }
  157. public void PrepareCommon1()
  158. {
  159. // (void + int64 + float) * (int64 + float) * (0 - 20) = 120
  160. TypeInfo typeVoid = new TypeInfo(typeof(void), ParamOrReturnType.VOID);
  161. TypeInfo typeLong = new TypeInfo(typeof(long), ParamOrReturnType.I8_U8);
  162. TypeInfo typeDouble = new TypeInfo(typeof(double), ParamOrReturnType.R8);
  163. int maxParamCount = 20;
  164. foreach (var returnType in new TypeInfo[] { typeVoid, typeLong, typeDouble })
  165. {
  166. var rt = new ReturnInfo() { Type = returnType };
  167. foreach (var argType in new TypeInfo[] { typeLong, typeDouble })
  168. {
  169. for (int paramCount = 0; paramCount <= maxParamCount; paramCount++)
  170. {
  171. var paramInfos = new List<ParamInfo>();
  172. for (int i = 0; i < paramCount; i++)
  173. {
  174. paramInfos.Add(new ParamInfo() { Type = argType });
  175. }
  176. var mbs = new MethodBridgeSig() { ReturnInfo = rt, ParamInfos = paramInfos};
  177. AddCallMethod(mbs);
  178. }
  179. }
  180. }
  181. }
  182. public void PrepareCommon2()
  183. {
  184. // (void + int64 + float) * (int64 + float + sr) ^ (0 - 4) = 363
  185. TypeInfo typeVoid = new TypeInfo(typeof(void), ParamOrReturnType.VOID);
  186. TypeInfo typeLong = new TypeInfo(typeof(long), ParamOrReturnType.I8_U8);
  187. TypeInfo typeDouble = new TypeInfo(typeof(double), ParamOrReturnType.R8);
  188. int maxParamCount = 4;
  189. var argTypes = new TypeInfo[] { typeLong, typeDouble };
  190. int paramTypeNum = argTypes.Length;
  191. foreach (var returnType in new TypeInfo[] { typeVoid, typeLong, typeDouble })
  192. {
  193. var rt = new ReturnInfo() { Type = returnType };
  194. for(int paramCount = 1; paramCount <= maxParamCount; paramCount++)
  195. {
  196. int totalCombinationNum = (int)Math.Pow(paramTypeNum, paramCount);
  197. for (int k = 0; k < totalCombinationNum; k++)
  198. {
  199. var paramInfos = new List<ParamInfo>();
  200. int c = k;
  201. for(int i = 0; i < paramCount; i++)
  202. {
  203. paramInfos.Add(new ParamInfo { Type = argTypes[c % paramTypeNum] });
  204. c /= paramTypeNum;
  205. }
  206. var mbs = new MethodBridgeSig() { ReturnInfo = rt, ParamInfos = paramInfos };
  207. AddCallMethod(mbs);
  208. }
  209. }
  210. }
  211. }
  212. private void PrepareMethodsFromCustomeGenericTypes()
  213. {
  214. foreach (var type in GeneratorConfig.PrepareCustomGenericTypes())
  215. {
  216. ScanType(type);
  217. }
  218. }
  219. public void PrepareMethods()
  220. {
  221. PrepareCommon1();
  222. PrepareCommon2();
  223. PrepareMethodsFromCustomeGenericTypes();
  224. foreach(var methodSig in _platformAdaptor.IsArch32 ? GeneratorConfig.PrepareCustomMethodSignatures32() : GeneratorConfig.PrepareCustomMethodSignatures64())
  225. {
  226. var method = MethodBridgeSig.CreateBySignatuer(methodSig);
  227. AddCallMethod(method);
  228. AddInvokeMethod(method);
  229. }
  230. foreach(var method in _platformAdaptor.GetPreserveMethods())
  231. {
  232. AddCallMethod(method);
  233. AddInvokeMethod(method);
  234. }
  235. PrepareFromAssemblies();
  236. {
  237. var sortedMethods = new SortedDictionary<string, MethodBridgeSig>();
  238. foreach (var method in _callMethodSet)
  239. {
  240. sortedMethods.Add(method.CreateCallSigName(), method);
  241. }
  242. _callMethodList = sortedMethods.Values.ToList();
  243. }
  244. {
  245. var sortedMethods = new SortedDictionary<string, MethodBridgeSig>();
  246. foreach (var method in _invokeMethodSet)
  247. {
  248. sortedMethods.Add(method.CreateCallSigName(), method);
  249. }
  250. _invokeMethodList = sortedMethods.Values.ToList();
  251. }
  252. }
  253. public void Generate()
  254. {
  255. var frr = new FileRegionReplace(GetTemplateFile());
  256. List<string> lines = new List<string>(20_0000);
  257. Debug.LogFormat("== call method count:{0}", _callMethodList.Count);
  258. foreach(var method in _callMethodList)
  259. {
  260. _platformAdaptor.GenerateCall(method, lines);
  261. }
  262. Debug.LogFormat("== invoke method count:{0}", _invokeMethodList.Count);
  263. foreach (var method in _invokeMethodList)
  264. {
  265. _platformAdaptor.GenerateInvoke(method, lines);
  266. }
  267. _platformAdaptor.GenCallStub(_callMethodList, lines);
  268. _platformAdaptor.GenInvokeStub(_invokeMethodList, lines);
  269. frr.Replace("INVOKE_STUB", string.Join("\n", lines));
  270. Directory.CreateDirectory(Path.GetDirectoryName(_outputFile));
  271. frr.Commit(_outputFile);
  272. }
  273. }
  274. }