GenericReferenceWriter.cs 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. using HybridCLR.Editor.Meta;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.IO;
  5. using System.Linq;
  6. using System.Text;
  7. using System.Text.RegularExpressions;
  8. using System.Threading.Tasks;
  9. using UnityEngine;
  10. namespace HybridCLR.Editor.AOT
  11. {
  12. public class GenericReferenceWriter
  13. {
  14. private static readonly Dictionary<Type, string> _typeNameMapping = new Dictionary<Type, string>
  15. {
  16. {typeof(bool), "bool" },
  17. {typeof(byte), "byte" },
  18. {typeof(sbyte), "sbyte" },
  19. {typeof(short), "short" },
  20. {typeof(ushort), "ushort" },
  21. {typeof(int), "int" },
  22. {typeof(uint), "uint" },
  23. {typeof(long), "long" },
  24. {typeof(ulong), "ulong" },
  25. {typeof(float), "float" },
  26. {typeof(double), "double" },
  27. {typeof(object), "object" },
  28. {typeof(string), "string" },
  29. };
  30. private readonly Dictionary<string, string> _typeSimpleNameMapping = new Dictionary<string, string>();
  31. private readonly Regex _systemTypePattern;
  32. private readonly Regex _genericPattern = new Regex(@"`\d+");
  33. public GenericReferenceWriter()
  34. {
  35. foreach (var e in _typeNameMapping)
  36. {
  37. _typeSimpleNameMapping.Add(e.Key.FullName, e.Value);
  38. }
  39. _systemTypePattern = new Regex(string.Join("|", _typeSimpleNameMapping.Keys.Select (k => $@"\b{k}\b")));
  40. }
  41. public string PrettifyTypeSig(string typeSig)
  42. {
  43. string s = _genericPattern.Replace(typeSig, "").Replace('/', '.');
  44. return _systemTypePattern.Replace(s, m => _typeSimpleNameMapping[m.Groups[0].Value]);
  45. }
  46. public string PrettifyMethodSig(string methodSig)
  47. {
  48. string s = PrettifyTypeSig(methodSig).Replace("::", ".");
  49. if (s.Contains(".ctor("))
  50. {
  51. s = "new " + s.Replace(".ctor(", "(");
  52. }
  53. return s;
  54. }
  55. public void Write(List<GenericClass> types, List<GenericMethod> methods, string outputFile)
  56. {
  57. string parentDir = Directory.GetParent(outputFile).FullName;
  58. Directory.CreateDirectory(parentDir);
  59. List<string> codes = new List<string>();
  60. codes.Add("using System.Collections.Generic;");
  61. codes.Add("public class AOTGenericReferences : UnityEngine.MonoBehaviour");
  62. codes.Add("{");
  63. codes.Add("");
  64. codes.Add("\t// {{ AOT assemblies");
  65. codes.Add("\tpublic static readonly IReadOnlyList<string> PatchedAOTAssemblyList = new List<string>");
  66. codes.Add("\t{");
  67. List<dnlib.DotNet.ModuleDef> modules = new HashSet<dnlib.DotNet.ModuleDef>(
  68. types.Select(t => t.Type.Module).Concat(methods.Select(m => m.Method.Module))).ToList();
  69. modules.Sort((a, b) => a.Name.CompareTo(b.Name));
  70. foreach (dnlib.DotNet.ModuleDef module in modules)
  71. {
  72. codes.Add($"\t\t\"{module.Name}\",");
  73. }
  74. codes.Add("\t};");
  75. codes.Add("\t// }}");
  76. codes.Add("");
  77. codes.Add("\t// {{ constraint implement type");
  78. codes.Add("\t// }} ");
  79. codes.Add("");
  80. codes.Add("\t// {{ AOT generic types");
  81. List<string> typeNames = types.Select(t => PrettifyTypeSig(t.ToTypeSig().ToString())).ToList();
  82. typeNames.Sort(string.CompareOrdinal);
  83. foreach(var typeName in typeNames)
  84. {
  85. codes.Add($"\t// {typeName}");
  86. }
  87. codes.Add("\t// }}");
  88. codes.Add("");
  89. codes.Add("\tpublic void RefMethods()");
  90. codes.Add("\t{");
  91. List<(string, string, string)> methodTypeAndNames = methods.Select(m =>
  92. (PrettifyTypeSig(m.Method.DeclaringType.ToString()), PrettifyMethodSig(m.Method.Name), PrettifyMethodSig(m.ToMethodSpec().ToString())))
  93. .ToList();
  94. methodTypeAndNames.Sort((a, b) =>
  95. {
  96. int c = String.Compare(a.Item1, b.Item1, StringComparison.Ordinal);
  97. if (c != 0)
  98. {
  99. return c;
  100. }
  101. c = String.Compare(a.Item2, b.Item2, StringComparison.Ordinal);
  102. if (c != 0)
  103. {
  104. return c;
  105. }
  106. return String.Compare(a.Item3, b.Item3, StringComparison.Ordinal);
  107. });
  108. foreach(var method in methodTypeAndNames)
  109. {
  110. codes.Add($"\t\t// {PrettifyMethodSig(method.Item3)}");
  111. }
  112. codes.Add("\t}");
  113. codes.Add("}");
  114. var utf8WithoutBom = new System.Text.UTF8Encoding(false);
  115. File.WriteAllText(outputFile, string.Join("\n", codes), utf8WithoutBom);
  116. Debug.Log($"[GenericReferenceWriter] write {outputFile}");
  117. }
  118. }
  119. }