Generator.cs 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643
  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.ComponentModel.DataAnnotations;
  8. using System.IO;
  9. using System.Linq;
  10. using System.Reflection;
  11. using System.Text;
  12. using System.Threading.Tasks;
  13. using UnityEditor;
  14. using UnityEngine;
  15. using TypeInfo = HybridCLR.Editor.ABI.TypeInfo;
  16. namespace HybridCLR.Editor.MethodBridge
  17. {
  18. public class Generator
  19. {
  20. public class Options
  21. {
  22. public string TemplateCode { get; set; }
  23. public string OutputFile { get; set; }
  24. public IReadOnlyCollection<GenericMethod> GenericMethods { get; set; }
  25. }
  26. private readonly List<GenericMethod> _genericMethods;
  27. private readonly string _templateCode;
  28. private readonly string _outputFile;
  29. private readonly TypeCreator _typeCreator;
  30. private readonly HashSet<MethodDesc> _managed2nativeMethodSet = new HashSet<MethodDesc>();
  31. private readonly HashSet<MethodDesc> _native2managedMethodSet = new HashSet<MethodDesc>();
  32. private readonly HashSet<MethodDesc> _adjustThunkMethodSet = new HashSet<MethodDesc>();
  33. public Generator(Options options)
  34. {
  35. List<(GenericMethod, string)> genericMethodInfo = options.GenericMethods.Select(m => (m, m.ToString())).ToList();
  36. genericMethodInfo.Sort((a, b) => string.CompareOrdinal(a.Item2, b.Item2));
  37. _genericMethods = genericMethodInfo.Select(m => m.Item1).ToList();
  38. _templateCode = options.TemplateCode;
  39. _outputFile = options.OutputFile;
  40. _typeCreator = new TypeCreator();
  41. }
  42. private readonly Dictionary<string, TypeInfo> _sig2Types = new Dictionary<string, TypeInfo>();
  43. private TypeInfo GetSharedTypeInfo(TypeSig type)
  44. {
  45. var typeInfo = _typeCreator.CreateTypeInfo(type);
  46. if (!typeInfo.IsStruct)
  47. {
  48. return typeInfo;
  49. }
  50. string sigName = ToFullName(typeInfo.Klass);
  51. if (!_sig2Types.TryGetValue(sigName, out var sharedTypeInfo))
  52. {
  53. sharedTypeInfo = typeInfo;
  54. _sig2Types.Add(sigName, sharedTypeInfo);
  55. }
  56. return sharedTypeInfo;
  57. }
  58. private MethodDesc CreateMethodDesc(MethodDef methodDef, bool forceRemoveThis, TypeSig returnType, List<TypeSig> parameters)
  59. {
  60. var paramInfos = new List<ParamInfo>();
  61. if (forceRemoveThis && !methodDef.IsStatic)
  62. {
  63. parameters.RemoveAt(0);
  64. }
  65. if (returnType.ContainsGenericParameter)
  66. {
  67. throw new Exception($"[PreservedMethod] method:{methodDef} has generic parameters");
  68. }
  69. foreach (var paramInfo in parameters)
  70. {
  71. if (paramInfo.ContainsGenericParameter)
  72. {
  73. throw new Exception($"[PreservedMethod] method:{methodDef} has generic parameters");
  74. }
  75. paramInfos.Add(new ParamInfo() { Type = GetSharedTypeInfo(paramInfo) });
  76. }
  77. var mbs = new MethodDesc()
  78. {
  79. MethodDef = methodDef,
  80. ReturnInfo = new ReturnInfo() { Type = returnType != null ? GetSharedTypeInfo(returnType) : TypeInfo.s_void },
  81. ParamInfos = paramInfos,
  82. };
  83. return mbs;
  84. }
  85. private void AddManaged2NativeMethod(MethodDesc method)
  86. {
  87. method.Init();
  88. _managed2nativeMethodSet.Add(method);
  89. }
  90. private void AddNative2ManagedMethod(MethodDesc method)
  91. {
  92. method.Init();
  93. _native2managedMethodSet.Add(method);
  94. }
  95. private void AddAdjustThunkMethod(MethodDesc method)
  96. {
  97. method.Init();
  98. _adjustThunkMethodSet.Add(method);
  99. }
  100. private void ProcessMethod(MethodDef method, List<TypeSig> klassInst, List<TypeSig> methodInst)
  101. {
  102. if (method.IsPrivate || (method.IsAssembly && !method.IsPublic && !method.IsFamily))
  103. {
  104. if (klassInst == null && methodInst == null)
  105. {
  106. return;
  107. }
  108. else
  109. {
  110. //Debug.Log($"[PreservedMethod] method:{method}");
  111. }
  112. }
  113. ICorLibTypes corLibTypes = method.Module.CorLibTypes;
  114. TypeSig returnType;
  115. List<TypeSig> parameters;
  116. if (klassInst == null && methodInst == null)
  117. {
  118. if (method.HasGenericParameters)
  119. {
  120. throw new Exception($"[PreservedMethod] method:{method} has generic parameters");
  121. }
  122. returnType = MetaUtil.ToShareTypeSig(corLibTypes, method.ReturnType);
  123. parameters = method.Parameters.Select(p => MetaUtil.ToShareTypeSig(corLibTypes, p.Type)).ToList();
  124. }
  125. else
  126. {
  127. var gc = new GenericArgumentContext(klassInst, methodInst);
  128. returnType = MetaUtil.ToShareTypeSig(corLibTypes, MetaUtil.Inflate(method.ReturnType, gc));
  129. parameters = method.Parameters.Select(p => MetaUtil.ToShareTypeSig(corLibTypes, MetaUtil.Inflate(p.Type, gc))).ToList();
  130. }
  131. var m2nMethod = CreateMethodDesc(method, false, returnType, parameters);
  132. AddManaged2NativeMethod(m2nMethod);
  133. if (method.IsVirtual)
  134. {
  135. if (method.DeclaringType.IsInterface)
  136. {
  137. AddAdjustThunkMethod(m2nMethod);
  138. }
  139. //var adjustThunkMethod = CreateMethodDesc(method, true, returnType, parameters);
  140. AddNative2ManagedMethod(m2nMethod);
  141. }
  142. if (method.Name == "Invoke" && method.DeclaringType.IsDelegate)
  143. {
  144. var openMethod = CreateMethodDesc(method, true, returnType, parameters);
  145. AddNative2ManagedMethod(openMethod);
  146. }
  147. }
  148. public void PrepareMethods()
  149. {
  150. foreach(var method in _genericMethods)
  151. {
  152. ProcessMethod(method.Method, method.KlassInst, method.MethodInst);
  153. }
  154. }
  155. static void CheckUnique(IEnumerable<string> names)
  156. {
  157. var set = new HashSet<string>();
  158. foreach (var name in names)
  159. {
  160. if (!set.Add(name))
  161. {
  162. throw new Exception($"[CheckUnique] duplicate name:{name}");
  163. }
  164. }
  165. }
  166. public void Generate()
  167. {
  168. var frr = new FileRegionReplace(_templateCode);
  169. List<string> lines = new List<string>(20_0000);
  170. List<MethodDesc> managed2NativeMethodList = _managed2nativeMethodSet.ToList();
  171. managed2NativeMethodList.Sort((a, b) => string.CompareOrdinal(a.Sig, b.Sig));
  172. List<MethodDesc> native2ManagedMethodList = _native2managedMethodSet.ToList();
  173. native2ManagedMethodList.Sort((a, b) => string.CompareOrdinal(a.Sig, b.Sig));
  174. List<MethodDesc> adjustThunkMethodList = _adjustThunkMethodSet.ToList();
  175. adjustThunkMethodList.Sort((a, b) => string.CompareOrdinal(a.Sig, b.Sig));
  176. Debug.LogFormat("== managed2native:{0} native2managed:{1} adjustThunk:{2}",
  177. managed2NativeMethodList.Count, native2ManagedMethodList.Count, adjustThunkMethodList.Count);
  178. var structTypeSet = new HashSet<TypeInfo>();
  179. CollectStructDefs(managed2NativeMethodList, structTypeSet);
  180. CollectStructDefs(native2ManagedMethodList, structTypeSet);
  181. CollectStructDefs(adjustThunkMethodList, structTypeSet);
  182. List<TypeInfo> structTypes = structTypeSet.ToList();
  183. structTypes.Sort((a, b) => a.TypeId - b.TypeId);
  184. var classInfos = new List<ClassInfo>();
  185. var classTypeSet = new HashSet<TypeInfo>();
  186. foreach (var type in structTypes)
  187. {
  188. GenerateClassInfo(type, classTypeSet, classInfos);
  189. }
  190. CheckUnique(structTypes.Select(t => ToFullName(t.Klass)));
  191. CheckUnique(structTypes.Select(t => t.CreateSigName()));
  192. GenerateStructDefines(classInfos, lines);
  193. GenerateStructureSignatureStub(structTypes, lines);
  194. foreach(var method in managed2NativeMethodList)
  195. {
  196. GenerateManaged2NativeMethod(method, lines);
  197. }
  198. GenerateManaged2NativeStub(managed2NativeMethodList, lines);
  199. foreach (var method in native2ManagedMethodList)
  200. {
  201. GenerateNative2ManagedMethod(method, lines);
  202. }
  203. GenerateNative2ManagedStub(native2ManagedMethodList, lines);
  204. foreach (var method in adjustThunkMethodList)
  205. {
  206. GenerateAdjustThunkMethod(method, lines);
  207. }
  208. GenerateAdjustThunkStub(adjustThunkMethodList, lines);
  209. frr.Replace("CODE", string.Join("\n", lines));
  210. Directory.CreateDirectory(Path.GetDirectoryName(_outputFile));
  211. frr.Commit(_outputFile);
  212. }
  213. private void CollectStructDefs(List<MethodDesc> methods, HashSet<TypeInfo> structTypes)
  214. {
  215. foreach (var method in methods)
  216. {
  217. foreach(var paramInfo in method.ParamInfos)
  218. {
  219. if (paramInfo.Type.IsStruct)
  220. {
  221. structTypes.Add(paramInfo.Type);
  222. if (paramInfo.Type.Klass.ContainsGenericParameter)
  223. {
  224. throw new Exception($"[CollectStructDefs] method:{method.MethodDef} type:{paramInfo.Type.Klass} contains generic parameter");
  225. }
  226. }
  227. }
  228. if (method.ReturnInfo.Type.IsStruct)
  229. {
  230. structTypes.Add(method.ReturnInfo.Type);
  231. if (method.ReturnInfo.Type.Klass.ContainsGenericParameter)
  232. {
  233. throw new Exception($"[CollectStructDefs] method:{method.MethodDef} type:{method.ReturnInfo.Type.Klass} contains generic parameter");
  234. }
  235. }
  236. }
  237. }
  238. class FieldInfo
  239. {
  240. public FieldDef field;
  241. public TypeInfo type;
  242. }
  243. class ClassInfo
  244. {
  245. public TypeInfo type;
  246. public TypeDef typeDef;
  247. public List<FieldInfo> fields = new List<FieldInfo>();
  248. public ClassLayout layout;
  249. }
  250. private void GenerateClassInfo(TypeInfo type, HashSet<TypeInfo> typeSet, List<ClassInfo> classInfos)
  251. {
  252. if (!typeSet.Add(type))
  253. {
  254. return;
  255. }
  256. TypeSig typeSig = type.Klass;
  257. var fields = new List<FieldInfo>();
  258. TypeDef typeDef = typeSig.ToTypeDefOrRef().ResolveTypeDefThrow();
  259. List<TypeSig> klassInst = typeSig.ToGenericInstSig()?.GenericArguments?.ToList();
  260. GenericArgumentContext ctx = klassInst != null ? new GenericArgumentContext(klassInst, null) : null;
  261. ClassLayout sa = typeDef.ClassLayout;
  262. ICorLibTypes corLibTypes = typeDef.Module.CorLibTypes;
  263. foreach (FieldDef field in typeDef.Fields)
  264. {
  265. if (field.IsStatic)
  266. {
  267. continue;
  268. }
  269. TypeSig fieldType = ctx != null ? MetaUtil.Inflate(field.FieldType, ctx) : field.FieldType;
  270. fieldType = MetaUtil.ToShareTypeSig(corLibTypes, fieldType);
  271. var fieldTypeInfo = _typeCreator.CreateTypeInfo(fieldType);
  272. if (fieldTypeInfo.IsStruct)
  273. {
  274. GenerateClassInfo(fieldTypeInfo, typeSet, classInfos);
  275. }
  276. fields.Add(new FieldInfo { field = field, type = fieldTypeInfo });
  277. }
  278. classInfos.Add(new ClassInfo() { type = type, typeDef = typeDef, fields = fields, layout = sa });
  279. }
  280. private void GenerateStructDefines(List<ClassInfo> classInfos, List<string> lines)
  281. {
  282. foreach (var ci in classInfos)
  283. {
  284. lines.Add($"// {ci.type.Klass}");
  285. uint packingSize = ci.layout?.PackingSize ?? 0;
  286. if (packingSize != 0)
  287. {
  288. lines.Add($"#pragma pack(push, {packingSize})");
  289. }
  290. uint classSize = ci.layout?.ClassSize ?? 0;
  291. if (ci.typeDef.IsExplicitLayout)
  292. {
  293. lines.Add($"union {ci.type.GetTypeName()} {{");
  294. if (classSize > 0)
  295. {
  296. lines.Add($"\tstruct {{ char __fieldSize_offsetPadding[{classSize}];}};");
  297. }
  298. int index = 0;
  299. foreach (var field in ci.fields)
  300. {
  301. uint offset = field.field.FieldOffset.Value;
  302. string fieldName = $"__{index}";
  303. string commentFieldName = $"{field.field.Name}";
  304. lines.Add("\t#pragma pack(push, 1)");
  305. lines.Add($"\tstruct {{ {(offset > 0 ? $"char {fieldName}_offsetPadding[{offset}];" : "")} {field.type.GetTypeName()} {fieldName};}}; // {commentFieldName}");
  306. lines.Add($"\t#pragma pack(pop)");
  307. lines.Add($"\tstruct {{ {field.type.GetTypeName()} {fieldName}_forAlignmentOnly;}}; // {commentFieldName}");
  308. ++index;
  309. }
  310. }
  311. else
  312. {
  313. lines.Add($"{(classSize > 0 ? "union" : "struct")} {ci.type.GetTypeName()} {{");
  314. if (classSize > 0)
  315. {
  316. lines.Add($"\tstruct {{ char __fieldSize_offsetPadding[{classSize}];}};");
  317. lines.Add("\tstruct {");
  318. }
  319. int index = 0;
  320. foreach (var field in ci.fields)
  321. {
  322. string fieldName = $"__{index}";
  323. string commentFieldName = $"{field.field.Name}";
  324. lines.Add($"\t{field.type.GetTypeName()} {fieldName}; // {commentFieldName}");
  325. ++index;
  326. }
  327. if (classSize > 0)
  328. {
  329. lines.Add("\t};");
  330. }
  331. }
  332. lines.Add("};");
  333. if (packingSize != 0)
  334. {
  335. lines.Add($"#pragma pack(pop)");
  336. }
  337. }
  338. }
  339. public const string SigOfObj = "u";
  340. public static string ToFullName(TypeSig type)
  341. {
  342. type = type.RemovePinnedAndModifiers();
  343. switch (type.ElementType)
  344. {
  345. case ElementType.Void: return "v";
  346. case ElementType.Boolean: return "u1";
  347. case ElementType.I1: return "i1";
  348. case ElementType.U1: return "u1";
  349. case ElementType.I2: return "i2";
  350. case ElementType.Char:
  351. case ElementType.U2: return "u2";
  352. case ElementType.I4: return "i4";
  353. case ElementType.U4: return "u4";
  354. case ElementType.I8: return "i8";
  355. case ElementType.U8: return "u8";
  356. case ElementType.R4: return "r4";
  357. case ElementType.R8: return "r8";
  358. case ElementType.I: return "i";
  359. case ElementType.U:
  360. case ElementType.String:
  361. case ElementType.Ptr:
  362. case ElementType.ByRef:
  363. case ElementType.Class:
  364. case ElementType.Array:
  365. case ElementType.SZArray:
  366. case ElementType.FnPtr:
  367. case ElementType.Object:
  368. return SigOfObj;
  369. case ElementType.Module:
  370. case ElementType.Var:
  371. case ElementType.MVar:
  372. throw new NotSupportedException($"ToFullName type:{type}");
  373. case ElementType.TypedByRef: return TypeInfo.strTypedByRef;
  374. case ElementType.ValueType:
  375. {
  376. TypeDef typeDef = type.ToTypeDefOrRef().ResolveTypeDef();
  377. if (typeDef == null)
  378. {
  379. throw new Exception($"type:{type} definition could not be found. Please try `HybridCLR/Genergate/LinkXml`, then Build once to generate the AOT dll, and then regenerate the bridge function");
  380. }
  381. if (typeDef.IsEnum)
  382. {
  383. return ToFullName(typeDef.GetEnumUnderlyingType());
  384. }
  385. return ToValueTypeFullName((ClassOrValueTypeSig)type);
  386. }
  387. case ElementType.GenericInst:
  388. {
  389. GenericInstSig gis = (GenericInstSig)type;
  390. if (!gis.GenericType.IsValueType)
  391. {
  392. return SigOfObj;
  393. }
  394. TypeDef typeDef = gis.GenericType.ToTypeDefOrRef().ResolveTypeDef();
  395. if (typeDef.IsEnum)
  396. {
  397. return ToFullName(typeDef.GetEnumUnderlyingType());
  398. }
  399. return $"{ToValueTypeFullName(gis.GenericType)}<{string.Join(",", gis.GenericArguments.Select(a => ToFullName(a)))}>";
  400. }
  401. default: throw new NotSupportedException($"{type.ElementType}");
  402. }
  403. }
  404. private static bool IsSystemOrUnityAssembly(ModuleDef module)
  405. {
  406. if (module.IsCoreLibraryModule == true)
  407. {
  408. return true;
  409. }
  410. string assName = module.Assembly.Name.String;
  411. return assName.StartsWith("System.") || assName.StartsWith("UnityEngine.");
  412. }
  413. private static string ToValueTypeFullName(ClassOrValueTypeSig type)
  414. {
  415. TypeDef typeDef = type.ToTypeDefOrRef().ResolveTypeDef();
  416. if (typeDef == null)
  417. {
  418. throw new Exception($"type:{type} resolve fail");
  419. }
  420. if (typeDef.DeclaringType != null)
  421. {
  422. return $"{ToValueTypeFullName((ClassOrValueTypeSig)typeDef.DeclaringType.ToTypeSig())}/{typeDef.Name}";
  423. }
  424. if (IsSystemOrUnityAssembly(typeDef.Module))
  425. {
  426. return type.FullName;
  427. }
  428. return $"{Path.GetFileNameWithoutExtension(typeDef.Module.Name)}:{typeDef.FullName}";
  429. }
  430. public void GenerateStructureSignatureStub(List<TypeInfo> types, List<string> lines)
  431. {
  432. lines.Add("FullName2Signature hybridclr::interpreter::g_fullName2SignatureStub[] = {");
  433. foreach (var type in types)
  434. {
  435. lines.Add($"\t{{\"{ToFullName(type.Klass)}\", \"{type.CreateSigName()}\"}},");
  436. }
  437. lines.Add("\t{ nullptr, nullptr},");
  438. lines.Add("};");
  439. }
  440. public void GenerateManaged2NativeStub(List<MethodDesc> methods, List<string> lines)
  441. {
  442. lines.Add($@"
  443. Managed2NativeMethodInfo hybridclr::interpreter::g_managed2nativeStub[] =
  444. {{
  445. ");
  446. foreach (var method in methods)
  447. {
  448. lines.Add($"\t{{\"{method.CreateInvokeSigName()}\", __M2N_{method.CreateInvokeSigName()}}},");
  449. }
  450. lines.Add($"\t{{nullptr, nullptr}},");
  451. lines.Add("};");
  452. }
  453. public void GenerateNative2ManagedStub(List<MethodDesc> methods, List<string> lines)
  454. {
  455. lines.Add($@"
  456. Native2ManagedMethodInfo hybridclr::interpreter::g_native2managedStub[] =
  457. {{
  458. ");
  459. foreach (var method in methods)
  460. {
  461. lines.Add($"\t{{\"{method.CreateInvokeSigName()}\", (Il2CppMethodPointer)__N2M_{method.CreateInvokeSigName()}}},");
  462. }
  463. lines.Add($"\t{{nullptr, nullptr}},");
  464. lines.Add("};");
  465. }
  466. public void GenerateAdjustThunkStub(List<MethodDesc> methods, List<string> lines)
  467. {
  468. lines.Add($@"
  469. NativeAdjustThunkMethodInfo hybridclr::interpreter::g_adjustThunkStub[] =
  470. {{
  471. ");
  472. foreach (var method in methods)
  473. {
  474. lines.Add($"\t{{\"{method.CreateInvokeSigName()}\", (Il2CppMethodPointer)__N2M_AdjustorThunk_{method.CreateCallSigName()}}},");
  475. }
  476. lines.Add($"\t{{nullptr, nullptr}},");
  477. lines.Add("};");
  478. }
  479. private string GetManaged2NativePassParam(TypeInfo type, string varName)
  480. {
  481. return $"M2NFromValueOrAddress<{type.GetTypeName()}>({varName})";
  482. }
  483. private string GetNative2ManagedPassParam(TypeInfo type, string varName)
  484. {
  485. return type.NeedExpandValue() ? $"(uint64_t)({varName})" : $"N2MAsUint64ValueOrAddress<{type.GetTypeName()}>({varName})";
  486. }
  487. public void GenerateManaged2NativeMethod(MethodDesc method, List<string> lines)
  488. {
  489. string paramListStr = string.Join(", ", method.ParamInfos.Select(p => $"{p.Type.GetTypeName()} __arg{p.Index}").Concat(new string[] { "const MethodInfo* method" }));
  490. string paramNameListStr = string.Join(", ", method.ParamInfos.Select(p => GetManaged2NativePassParam(p.Type, $"localVarBase+argVarIndexs[{p.Index}]")).Concat(new string[] { "method" }));
  491. lines.Add($@"
  492. static void __M2N_{method.CreateCallSigName()}(const MethodInfo* method, uint16_t* argVarIndexs, StackObject* localVarBase, void* ret)
  493. {{
  494. typedef {method.ReturnInfo.Type.GetTypeName()} (*NativeMethod)({paramListStr});
  495. {(!method.ReturnInfo.IsVoid ? $"*({method.ReturnInfo.Type.GetTypeName()}*)ret = " : "")}((NativeMethod)(method->methodPointerCallByInterp))({paramNameListStr});
  496. }}
  497. ");
  498. }
  499. public string GenerateArgumentSizeAndOffset(List<ParamInfo> paramInfos)
  500. {
  501. StringBuilder s = new StringBuilder();
  502. int index = 0;
  503. foreach (var param in paramInfos)
  504. {
  505. s.AppendLine($"\tconstexpr int __ARG_OFFSET_{index}__ = {(index > 0 ? $"__ARG_OFFSET_{index - 1}__ + __ARG_SIZE_{index-1}__" : "0")};");
  506. s.AppendLine($"\tconstexpr int __ARG_SIZE_{index}__ = (sizeof(__arg{index}) + 7)/8;");
  507. index++;
  508. }
  509. s.AppendLine($"\tconstexpr int __TOTAL_ARG_SIZE__ = {(paramInfos.Count > 0 ? $"__ARG_OFFSET_{index-1}__ + __ARG_SIZE_{index-1}__" : "1")};");
  510. return s.ToString();
  511. }
  512. public string GenerateCopyArgumentToInterpreterStack(List<ParamInfo> paramInfos)
  513. {
  514. StringBuilder s = new StringBuilder();
  515. int index = 0;
  516. foreach (var param in paramInfos)
  517. {
  518. if (param.Type.IsPrimitiveType)
  519. {
  520. if (param.Type.NeedExpandValue())
  521. {
  522. s.AppendLine($"\targs[__ARG_OFFSET_{index}__].u64 = __arg{index};");
  523. }
  524. else
  525. {
  526. s.AppendLine($"\t*({param.Type.GetTypeName()}*)(args + __ARG_OFFSET_{index}__) = __arg{index};");
  527. }
  528. }
  529. else
  530. {
  531. s.AppendLine($"\t*({param.Type.GetTypeName()}*)(args + __ARG_OFFSET_{index}__) = __arg{index};");
  532. }
  533. index++;
  534. }
  535. return s.ToString();
  536. }
  537. private void GenerateNative2ManagedMethod0(MethodDesc method, bool adjustorThunk, List<string> lines)
  538. {
  539. string paramListStr = string.Join(", ", method.ParamInfos.Select(p => $"{p.Type.GetTypeName()} __arg{p.Index}").Concat(new string[] { "const MethodInfo* method" }));
  540. lines.Add($@"
  541. static {method.ReturnInfo.Type.GetTypeName()} __N2M_{(adjustorThunk ? "AdjustorThunk_" : "")}{method.CreateCallSigName()}({paramListStr})
  542. {{
  543. {(adjustorThunk ? "__arg0 += sizeof(Il2CppObject);" : "")}
  544. {GenerateArgumentSizeAndOffset(method.ParamInfos)}
  545. StackObject args[__TOTAL_ARG_SIZE__];
  546. {GenerateCopyArgumentToInterpreterStack(method.ParamInfos)}
  547. {(method.ReturnInfo.IsVoid ? "Interpreter::Execute(method, args, nullptr);" : $"{method.ReturnInfo.Type.GetTypeName()} ret; Interpreter::Execute(method, args, &ret); return ret;")}
  548. }}
  549. ");
  550. }
  551. public void GenerateNative2ManagedMethod(MethodDesc method, List<string> lines)
  552. {
  553. GenerateNative2ManagedMethod0(method, false, lines);
  554. }
  555. public void GenerateAdjustThunkMethod(MethodDesc method, List<string> lines)
  556. {
  557. GenerateNative2ManagedMethod0(method, true, lines);
  558. }
  559. }
  560. }