BindingCodeGenerator.cs 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Reflection;
  4. using System.Linq;
  5. using System.Text;
  6. using System.Text.RegularExpressions;
  7. using ILRuntime.Runtime.Enviorment;
  8. using ILRuntime.Other;
  9. namespace ILRuntime.Runtime.CLRBinding
  10. {
  11. public class BindingCodeGenerator
  12. {
  13. public static void GenerateBindingCode(List<Type> types, string outputPath,
  14. HashSet<MethodBase> excludeMethods = null, HashSet<FieldInfo> excludeFields = null,
  15. List<Type> valueTypeBinders = null, List<Type> delegateTypes = null)
  16. {
  17. if (!System.IO.Directory.Exists(outputPath))
  18. System.IO.Directory.CreateDirectory(outputPath);
  19. string[] oldFiles = System.IO.Directory.GetFiles(outputPath, "*.cs");
  20. foreach (var i in oldFiles)
  21. {
  22. System.IO.File.Delete(i);
  23. }
  24. List<string> clsNames = new List<string>();
  25. foreach (var i in types)
  26. {
  27. string clsName, realClsName;
  28. bool isByRef;
  29. if (i.GetCustomAttributes(typeof(ObsoleteAttribute), true).Length > 0)
  30. continue;
  31. i.GetClassName(out clsName, out realClsName, out isByRef);
  32. clsNames.Add(clsName);
  33. using (System.IO.StreamWriter sw = new System.IO.StreamWriter(outputPath + "/" + clsName + ".cs", false, new UTF8Encoding(false)))
  34. {
  35. StringBuilder sb = new StringBuilder();
  36. sb.Append(@"using System;
  37. using System.Collections.Generic;
  38. using System.Reflection;
  39. using System.Runtime.InteropServices;
  40. using ILRuntime.CLR.TypeSystem;
  41. using ILRuntime.CLR.Method;
  42. using ILRuntime.Runtime.Enviorment;
  43. using ILRuntime.Runtime.Intepreter;
  44. using ILRuntime.Runtime.Stack;
  45. using ILRuntime.Reflection;
  46. using ILRuntime.CLR.Utils;
  47. namespace ILRuntime.Runtime.Generated
  48. {
  49. unsafe class ");
  50. sb.AppendLine(clsName);
  51. sb.Append(@" {
  52. public static void Register(ILRuntime.Runtime.Enviorment.AppDomain app)
  53. {
  54. ");
  55. string flagDef = " BindingFlags flag = BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly;";
  56. string methodDef = " MethodBase method;";
  57. string methodsDef = " MethodInfo[] methods = type.GetMethods(flag).Where(t => !t.IsGenericMethod).ToArray();";
  58. string fieldDef = " FieldInfo field;";
  59. string argsDef = " Type[] args;";
  60. string typeDef = string.Format(" Type type = typeof({0});", realClsName);
  61. bool needMethods;
  62. MethodInfo[] methods = i.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly);
  63. FieldInfo[] fields = i.GetFields(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly);
  64. string registerMethodCode = i.GenerateMethodRegisterCode(methods, excludeMethods, out needMethods);
  65. string registerFieldCode = i.GenerateFieldRegisterCode(fields, excludeFields);
  66. string registerValueTypeCode = i.GenerateValueTypeRegisterCode(realClsName);
  67. string registerMiscCode = i.GenerateMiscRegisterCode(realClsName, true, true);
  68. string commonCode = i.GenerateCommonCode(realClsName);
  69. ConstructorInfo[] ctors = i.GetConstructors(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly);
  70. string ctorRegisterCode = i.GenerateConstructorRegisterCode(ctors, excludeMethods);
  71. string methodWraperCode = i.GenerateMethodWraperCode(methods, realClsName, excludeMethods, valueTypeBinders, null);
  72. string fieldWraperCode = i.GenerateFieldWraperCode(fields, realClsName, excludeFields, valueTypeBinders, null);
  73. string cloneWraperCode = i.GenerateCloneWraperCode(fields, realClsName);
  74. string ctorWraperCode = i.GenerateConstructorWraperCode(ctors, realClsName, excludeMethods, valueTypeBinders);
  75. bool hasMethodCode = !string.IsNullOrEmpty(registerMethodCode);
  76. bool hasFieldCode = !string.IsNullOrEmpty(registerFieldCode);
  77. bool hasValueTypeCode = !string.IsNullOrEmpty(registerValueTypeCode);
  78. bool hasMiscCode = !string.IsNullOrEmpty(registerMiscCode);
  79. bool hasCtorCode = !string.IsNullOrEmpty(ctorRegisterCode);
  80. bool hasNormalMethod = methods.Where(x => !x.IsGenericMethod).Count() != 0;
  81. if ((hasMethodCode && hasNormalMethod) || hasFieldCode || hasCtorCode)
  82. sb.AppendLine(flagDef);
  83. if (hasMethodCode || hasCtorCode)
  84. sb.AppendLine(methodDef);
  85. if (hasFieldCode)
  86. sb.AppendLine(fieldDef);
  87. if (hasMethodCode || hasFieldCode || hasCtorCode)
  88. sb.AppendLine(argsDef);
  89. if (hasMethodCode || hasFieldCode || hasValueTypeCode || hasMiscCode || hasCtorCode)
  90. sb.AppendLine(typeDef);
  91. if (needMethods)
  92. sb.AppendLine(methodsDef);
  93. sb.AppendLine(registerMethodCode);
  94. sb.AppendLine(registerFieldCode);
  95. sb.AppendLine(registerValueTypeCode);
  96. sb.AppendLine(registerMiscCode);
  97. sb.AppendLine(ctorRegisterCode);
  98. sb.AppendLine(" }");
  99. sb.AppendLine();
  100. sb.AppendLine(commonCode);
  101. sb.AppendLine(methodWraperCode);
  102. sb.AppendLine(fieldWraperCode);
  103. sb.AppendLine(cloneWraperCode);
  104. sb.AppendLine(ctorWraperCode);
  105. sb.AppendLine(" }");
  106. sb.AppendLine("}");
  107. sw.Write(Regex.Replace(sb.ToString(), "(?<!\r)\n", "\r\n"));
  108. sw.Flush();
  109. }
  110. }
  111. var delegateClsNames = GenerateDelegateBinding(delegateTypes, outputPath);
  112. clsNames.AddRange(delegateClsNames);
  113. GenerateBindingInitializeScript(clsNames, valueTypeBinders, outputPath);
  114. }
  115. internal class CLRBindingGenerateInfo
  116. {
  117. public Type Type { get; set; }
  118. public HashSet<MethodInfo> Methods { get; set; }
  119. public HashSet<FieldInfo> Fields { get; set; }
  120. public HashSet<ConstructorInfo> Constructors { get; set; }
  121. public bool ArrayNeeded { get; set; }
  122. public bool DefaultInstanceNeeded { get; set; }
  123. public bool ValueTypeNeeded { get; set; }
  124. public bool NeedGenerate
  125. {
  126. get
  127. {
  128. if (Methods.Count == 0 && Constructors.Count == 0 && Fields.Count == 0 && !ArrayNeeded && !DefaultInstanceNeeded && !ValueTypeNeeded)
  129. return false;
  130. else
  131. {
  132. //Making CLRBinding for such types makes no sense
  133. if (Type == typeof(Delegate) || Type == typeof(System.Runtime.CompilerServices.RuntimeHelpers))
  134. return false;
  135. return true;
  136. }
  137. }
  138. }
  139. }
  140. internal class FileNameEqualityComparer : IEqualityComparer<string>
  141. {
  142. public bool Equals(string x, string y)
  143. {
  144. // handle null cases first
  145. if (x == null)
  146. return (y == null);
  147. // x != null
  148. else if (y == null)
  149. return false;
  150. return x.Equals(y, StringComparison.OrdinalIgnoreCase);
  151. }
  152. public int GetHashCode(string obj)
  153. {
  154. int hashCode = 0;
  155. if (obj != null)
  156. {
  157. hashCode = obj.GetHashCode();
  158. }
  159. return hashCode;
  160. }
  161. }
  162. public static void GenerateBindingCode(ILRuntime.Runtime.Enviorment.AppDomain domain, string outputPath,
  163. List<Type> valueTypeBinders = null, List<Type> delegateTypes = null,
  164. params string[] excludeFiles)
  165. {
  166. if (domain == null)
  167. return;
  168. if (!System.IO.Directory.Exists(outputPath))
  169. System.IO.Directory.CreateDirectory(outputPath);
  170. Dictionary<Type, CLRBindingGenerateInfo> infos = new Dictionary<Type, CLRBindingGenerateInfo>(new ByReferenceKeyComparer<Type>());
  171. CrawlAppdomain(domain, infos);
  172. string[] oldFiles = System.IO.Directory.GetFiles(outputPath, "*.cs");
  173. foreach (var i in oldFiles)
  174. {
  175. System.IO.File.Delete(i);
  176. }
  177. if (valueTypeBinders == null)
  178. valueTypeBinders = new List<Type>(domain.ValueTypeBinders.Keys);
  179. HashSet<MethodBase> excludeMethods = null;
  180. HashSet<FieldInfo> excludeFields = null;
  181. HashSet<string> files = new HashSet<string>();
  182. List<string> clsNames = new List<string>();
  183. FileNameEqualityComparer fileNameEqualityComparer = new FileNameEqualityComparer();
  184. foreach (var info in infos)
  185. {
  186. if (!info.Value.NeedGenerate)
  187. continue;
  188. Type i = info.Value.Type;
  189. //CLR binding for delegate is important for cross domain invocation,so it should be generated
  190. //if (i.BaseType == typeof(MulticastDelegate))
  191. // continue;
  192. string clsName, realClsName;
  193. bool isByRef;
  194. if (i.GetCustomAttributes(typeof(ObsoleteAttribute), true).Length > 0)
  195. continue;
  196. i.GetClassName(out clsName, out realClsName, out isByRef);
  197. if (excludeFiles.Contains(clsName))
  198. continue;
  199. int extraClsNameIndex = 0;
  200. string oClsName = clsName;
  201. while (clsNames.Contains(oClsName))
  202. {
  203. extraClsNameIndex++;
  204. oClsName = clsName + "_t" + extraClsNameIndex;
  205. }
  206. clsNames.Add(oClsName);
  207. clsName = oClsName;
  208. //File path length limit
  209. string oriFileName = outputPath + "/" + clsName;
  210. int len = Math.Min(oriFileName.Length, 100);
  211. if (len < oriFileName.Length)
  212. oriFileName = oriFileName.Substring(0, len);
  213. int extraNameIndex = 0;
  214. string oFileName = oriFileName;
  215. while (files.Contains(oFileName, fileNameEqualityComparer))
  216. {
  217. extraNameIndex++;
  218. oFileName = oriFileName + "_t" + extraNameIndex;
  219. }
  220. files.Add(oFileName);
  221. oFileName = oFileName + ".cs";
  222. using (System.IO.StreamWriter sw = new System.IO.StreamWriter(oFileName, false, new UTF8Encoding(false)))
  223. {
  224. StringBuilder sb = new StringBuilder();
  225. sb.Append(@"using System;
  226. using System.Collections.Generic;
  227. using System.Linq;
  228. using System.Reflection;
  229. using System.Runtime.InteropServices;
  230. using ILRuntime.CLR.TypeSystem;
  231. using ILRuntime.CLR.Method;
  232. using ILRuntime.Runtime.Enviorment;
  233. using ILRuntime.Runtime.Intepreter;
  234. using ILRuntime.Runtime.Stack;
  235. using ILRuntime.Reflection;
  236. using ILRuntime.CLR.Utils;
  237. namespace ILRuntime.Runtime.Generated
  238. {
  239. unsafe class ");
  240. sb.AppendLine(clsName);
  241. sb.Append(@" {
  242. public static void Register(ILRuntime.Runtime.Enviorment.AppDomain app)
  243. {
  244. ");
  245. string flagDef = " BindingFlags flag = BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly;";
  246. string methodDef = " MethodBase method;";
  247. string methodsDef = " MethodInfo[] methods = type.GetMethods(flag).Where(t => !t.IsGenericMethod).ToArray();";
  248. string fieldDef = " FieldInfo field;";
  249. string argsDef = " Type[] args;";
  250. string typeDef = string.Format(" Type type = typeof({0});", realClsName);
  251. bool needMethods;
  252. MethodInfo[] methods = info.Value.Methods.ToArray();
  253. FieldInfo[] fields = info.Value.Fields.ToArray();
  254. string registerMethodCode = i.GenerateMethodRegisterCode(methods, excludeMethods, out needMethods);
  255. string registerFieldCode = fields.Length > 0 ? i.GenerateFieldRegisterCode(fields, excludeFields) : null;
  256. string registerValueTypeCode = info.Value.ValueTypeNeeded ? i.GenerateValueTypeRegisterCode(realClsName) : null;
  257. string registerMiscCode = i.GenerateMiscRegisterCode(realClsName, info.Value.DefaultInstanceNeeded, info.Value.ArrayNeeded);
  258. string commonCode = i.GenerateCommonCode(realClsName);
  259. ConstructorInfo[] ctors = info.Value.Constructors.ToArray();
  260. string ctorRegisterCode = i.GenerateConstructorRegisterCode(ctors, excludeMethods);
  261. string methodWraperCode = i.GenerateMethodWraperCode(methods, realClsName, excludeMethods, valueTypeBinders, domain);
  262. string fieldWraperCode = fields.Length > 0 ? i.GenerateFieldWraperCode(fields, realClsName, excludeFields, valueTypeBinders, domain) : null;
  263. string cloneWraperCode = null;
  264. if (info.Value.ValueTypeNeeded)
  265. {
  266. //Memberwise clone should copy all fields
  267. var fs = i.GetFields(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly);
  268. cloneWraperCode = i.GenerateCloneWraperCode(fs, realClsName);
  269. }
  270. bool hasMethodCode = !string.IsNullOrEmpty(registerMethodCode);
  271. bool hasFieldCode = !string.IsNullOrEmpty(registerFieldCode);
  272. bool hasValueTypeCode = !string.IsNullOrEmpty(registerValueTypeCode);
  273. bool hasMiscCode = !string.IsNullOrEmpty(registerMiscCode);
  274. bool hasCtorCode = !string.IsNullOrEmpty(ctorRegisterCode);
  275. bool hasNormalMethod = methods.Where(x => !x.IsGenericMethod).Count() != 0;
  276. if ((hasMethodCode && hasNormalMethod) || hasFieldCode || hasCtorCode)
  277. sb.AppendLine(flagDef);
  278. if (hasMethodCode || hasCtorCode)
  279. sb.AppendLine(methodDef);
  280. if (hasFieldCode)
  281. sb.AppendLine(fieldDef);
  282. if (hasMethodCode || hasFieldCode || hasCtorCode)
  283. sb.AppendLine(argsDef);
  284. if (hasMethodCode || hasFieldCode || hasValueTypeCode || hasMiscCode || hasCtorCode)
  285. sb.AppendLine(typeDef);
  286. if (needMethods)
  287. sb.AppendLine(methodsDef);
  288. sb.AppendLine(registerMethodCode);
  289. if (fields.Length > 0)
  290. sb.AppendLine(registerFieldCode);
  291. if (info.Value.ValueTypeNeeded)
  292. sb.AppendLine(registerValueTypeCode);
  293. if (!string.IsNullOrEmpty(registerMiscCode))
  294. sb.AppendLine(registerMiscCode);
  295. sb.AppendLine(ctorRegisterCode);
  296. sb.AppendLine(" }");
  297. sb.AppendLine();
  298. sb.AppendLine(commonCode);
  299. sb.AppendLine(methodWraperCode);
  300. if (fields.Length > 0)
  301. sb.AppendLine(fieldWraperCode);
  302. if (info.Value.ValueTypeNeeded)
  303. sb.AppendLine(cloneWraperCode);
  304. string ctorWraperCode = i.GenerateConstructorWraperCode(ctors, realClsName, excludeMethods, valueTypeBinders);
  305. sb.AppendLine(ctorWraperCode);
  306. sb.AppendLine(" }");
  307. sb.AppendLine("}");
  308. sw.Write(Regex.Replace(sb.ToString(), "(?<!\r)\n", "\r\n"));
  309. sw.Flush();
  310. }
  311. }
  312. using (System.IO.StreamWriter sw = new System.IO.StreamWriter(outputPath + "/CLRBindings.cs", false, new UTF8Encoding(false)))
  313. {
  314. StringBuilder sb = new StringBuilder();
  315. sb.AppendLine(@"using System;
  316. using System.Collections.Generic;
  317. using System.Reflection;
  318. namespace ILRuntime.Runtime.Generated
  319. {
  320. class CLRBindings
  321. {");
  322. sb.Append(SmartBindText);
  323. sb.Append(@"
  324. /// <summary>
  325. /// Initialize the CLR binding, please invoke this AFTER CLR Redirection registration
  326. /// </summary>
  327. public static void Initialize(ILRuntime.Runtime.Enviorment.AppDomain app)
  328. {");
  329. foreach (var i in clsNames)
  330. {
  331. sb.Append(" ");
  332. sb.Append(i);
  333. sb.AppendLine(".Register(app);");
  334. }
  335. sb.AppendLine(@" }
  336. }
  337. }");
  338. sw.Write(Regex.Replace(sb.ToString(), "(?<!\r)\n", "\r\n"));
  339. }
  340. var delegateClsNames = GenerateDelegateBinding(delegateTypes, outputPath);
  341. clsNames.AddRange(delegateClsNames);
  342. GenerateBindingInitializeScript(clsNames, valueTypeBinders, outputPath);
  343. }
  344. static void PrewarmDomain(ILRuntime.Runtime.Enviorment.AppDomain domain)
  345. {
  346. var arr = domain.LoadedTypes.Values.ToArray();
  347. //Prewarm
  348. foreach (var type in arr)
  349. {
  350. if (type is CLR.TypeSystem.ILType)
  351. {
  352. if (type.HasGenericParameter)
  353. continue;
  354. var methods = type.GetMethods().ToList();
  355. foreach (var i in ((CLR.TypeSystem.ILType)type).GetConstructors())
  356. methods.Add(i);
  357. if (((CLR.TypeSystem.ILType)type).GetStaticConstroctor() != null)
  358. methods.Add(((CLR.TypeSystem.ILType)type).GetStaticConstroctor());
  359. foreach (var j in methods)
  360. {
  361. CLR.Method.ILMethod method = j as CLR.Method.ILMethod;
  362. if (method != null)
  363. {
  364. if (method.GenericParameterCount > 0 && !method.IsGenericInstance)
  365. continue;
  366. var body = method.Body;
  367. }
  368. }
  369. }
  370. }
  371. }
  372. internal static void CrawlAppdomain(ILRuntime.Runtime.Enviorment.AppDomain domain, Dictionary<Type, CLRBindingGenerateInfo> infos)
  373. {
  374. domain.SuppressStaticConstructor = true;
  375. //Prewarm
  376. PrewarmDomain(domain);
  377. //Prewarm twice to ensure GenericMethods are prewarmed properly
  378. PrewarmDomain(domain);
  379. var arr = domain.LoadedTypes.Values.ToArray();
  380. foreach (var type in arr)
  381. {
  382. if (type is CLR.TypeSystem.ILType)
  383. {
  384. if (type.TypeForCLR.IsByRef || type.HasGenericParameter)
  385. continue;
  386. var methods = type.GetMethods().ToList();
  387. foreach (var i in ((CLR.TypeSystem.ILType)type).GetConstructors())
  388. methods.Add(i);
  389. if (((CLR.TypeSystem.ILType)type).GetStaticConstroctor() != null)
  390. methods.Add(((CLR.TypeSystem.ILType)type).GetStaticConstroctor());
  391. foreach (var j in methods)
  392. {
  393. CLR.Method.ILMethod method = j as CLR.Method.ILMethod;
  394. if (method != null)
  395. {
  396. if (method.GenericParameterCount > 0 && !method.IsGenericInstance)
  397. continue;
  398. var body = method.Body;
  399. foreach (var ins in body)
  400. {
  401. switch (ins.Code)
  402. {
  403. case Intepreter.OpCodes.OpCodeEnum.Newobj:
  404. {
  405. CLR.Method.CLRMethod m = domain.GetMethod(ins.TokenInteger) as CLR.Method.CLRMethod;
  406. if (m != null)
  407. {
  408. if (m.DeclearingType.IsDelegate)
  409. continue;
  410. Type t = m.DeclearingType.TypeForCLR;
  411. CLRBindingGenerateInfo info;
  412. if (!infos.TryGetValue(t, out info))
  413. {
  414. info = CreateNewBindingInfo(t);
  415. infos[t] = info;
  416. }
  417. if (m.IsConstructor)
  418. info.Constructors.Add(m.ConstructorInfo);
  419. else
  420. info.Methods.Add(m.MethodInfo);
  421. }
  422. }
  423. break;
  424. case Intepreter.OpCodes.OpCodeEnum.Ldfld:
  425. case Intepreter.OpCodes.OpCodeEnum.Stfld:
  426. case Intepreter.OpCodes.OpCodeEnum.Ldflda:
  427. case Intepreter.OpCodes.OpCodeEnum.Ldsfld:
  428. case Intepreter.OpCodes.OpCodeEnum.Ldsflda:
  429. case Intepreter.OpCodes.OpCodeEnum.Stsfld:
  430. {
  431. var t = domain.GetType((int)(ins.TokenLong >> 32)) as CLR.TypeSystem.CLRType;
  432. if(t != null)
  433. {
  434. var fi = t.GetField((int)ins.TokenLong);
  435. if (fi != null && fi.IsPublic)
  436. {
  437. CLRBindingGenerateInfo info;
  438. if (!infos.TryGetValue(t.TypeForCLR, out info))
  439. {
  440. info = CreateNewBindingInfo(t.TypeForCLR);
  441. infos[t.TypeForCLR] = info;
  442. }
  443. if (ins.Code == Intepreter.OpCodes.OpCodeEnum.Stfld || ins.Code == Intepreter.OpCodes.OpCodeEnum.Stsfld)
  444. {
  445. if (t.IsValueType)
  446. {
  447. info.ValueTypeNeeded = true;
  448. info.DefaultInstanceNeeded = true;
  449. }
  450. }
  451. info.Fields.Add(fi);
  452. }
  453. }
  454. }
  455. break;
  456. case Intepreter.OpCodes.OpCodeEnum.Ldtoken:
  457. {
  458. if (ins.TokenInteger == 0)
  459. {
  460. var t = domain.GetType((int)(ins.TokenLong >> 32)) as CLR.TypeSystem.CLRType;
  461. if (t != null)
  462. {
  463. var fi = t.GetField((int)ins.TokenLong);
  464. if (fi != null)
  465. {
  466. CLRBindingGenerateInfo info;
  467. if (!infos.TryGetValue(t.TypeForCLR, out info))
  468. {
  469. info = CreateNewBindingInfo(t.TypeForCLR);
  470. infos[t.TypeForCLR] = info;
  471. }
  472. info.Fields.Add(fi);
  473. }
  474. }
  475. }
  476. }
  477. break;
  478. case Intepreter.OpCodes.OpCodeEnum.Newarr:
  479. {
  480. var t = domain.GetType(ins.TokenInteger) as CLR.TypeSystem.CLRType;
  481. if(t != null)
  482. {
  483. CLRBindingGenerateInfo info;
  484. if (!infos.TryGetValue(t.TypeForCLR, out info))
  485. {
  486. info = CreateNewBindingInfo(t.TypeForCLR);
  487. infos[t.TypeForCLR] = info;
  488. }
  489. info.ArrayNeeded = true;
  490. }
  491. }
  492. break;
  493. case Intepreter.OpCodes.OpCodeEnum.Call:
  494. case Intepreter.OpCodes.OpCodeEnum.Callvirt:
  495. {
  496. CLR.Method.CLRMethod m = domain.GetMethod(ins.TokenInteger) as CLR.Method.CLRMethod;
  497. if (m != null)
  498. {
  499. //Cannot explicit call base class's constructor directly
  500. if (m.IsConstructor && m.DeclearingType.CanAssignTo(((CLR.TypeSystem.ILType)type).FirstCLRBaseType))
  501. continue;
  502. if (m.IsConstructor)
  503. {
  504. if (!m.ConstructorInfo.IsPublic)
  505. continue;
  506. Type t = m.DeclearingType.TypeForCLR;
  507. CLRBindingGenerateInfo info;
  508. if (!infos.TryGetValue(t, out info))
  509. {
  510. info = CreateNewBindingInfo(t);
  511. infos[t] = info;
  512. }
  513. info.Constructors.Add(m.ConstructorInfo);
  514. }
  515. else
  516. {
  517. if (!m.MethodInfo.IsPublic)
  518. continue;
  519. Type t = m.DeclearingType.TypeForCLR;
  520. CLRBindingGenerateInfo info;
  521. if (!infos.TryGetValue(t, out info))
  522. {
  523. info = CreateNewBindingInfo(t);
  524. infos[t] = info;
  525. }
  526. info.Methods.Add(m.MethodInfo);
  527. }
  528. }
  529. }
  530. break;
  531. }
  532. }
  533. }
  534. }
  535. }
  536. }
  537. }
  538. internal static CLRBindingGenerateInfo CreateNewBindingInfo(Type t)
  539. {
  540. CLRBindingGenerateInfo info = new CLRBindingGenerateInfo();
  541. info.Type = t;
  542. info.Methods = new HashSet<MethodInfo>();
  543. info.Fields = new HashSet<FieldInfo>();
  544. info.Constructors = new HashSet<ConstructorInfo>();
  545. if (t.IsValueType)
  546. info.DefaultInstanceNeeded = true;
  547. return info;
  548. }
  549. internal static List<string> GenerateDelegateBinding(List<Type> types, string outputPath)
  550. {
  551. if (types == null)
  552. types = new List<Type>(0);
  553. List<string> clsNames = new List<string>();
  554. foreach (var i in types)
  555. {
  556. var mi = i.GetMethod("Invoke");
  557. var miParameters = mi.GetParameters();
  558. if (mi.ReturnType == typeof(void) && miParameters.Length == 0)
  559. continue;
  560. string clsName, realClsName, paramClsName, paramRealClsName;
  561. bool isByRef, paramIsByRef;
  562. i.GetClassName(out clsName, out realClsName, out isByRef);
  563. clsNames.Add(clsName);
  564. using (System.IO.StreamWriter sw = new System.IO.StreamWriter(outputPath + "/" + clsName + ".cs", false, new UTF8Encoding(false)))
  565. {
  566. StringBuilder sb = new StringBuilder();
  567. sb.Append(@"using System;
  568. using System.Collections.Generic;
  569. using System.Reflection;
  570. using System.Runtime.InteropServices;
  571. using ILRuntime.CLR.TypeSystem;
  572. using ILRuntime.CLR.Method;
  573. using ILRuntime.Runtime.Enviorment;
  574. using ILRuntime.Runtime.Intepreter;
  575. using ILRuntime.Runtime.Stack;
  576. using ILRuntime.Reflection;
  577. using ILRuntime.CLR.Utils;
  578. namespace ILRuntime.Runtime.Generated
  579. {
  580. unsafe class ");
  581. sb.AppendLine(clsName);
  582. sb.AppendLine(@" {
  583. public static void Register(ILRuntime.Runtime.Enviorment.AppDomain app)
  584. {");
  585. bool first = true;
  586. if (mi.ReturnType != typeof(void))
  587. {
  588. sb.Append(" app.DelegateManager.RegisterFunctionDelegate<");
  589. first = true;
  590. foreach (var j in miParameters)
  591. {
  592. if (first)
  593. {
  594. first = false;
  595. }
  596. else
  597. sb.Append(", ");
  598. j.ParameterType.GetClassName(out paramClsName, out paramRealClsName, out paramIsByRef);
  599. sb.Append(paramRealClsName);
  600. }
  601. if (!first)
  602. sb.Append(", ");
  603. mi.ReturnType.GetClassName(out paramClsName, out paramRealClsName, out paramIsByRef);
  604. sb.Append(paramRealClsName);
  605. sb.AppendLine("> ();");
  606. }
  607. else
  608. {
  609. sb.Append(" app.DelegateManager.RegisterMethodDelegate<");
  610. first = true;
  611. foreach (var j in miParameters)
  612. {
  613. if (first)
  614. {
  615. first = false;
  616. }
  617. else
  618. sb.Append(", ");
  619. j.ParameterType.GetClassName(out paramClsName, out paramRealClsName, out paramIsByRef);
  620. sb.Append(paramRealClsName);
  621. }
  622. sb.AppendLine("> ();");
  623. }
  624. sb.AppendLine();
  625. sb.Append(" app.DelegateManager.RegisterDelegateConvertor<");
  626. sb.Append(realClsName);
  627. sb.AppendLine(">((act) =>");
  628. sb.AppendLine(" {");
  629. sb.Append(" return new ");
  630. sb.Append(realClsName);
  631. sb.Append("((");
  632. first = true;
  633. foreach (var j in miParameters)
  634. {
  635. if (first)
  636. {
  637. first = false;
  638. }
  639. else
  640. sb.Append(", ");
  641. sb.Append(j.Name);
  642. }
  643. sb.AppendLine(") =>");
  644. sb.AppendLine(" {");
  645. if (mi.ReturnType != typeof(void))
  646. {
  647. sb.Append(" return ((Func<");
  648. first = true;
  649. foreach (var j in miParameters)
  650. {
  651. if (first)
  652. {
  653. first = false;
  654. }
  655. else
  656. sb.Append(", ");
  657. j.ParameterType.GetClassName(out paramClsName, out paramRealClsName, out paramIsByRef);
  658. sb.Append(paramRealClsName);
  659. }
  660. if (!first)
  661. sb.Append(", ");
  662. mi.ReturnType.GetClassName(out paramClsName, out paramRealClsName, out paramIsByRef);
  663. sb.Append(paramRealClsName);
  664. }
  665. else
  666. {
  667. sb.Append(" ((Action<");
  668. first = true;
  669. foreach (var j in miParameters)
  670. {
  671. if (first)
  672. {
  673. first = false;
  674. }
  675. else
  676. sb.Append(", ");
  677. j.ParameterType.GetClassName(out paramClsName, out paramRealClsName, out paramIsByRef);
  678. sb.Append(paramRealClsName);
  679. }
  680. }
  681. sb.Append(">)act)(");
  682. first = true;
  683. foreach (var j in miParameters)
  684. {
  685. if (first)
  686. {
  687. first = false;
  688. }
  689. else
  690. sb.Append(", ");
  691. sb.Append(j.Name);
  692. }
  693. sb.AppendLine(");");
  694. sb.AppendLine(" });");
  695. sb.AppendLine(" });");
  696. sb.AppendLine(" }");
  697. sb.AppendLine(" }");
  698. sb.AppendLine("}");
  699. sw.Write(Regex.Replace(sb.ToString(), "(?<!\r)\n", "\r\n"));
  700. sw.Flush();
  701. }
  702. }
  703. return clsNames;
  704. }
  705. static private string SmartBindText = @"
  706. //will auto register in unity
  707. #if UNITY_5_3_OR_NEWER
  708. [UnityEngine.RuntimeInitializeOnLoadMethod(UnityEngine.RuntimeInitializeLoadType.BeforeSceneLoad)]
  709. #endif
  710. static private void RegisterBindingAction()
  711. {
  712. ILRuntime.Runtime.CLRBinding.CLRBindingUtils.RegisterBindingAction(Initialize);
  713. }
  714. ";
  715. internal static void GenerateBindingInitializeScript(List<string> clsNames, List<Type> valueTypeBinders, string outputPath)
  716. {
  717. if (!System.IO.Directory.Exists(outputPath))
  718. System.IO.Directory.CreateDirectory(outputPath);
  719. using (System.IO.StreamWriter sw = new System.IO.StreamWriter(outputPath + "/CLRBindings.cs", false, new UTF8Encoding(false)))
  720. {
  721. StringBuilder sb = new StringBuilder();
  722. sb.Append(@"using System;
  723. using System.Collections.Generic;
  724. using System.Reflection;
  725. namespace ILRuntime.Runtime.Generated
  726. {
  727. class CLRBindings
  728. {
  729. ");
  730. sb.Append(SmartBindText);
  731. if (valueTypeBinders != null)
  732. {
  733. sb.AppendLine();
  734. foreach (var i in valueTypeBinders)
  735. {
  736. string clsName, realClsName;
  737. bool isByRef;
  738. i.GetClassName(out clsName, out realClsName, out isByRef);
  739. sb.AppendLine(string.Format(" internal static ILRuntime.Runtime.Enviorment.ValueTypeBinder<{0}> s_{1}_Binder = null;", realClsName, clsName));
  740. }
  741. sb.AppendLine();
  742. }
  743. sb.AppendLine(@" /// <summary>
  744. /// Initialize the CLR binding, please invoke this AFTER CLR Redirection registration
  745. /// </summary>
  746. public static void Initialize(ILRuntime.Runtime.Enviorment.AppDomain app)
  747. {");
  748. if (clsNames != null)
  749. {
  750. foreach (var i in clsNames)
  751. {
  752. sb.Append(" ");
  753. sb.Append(i);
  754. sb.AppendLine(".Register(app);");
  755. }
  756. }
  757. if (valueTypeBinders != null && valueTypeBinders.Count > 0)
  758. {
  759. sb.AppendLine();
  760. sb.AppendLine(" ILRuntime.CLR.TypeSystem.CLRType __clrType = null;");
  761. foreach (var i in valueTypeBinders)
  762. {
  763. string clsName, realClsName;
  764. bool isByRef;
  765. i.GetClassName(out clsName, out realClsName, out isByRef);
  766. sb.AppendLine(string.Format(" __clrType = (ILRuntime.CLR.TypeSystem.CLRType)app.GetType (typeof({0}));", realClsName));
  767. sb.AppendLine(string.Format(" s_{0}_Binder = __clrType.ValueTypeBinder as ILRuntime.Runtime.Enviorment.ValueTypeBinder<{1}>;", clsName, realClsName));
  768. }
  769. }
  770. sb.AppendLine(@" }");
  771. sb.AppendLine(@"
  772. /// <summary>
  773. /// Release the CLR binding, please invoke this BEFORE ILRuntime Appdomain destroy
  774. /// </summary>
  775. public static void Shutdown(ILRuntime.Runtime.Enviorment.AppDomain app)
  776. {");
  777. if (valueTypeBinders != null)
  778. {
  779. foreach (var i in valueTypeBinders)
  780. {
  781. string clsName, realClsName;
  782. bool isByRef;
  783. i.GetClassName(out clsName, out realClsName, out isByRef);
  784. sb.AppendLine(string.Format(" s_{0}_Binder = null;", clsName));
  785. }
  786. }
  787. sb.AppendLine(@" }");
  788. sb.AppendLine(@" }
  789. }");
  790. sw.Write(Regex.Replace(sb.ToString(), "(?<!\r)\n", "\r\n"));
  791. }
  792. }
  793. }
  794. }