From d431aeb01964a0d2ab24efa6c18a79e61f6eed05 Mon Sep 17 00:00:00 2001 From: walon Date: Sun, 26 May 2024 11:59:54 +0800 Subject: [PATCH] =?UTF-8?q?[new]=20=E6=94=AF=E6=8C=81MonoPInvokeCallback?= =?UTF-8?q?=E5=87=BD=E6=95=B0=E7=9A=84=E5=8F=82=E6=95=B0=E6=88=96=E8=BF=94?= =?UTF-8?q?=E5=9B=9E=E7=B1=BB=E5=9E=8B=E4=B8=BAstruct=E7=B1=BB=E5=9E=8B=20?= =?UTF-8?q?[fix]=20=E4=BF=AE=E5=A4=8DReversePInvokeWrapper=E5=87=BD?= =?UTF-8?q?=E6=95=B0=E5=AE=9A=E4=B9=89=E6=9C=AA=E5=8C=85=E5=90=AB=E8=B0=83?= =?UTF-8?q?=E7=94=A8=E7=BA=A6=E5=AE=9A=E7=9A=84bug=20[refactor]=20?= =?UTF-8?q?=E5=90=88=E5=B9=B6ReversePInvokeMethodStub=E5=88=B0MethodBridge?= =?UTF-8?q?=EF=BC=8C=E5=90=8C=E6=97=B6=E5=B0=86MetadataModule=E4=B8=ADReve?= =?UTF-8?q?rsePInvoke=E7=9B=B8=E5=85=B3=E4=BB=A3=E7=A0=81=E7=A7=BB?= =?UTF-8?q?=E5=88=B0InterpreterModule?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Commands/AOTReferenceGeneratorCommand.cs | 20 +- .../Commands/MethodBridgeGeneratorCommand.cs | 44 +++-- Editor/Commands/PrebuildCommand.cs | 3 +- .../ReversePInvokeWrapperGeneratorCommand.cs | 84 ++++----- Editor/Link/Analyzer.cs | 34 ++-- Editor/Meta/AssemblyCacheBase.cs | 26 +-- Editor/MethodBridge/Analyzer.cs | 1 + Editor/MethodBridge/Generator.cs | 174 +++++++++++++++++- Editor/ReversePInvokeWrap/Analyzer.cs | 80 +------- Editor/ReversePInvokeWrap/Generator.cs | 60 ------ Editor/ReversePInvokeWrap/Generator.cs.meta | 11 -- 11 files changed, 261 insertions(+), 276 deletions(-) delete mode 100644 Editor/ReversePInvokeWrap/Generator.cs delete mode 100644 Editor/ReversePInvokeWrap/Generator.cs.meta diff --git a/Editor/Commands/AOTReferenceGeneratorCommand.cs b/Editor/Commands/AOTReferenceGeneratorCommand.cs index c426f1d..c2d6340 100644 --- a/Editor/Commands/AOTReferenceGeneratorCommand.cs +++ b/Editor/Commands/AOTReferenceGeneratorCommand.cs @@ -27,20 +27,18 @@ namespace HybridCLR.Editor.Commands var gs = SettingsUtil.HybridCLRSettings; List hotUpdateDllNames = SettingsUtil.HotUpdateAssemblyNamesExcludePreserved; - using (AssemblyReferenceDeepCollector collector = new AssemblyReferenceDeepCollector(MetaUtil.CreateHotUpdateAndAOTAssemblyResolver(target, hotUpdateDllNames), hotUpdateDllNames)) + AssemblyReferenceDeepCollector collector = new AssemblyReferenceDeepCollector(MetaUtil.CreateHotUpdateAndAOTAssemblyResolver(target, hotUpdateDllNames), hotUpdateDllNames); + var analyzer = new Analyzer(new Analyzer.Options { - var analyzer = new Analyzer(new Analyzer.Options - { - MaxIterationCount = Math.Min(20, gs.maxGenericReferenceIteration), - Collector = collector, - }); + MaxIterationCount = Math.Min(20, gs.maxGenericReferenceIteration), + Collector = collector, + }); - analyzer.Run(); + analyzer.Run(); - var writer = new GenericReferenceWriter(); - writer.Write(analyzer.AotGenericTypes.ToList(), analyzer.AotGenericMethods.ToList(), $"{Application.dataPath}/{gs.outputAOTGenericReferenceFile}"); - AssetDatabase.Refresh(); - } + var writer = new GenericReferenceWriter(); + writer.Write(analyzer.AotGenericTypes.ToList(), analyzer.AotGenericMethods.ToList(), $"{Application.dataPath}/{gs.outputAOTGenericReferenceFile}"); + AssetDatabase.Refresh(); } } } diff --git a/Editor/Commands/MethodBridgeGeneratorCommand.cs b/Editor/Commands/MethodBridgeGeneratorCommand.cs index ab8f365..806f726 100644 --- a/Editor/Commands/MethodBridgeGeneratorCommand.cs +++ b/Editor/Commands/MethodBridgeGeneratorCommand.cs @@ -2,6 +2,7 @@ using HybridCLR.Editor.ABI; using HybridCLR.Editor.Meta; using HybridCLR.Editor.MethodBridge; +using HybridCLR.Editor.ReversePInvokeWrap; using System; using System.Collections.Generic; using System.IO; @@ -30,30 +31,30 @@ namespace HybridCLR.Editor.Commands Directory.Delete(il2cppBuildCachePath, true); } - private static void GenerateMethodBridgeCppFile(Analyzer analyzer, string outputFile) + private static void GenerateMethodBridgeCppFile(IReadOnlyCollection genericMethods, List reversePInvokeMethods, string outputFile) { string templateCode = File.ReadAllText(outputFile, Encoding.UTF8); var g = new Generator(new Generator.Options() { TemplateCode = templateCode, OutputFile = outputFile, - GenericMethods = analyzer.GenericMethods, + GenericMethods = genericMethods, + ReversePInvokeMethods = reversePInvokeMethods, Development = EditorUserBuildSettings.development, }); - g.PrepareMethods(); g.Generate(); Debug.LogFormat("[MethodBridgeGeneratorCommand] output:{0}", outputFile); } - [MenuItem("HybridCLR/Generate/MethodBridge", priority = 101)] - public static void CompileAndGenerateMethodBridge() + [MenuItem("HybridCLR/Generate/MethodBridgeAndReversePInvokeWrapper", priority = 101)] + public static void GenerateMethodBridgeAndReversePInvokeWrapper() { BuildTarget target = EditorUserBuildSettings.activeBuildTarget; - GenerateMethodBridge(target); + GenerateMethodBridgeAndReversePInvokeWrapper(target); } - public static void GenerateMethodBridge(BuildTarget target) + public static void GenerateMethodBridgeAndReversePInvokeWrapper(BuildTarget target) { string aotDllDir = SettingsUtil.GetAssembliesPostIl2CppStripDir(target); List aotAssemblyNames = Directory.Exists(aotDllDir) ? @@ -63,18 +64,25 @@ namespace HybridCLR.Editor.Commands { throw new Exception($"no aot assembly found. please run `HybridCLR/Generate/All` or `HybridCLR/Generate/AotDlls` to generate aot dlls before runing `HybridCLR/Generate/MethodBridge`"); } - using (AssemblyReferenceDeepCollector collector = new AssemblyReferenceDeepCollector(MetaUtil.CreateAOTAssemblyResolver(target), aotAssemblyNames)) - { - var analyzer = new Analyzer(new Analyzer.Options - { - MaxIterationCount = Math.Min(20, SettingsUtil.HybridCLRSettings.maxMethodBridgeGenericIteration), - Collector = collector, - }); + AssemblyReferenceDeepCollector collector = new AssemblyReferenceDeepCollector(MetaUtil.CreateAOTAssemblyResolver(target), aotAssemblyNames); - analyzer.Run(); - string outputFile = $"{SettingsUtil.GeneratedCppDir}/MethodBridge.cpp"; - GenerateMethodBridgeCppFile(analyzer, outputFile); - } + var methodBridgeAnalyzer = new Analyzer(new Analyzer.Options + { + MaxIterationCount = Math.Min(20, SettingsUtil.HybridCLRSettings.maxMethodBridgeGenericIteration), + Collector = collector, + }); + + methodBridgeAnalyzer.Run(); + + List hotUpdateDlls = SettingsUtil.HotUpdateAssemblyNamesExcludePreserved; + var cache = new AssemblyCache(MetaUtil.CreateHotUpdateAndAOTAssemblyResolver(target, hotUpdateDlls)); + + var reversePInvokeAnalyzer = new ReversePInvokeWrap.Analyzer(cache, hotUpdateDlls); + reversePInvokeAnalyzer.Run(); + + string outputFile = $"{SettingsUtil.GeneratedCppDir}/MethodBridge.cpp"; + + GenerateMethodBridgeCppFile(methodBridgeAnalyzer.GenericMethods, reversePInvokeAnalyzer.ReversePInvokeMethods, outputFile); CleanIl2CppBuildCache(); } diff --git a/Editor/Commands/PrebuildCommand.cs b/Editor/Commands/PrebuildCommand.cs index d480228..52d255f 100644 --- a/Editor/Commands/PrebuildCommand.cs +++ b/Editor/Commands/PrebuildCommand.cs @@ -32,8 +32,7 @@ namespace HybridCLR.Editor.Commands StripAOTDllCommand.GenerateStripedAOTDlls(target); // 桥接函数生成依赖于AOT dll,必须保证已经build过,生成AOT dll - MethodBridgeGeneratorCommand.GenerateMethodBridge(target); - ReversePInvokeWrapperGeneratorCommand.GenerateReversePInvokeWrapper(target); + MethodBridgeGeneratorCommand.GenerateMethodBridgeAndReversePInvokeWrapper(target); AOTReferenceGeneratorCommand.GenerateAOTGenericReference(target); } } diff --git a/Editor/Commands/ReversePInvokeWrapperGeneratorCommand.cs b/Editor/Commands/ReversePInvokeWrapperGeneratorCommand.cs index 706e748..faef39a 100644 --- a/Editor/Commands/ReversePInvokeWrapperGeneratorCommand.cs +++ b/Editor/Commands/ReversePInvokeWrapperGeneratorCommand.cs @@ -1,49 +1,49 @@ -using HybridCLR.Editor.ABI; -using HybridCLR.Editor.Link; -using HybridCLR.Editor.Meta; -using HybridCLR.Editor.ReversePInvokeWrap; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Text; -using System.Threading.Tasks; -using UnityEditor; -using UnityEngine; +//using HybridCLR.Editor.ABI; +//using HybridCLR.Editor.Link; +//using HybridCLR.Editor.Meta; +//using HybridCLR.Editor.ReversePInvokeWrap; +//using System; +//using System.Collections.Generic; +//using System.IO; +//using System.Linq; +//using System.Reflection; +//using System.Text; +//using System.Threading.Tasks; +//using UnityEditor; +//using UnityEngine; -namespace HybridCLR.Editor.Commands -{ +//namespace HybridCLR.Editor.Commands +//{ - public static class ReversePInvokeWrapperGeneratorCommand - { +// public static class ReversePInvokeWrapperGeneratorCommand +// { - [MenuItem("HybridCLR/Generate/ReversePInvokeWrapper", priority = 103)] +// [MenuItem("HybridCLR/Generate/ReversePInvokeWrapper", priority = 103)] - public static void CompileAndGenerateReversePInvokeWrapper() - { - BuildTarget target = EditorUserBuildSettings.activeBuildTarget; - CompileDllCommand.CompileDll(target); - GenerateReversePInvokeWrapper(target); - } +// public static void CompileAndGenerateReversePInvokeWrapper() +// { +// BuildTarget target = EditorUserBuildSettings.activeBuildTarget; +// CompileDllCommand.CompileDll(target); +// GenerateReversePInvokeWrapper(target); +// } - public static void GenerateReversePInvokeWrapper(BuildTarget target) - { - List hotUpdateDlls = SettingsUtil.HotUpdateAssemblyNamesExcludePreserved; - using (var cache = new AssemblyCache(MetaUtil.CreateHotUpdateAndAOTAssemblyResolver(target, hotUpdateDlls))) - { - var analyzer = new ReversePInvokeWrap.Analyzer(cache, hotUpdateDlls); - analyzer.Run(); +// public static void GenerateReversePInvokeWrapper(BuildTarget target) +// { +// List hotUpdateDlls = SettingsUtil.HotUpdateAssemblyNamesExcludePreserved; +// var cache = new AssemblyCache(MetaUtil.CreateHotUpdateAndAOTAssemblyResolver(target, hotUpdateDlls)); +// { +// var analyzer = new ReversePInvokeWrap.Analyzer(cache, hotUpdateDlls); +// analyzer.Run(); - string outputFile = $"{SettingsUtil.GeneratedCppDir}/ReversePInvokeMethodStub.cpp"; +// string outputFile = $"{SettingsUtil.GeneratedCppDir}/ReversePInvokeMethodStub.cpp"; - List methods = analyzer.BuildABIMethods(); - Debug.Log($"GenerateReversePInvokeWrapper. wraperCount:{methods.Sum(m => m.Count)} output:{outputFile}"); - var generator = new Generator(); - generator.Generate(methods, outputFile); - Debug.LogFormat("[ReversePInvokeWrapperGeneratorCommand] output:{0}", outputFile); - } - MethodBridgeGeneratorCommand.CleanIl2CppBuildCache(); - } - } -} +// List methods = analyzer.BuildABIMethods(); +// Debug.Log($"GenerateReversePInvokeWrapper. wraperCount:{methods.Sum(m => m.Count)} output:{outputFile}"); +// var generator = new Generator(); +// generator.Generate(methods, outputFile); +// Debug.LogFormat("[ReversePInvokeWrapperGeneratorCommand] output:{0}", outputFile); +// } +// MethodBridgeGeneratorCommand.CleanIl2CppBuildCache(); +// } +// } +//} diff --git a/Editor/Link/Analyzer.cs b/Editor/Link/Analyzer.cs index de4a9d1..ffbb93d 100644 --- a/Editor/Link/Analyzer.cs +++ b/Editor/Link/Analyzer.cs @@ -23,31 +23,27 @@ namespace HybridCLR.Editor.Link public HashSet CollectRefs(List rootAssemblies) { - using (var assCollector = new AssemblyCache(_resolver)) - { - var rootAssemblyNames = new HashSet(rootAssemblies); + var assCollector = new AssemblyCache(_resolver); + var rootAssemblyNames = new HashSet(rootAssemblies); - var typeRefs = new HashSet(TypeEqualityComparer.Instance); - foreach (var rootAss in rootAssemblies) + var typeRefs = new HashSet(TypeEqualityComparer.Instance); + foreach (var rootAss in rootAssemblies) + { + var dnAss = assCollector.LoadModule(rootAss, false); + foreach (var type in dnAss.GetTypeRefs()) { - var dnAss = assCollector.LoadModule(rootAss, false); - foreach (var type in dnAss.GetTypeRefs()) + if (type.DefinitionAssembly == null) { - if (type.DefinitionAssembly == null) - { - Debug.LogWarning($"assembly:{dnAss.Name} TypeRef {type.FullName} has no DefinitionAssembly"); - continue; - } - if (!rootAssemblyNames.Contains(type.DefinitionAssembly.Name.ToString())) - { - typeRefs.Add(type); - } + Debug.LogWarning($"assembly:{dnAss.Name} TypeRef {type.FullName} has no DefinitionAssembly"); + continue; + } + if (!rootAssemblyNames.Contains(type.DefinitionAssembly.Name.ToString())) + { + typeRefs.Add(type); } } - - assCollector.Dispose(); - return typeRefs; } + return typeRefs; } } } diff --git a/Editor/Meta/AssemblyCacheBase.cs b/Editor/Meta/AssemblyCacheBase.cs index c1f51a0..04f2d15 100644 --- a/Editor/Meta/AssemblyCacheBase.cs +++ b/Editor/Meta/AssemblyCacheBase.cs @@ -8,12 +8,11 @@ using System.Threading.Tasks; namespace HybridCLR.Editor.Meta { - public abstract class AssemblyCacheBase : IDisposable + public abstract class AssemblyCacheBase { private readonly IAssemblyResolver _assemblyPathResolver; private readonly ModuleContext _modCtx; private readonly AssemblyResolver _asmResolver; - private bool disposedValue; private bool _loadedNetstandard; @@ -96,28 +95,5 @@ namespace HybridCLR.Editor.Meta _loadedModulesIncludeNetstandard.Add(mod); return mod; } - - protected virtual void Dispose(bool disposing) - { - if (!disposedValue) - { - if (disposing) - { - foreach (var mod in _loadedModulesIncludeNetstandard) - { - mod.Dispose(); - } - _loadedModulesIncludeNetstandard.Clear(); - LoadedModules.Clear(); - } - disposedValue = true; - } - } - - public void Dispose() - { - Dispose(disposing: true); - GC.SuppressFinalize(this); - } } } diff --git a/Editor/MethodBridge/Analyzer.cs b/Editor/MethodBridge/Analyzer.cs index 59e2dd7..dd0fd66 100644 --- a/Editor/MethodBridge/Analyzer.cs +++ b/Editor/MethodBridge/Analyzer.cs @@ -1,4 +1,5 @@ using dnlib.DotNet; +using HybridCLR.Editor.ABI; using HybridCLR.Editor.Meta; using System; using System.Collections.Generic; diff --git a/Editor/MethodBridge/Generator.cs b/Editor/MethodBridge/Generator.cs index a7f1954..eda1fa0 100644 --- a/Editor/MethodBridge/Generator.cs +++ b/Editor/MethodBridge/Generator.cs @@ -1,6 +1,7 @@ using dnlib.DotNet; using HybridCLR.Editor.ABI; using HybridCLR.Editor.Meta; +using HybridCLR.Editor.ReversePInvokeWrap; using HybridCLR.Editor.Template; using System; using System.Collections.Generic; @@ -13,6 +14,7 @@ using System.Threading.Tasks; using UnityEditor; using UnityEngine; using TypeInfo = HybridCLR.Editor.ABI.TypeInfo; +using CallingConvention = System.Runtime.InteropServices.CallingConvention; namespace HybridCLR.Editor.MethodBridge { @@ -26,11 +28,15 @@ namespace HybridCLR.Editor.MethodBridge public IReadOnlyCollection GenericMethods { get; set; } + public List ReversePInvokeMethods { get; set; } + public bool Development { get; set; } } private readonly List _genericMethods; + private readonly List _originalReversePInvokeMethods; + private readonly string _templateCode; private readonly string _outputFile; @@ -45,11 +51,14 @@ namespace HybridCLR.Editor.MethodBridge private readonly HashSet _adjustThunkMethodSet = new HashSet(); + private List _reversePInvokeMethods; + public Generator(Options options) { List<(GenericMethod, string)> genericMethodInfo = options.GenericMethods.Select(m => (m, m.ToString())).ToList(); genericMethodInfo.Sort((a, b) => string.CompareOrdinal(a.Item2, b.Item2)); _genericMethods = genericMethodInfo.Select(m => m.Item1).ToList(); + _originalReversePInvokeMethods = options.ReversePInvokeMethods; _templateCode = options.TemplateCode; _outputFile = options.OutputFile; @@ -172,7 +181,7 @@ namespace HybridCLR.Editor.MethodBridge } } - public void PrepareMethods() + private void PrepareGenericMethods() { foreach(var method in _genericMethods) { @@ -375,11 +384,92 @@ namespace HybridCLR.Editor.MethodBridge return methodMap.Values.ToList(); } + + + private static string MakeSignature(MethodDesc desc, CallingConvention CallingConventionention) + { + string convStr = ((char)('A' + (int)CallingConventionention - 1)).ToString(); + return $"{convStr}{desc.Sig}"; + } + + private static CallingConvention GetCallingConvention(MethodDef method) + { + var monoPInvokeCallbackAttr = method.CustomAttributes.FirstOrDefault(ca => ca.AttributeType.Name == "MonoPInvokeCallbackAttribute"); + if (monoPInvokeCallbackAttr == null) + { + return CallingConvention.Winapi; + } + object delegateTypeSig = monoPInvokeCallbackAttr.ConstructorArguments[0].Value; + + TypeDef delegateTypeDef; + if (delegateTypeSig is ClassSig classSig) + { + delegateTypeDef = classSig.TypeDef; + } + else if (delegateTypeSig is GenericInstSig genericInstSig) + { + delegateTypeDef = genericInstSig.GenericType.TypeDefOrRef.ResolveTypeDefThrow(); + } + else + { + throw new NotSupportedException($"Unsupported delegate type {delegateTypeSig.GetType()}"); + } + + if (delegateTypeDef == null) + { + return CallingConvention.Winapi; + } + var attr = delegateTypeDef.CustomAttributes.FirstOrDefault(ca => ca.AttributeType.FullName == "System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute"); + if (attr == null) + { + return CallingConvention.Winapi; + } + var conv = attr.ConstructorArguments[0].Value; + return (CallingConvention)conv; + } + + private List BuildABIMethods(List rawMethods) + { + var methodsBySig = new Dictionary(); + foreach (var method in rawMethods) + { + var sharedMethod = new MethodDesc + { + MethodDef = method.Method, + ReturnInfo = new ReturnInfo { Type = _typeCreator.CreateTypeInfo(method.Method.ReturnType) }, + ParamInfos = method.Method.Parameters.Select(p => new ParamInfo { Type = _typeCreator.CreateTypeInfo(p.Type) }).ToList(), + }; + sharedMethod.Init(); + sharedMethod = ToIsomorphicMethod(sharedMethod); + + CallingConvention callingConv = GetCallingConvention(method.Method); + string signature = MakeSignature(sharedMethod, callingConv); + + if (!methodsBySig.TryGetValue(signature, out var arm)) + { + arm = new ABIReversePInvokeMethodInfo() + { + Method = sharedMethod, + Signature = signature, + Count = 0, + Callvention = callingConv, + }; + methodsBySig.Add(signature, arm); + } + int preserveCount = method.GenerationAttribute != null ? (int)method.GenerationAttribute.ConstructorArguments[0].Value : 1; + arm.Count += preserveCount; + } + var newMethods = methodsBySig.Values.ToList(); + newMethods.Sort((a, b) => string.CompareOrdinal(a.Signature, b.Signature)); + return newMethods; + } + private void BuildOptimizedMethods() { _managed2NativeMethodList = ToUniqueOrderedList(_managed2NativeMethodList0); _native2ManagedMethodList = ToUniqueOrderedList(_native2ManagedMethodList0); _adjustThunkMethodList = ToUniqueOrderedList(_adjustThunkMethodList0); + _reversePInvokeMethods = BuildABIMethods(_originalReversePInvokeMethods); } private void OptimizationTypesAndMethods() @@ -394,11 +484,12 @@ namespace HybridCLR.Editor.MethodBridge { var frr = new FileRegionReplace(_templateCode); - List lines = new List(20_0000); - - lines.Add("\n"); - lines.Add($"// DEVELOPMENT={(_development ? 1 : 0)}"); - lines.Add("\n"); + List lines = new List(20_0000) + { + "\n", + $"// DEVELOPMENT={(_development ? 1 : 0)}", + "\n" + }; var classInfos = new List(); var classTypeSet = new HashSet(); @@ -433,6 +524,8 @@ namespace HybridCLR.Editor.MethodBridge GenerateAdjustThunkStub(_adjustThunkMethodList, lines); + GenerateReversePInvokeWrappers(_reversePInvokeMethods, lines); + frr.Replace("CODE", string.Join("\n", lines)); Directory.CreateDirectory(Path.GetDirectoryName(_outputFile)); @@ -440,8 +533,69 @@ namespace HybridCLR.Editor.MethodBridge frr.Commit(_outputFile); } + private static string GetIl2cppCallConventionName(CallingConvention conv) + { + switch (conv) + { + case 0: + case CallingConvention.Winapi: + return "DEFAULT_CALL"; + case CallingConvention.Cdecl: + return "CDECL"; + case CallingConvention.StdCall: + return "STDCALL"; + case CallingConvention.ThisCall: + return "THISCALL"; + case CallingConvention.FastCall: + return "FASTCALL"; + default: + throw new NotSupportedException($"Unsupported CallingConvention {conv}"); + } + } + + private void GenerateReversePInvokeWrappers(List methods, List lines) + { + int methodIndex = 0; + var stubCodes = new List(); + foreach (var methodInfo in methods) + { + MethodDesc method = methodInfo.Method; + string il2cppCallConventionName = GetIl2cppCallConventionName(methodInfo.Callvention); + string paramDeclaringListWithoutMethodInfoStr = string.Join(", ", method.ParamInfos.Select(p => $"{p.Type.GetTypeName()} __arg{p.Index}")); + string paramNameListWithoutMethodInfoStr = string.Join(", ", method.ParamInfos.Select(p => $"__arg{p.Index}").Concat(new string[] { "method" })); + string paramTypeListWithMethodInfoStr = string.Join(", ", method.ParamInfos.Select(p => $"{p.Type.GetTypeName()}").Concat(new string[] { "const MethodInfo*" })); + string methodTypeDef = $"typedef {method.ReturnInfo.Type.GetTypeName()} (*Callback)({paramTypeListWithMethodInfoStr})"; + for (int i = 0; i < methodInfo.Count; i++, methodIndex++) + { + lines.Add($@" +{method.ReturnInfo.Type.GetTypeName()} {il2cppCallConventionName} __ReversePInvokeMethod_{methodIndex}({paramDeclaringListWithoutMethodInfoStr}) +{{ + il2cpp::vm::ScopedThreadAttacher _vmThreadHelper; + const MethodInfo* method = InterpreterModule::GetMethodInfoByReversePInvokeWrapperIndex({methodIndex}); + {methodTypeDef}; + {(method.ReturnInfo.IsVoid ? "" : "return ")}((Callback)(method->methodPointerCallByInterp))({paramNameListWithoutMethodInfoStr}); +}} + "); + stubCodes.Add($"\t{{\"{methodInfo.Signature}\", (Il2CppMethodPointer)__ReversePInvokeMethod_{methodIndex}}},"); + } + Debug.Log($"[ReversePInvokeWrap.Generator] method:{method.MethodDef} wrapperCount:{methodInfo.Count}"); + } + + lines.Add(@" +const ReversePInvokeMethodData hybridclr::interpreter::g_reversePInvokeMethodStub[] +{ +"); + lines.AddRange(stubCodes); + + lines.Add(@" + {nullptr, nullptr}, +}; +"); + } + public void Generate() { + PrepareGenericMethods(); CollectTypesAndMethods(); OptimizationTypesAndMethods(); GenerateCode(); @@ -687,7 +841,7 @@ namespace HybridCLR.Editor.MethodBridge public void GenerateStructureSignatureStub(List types, List lines) { - lines.Add("FullName2Signature hybridclr::interpreter::g_fullName2SignatureStub[] = {"); + lines.Add("const FullName2Signature hybridclr::interpreter::g_fullName2SignatureStub[] = {"); foreach (var type in types) { TypeInfo isoType = ToIsomorphicType(type); @@ -700,7 +854,7 @@ namespace HybridCLR.Editor.MethodBridge public void GenerateManaged2NativeStub(List methods, List lines) { lines.Add($@" -Managed2NativeMethodInfo hybridclr::interpreter::g_managed2nativeStub[] = +const Managed2NativeMethodInfo hybridclr::interpreter::g_managed2nativeStub[] = {{ "); @@ -716,7 +870,7 @@ Managed2NativeMethodInfo hybridclr::interpreter::g_managed2nativeStub[] = public void GenerateNative2ManagedStub(List methods, List lines) { lines.Add($@" -Native2ManagedMethodInfo hybridclr::interpreter::g_native2managedStub[] = +const Native2ManagedMethodInfo hybridclr::interpreter::g_native2managedStub[] = {{ "); @@ -732,7 +886,7 @@ Native2ManagedMethodInfo hybridclr::interpreter::g_native2managedStub[] = public void GenerateAdjustThunkStub(List methods, List lines) { lines.Add($@" -NativeAdjustThunkMethodInfo hybridclr::interpreter::g_adjustThunkStub[] = +const NativeAdjustThunkMethodInfo hybridclr::interpreter::g_adjustThunkStub[] = {{ "); diff --git a/Editor/ReversePInvokeWrap/Analyzer.cs b/Editor/ReversePInvokeWrap/Analyzer.cs index 891c1c6..217b3c8 100644 --- a/Editor/ReversePInvokeWrap/Analyzer.cs +++ b/Editor/ReversePInvokeWrap/Analyzer.cs @@ -36,6 +36,8 @@ namespace HybridCLR.Editor.ReversePInvokeWrap private readonly List _reversePInvokeMethods = new List(); + public List ReversePInvokeMethods => _reversePInvokeMethods; + public Analyzer(AssemblyCache cache, List assemblyNames) { foreach (var assemblyName in assemblyNames) @@ -75,84 +77,6 @@ namespace HybridCLR.Editor.ReversePInvokeWrap } } - private static string MakeSignature(MethodDesc desc, CallingConvention CallingConventionention) - { - string convStr = ((char)('A' + (int)CallingConventionention - 1)).ToString(); - return $"{convStr}{desc.Sig}"; - } - - private static CallingConvention GetCallingConvention(MethodDef method) - { - var monoPInvokeCallbackAttr = method.CustomAttributes.FirstOrDefault(ca => ca.AttributeType.Name == "MonoPInvokeCallbackAttribute"); - if (monoPInvokeCallbackAttr == null) - { - return CallingConvention.Winapi; - } - object delegateTypeSig = monoPInvokeCallbackAttr.ConstructorArguments[0].Value; - - TypeDef delegateTypeDef; - if (delegateTypeSig is ClassSig classSig) - { - delegateTypeDef = classSig.TypeDefOrRef.ResolveTypeDefThrow(); - } - else if (delegateTypeSig is GenericInstSig genericInstSig) - { - delegateTypeDef = genericInstSig.GenericType.TypeDefOrRef.ResolveTypeDefThrow(); - } - else - { - delegateTypeDef = null; - } - - if (delegateTypeDef == null) - { - throw new NotSupportedException($"Unsupported delegate type {delegateTypeSig.GetType()}"); - } - var attr = delegateTypeDef.CustomAttributes.FirstOrDefault(ca => ca.AttributeType.FullName == "System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute"); - if (attr == null) - { - return CallingConvention.Winapi; - } - var conv = attr.ConstructorArguments[0].Value; - return (CallingConvention)conv; - } - - public List BuildABIMethods() - { - var methodsBySig = new Dictionary(); - var typeCreator = new TypeCreator(); - foreach(var method in _reversePInvokeMethods) - { - MethodDesc desc = new MethodDesc - { - MethodDef = method.Method, - ReturnInfo = new ReturnInfo { Type = typeCreator.CreateTypeInfo(method.Method.ReturnType)}, - ParamInfos = method.Method.Parameters.Select(p => new ParamInfo { Type = typeCreator.CreateTypeInfo(p.Type)}).ToList(), - }; - desc.Init(); - - CallingConvention callingConv = GetCallingConvention(method.Method); - string signature = MakeSignature(desc, callingConv); - - if (!methodsBySig.TryGetValue(signature, out var arm)) - { - arm = new ABIReversePInvokeMethodInfo() - { - Method = desc, - Signature = signature, - Count = 0, - Callvention = callingConv, - }; - methodsBySig.Add(signature, arm); - } - int preserveCount = method.GenerationAttribute != null ? (int)method.GenerationAttribute.ConstructorArguments[0].Value : 1; - arm.Count += preserveCount; - } - var methods = methodsBySig.Values.ToList(); - methods.Sort((a, b) => string.CompareOrdinal(a.Signature, b.Signature)); - return methods; - } - public void Run() { CollectReversePInvokeMethods(); diff --git a/Editor/ReversePInvokeWrap/Generator.cs b/Editor/ReversePInvokeWrap/Generator.cs deleted file mode 100644 index 4c545d4..0000000 --- a/Editor/ReversePInvokeWrap/Generator.cs +++ /dev/null @@ -1,60 +0,0 @@ -using HybridCLR.Editor.ABI; -using HybridCLR.Editor.Template; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using UnityEngine; - -namespace HybridCLR.Editor.ReversePInvokeWrap -{ - public class Generator - { - public void Generate(List methods, string outputFile) - { - string template = File.ReadAllText(outputFile, Encoding.UTF8); - var frr = new FileRegionReplace(template); - var codes = new List(); - - int methodIndex = 0; - var stubCodes = new List(); - foreach(var methodInfo in methods) - { - MethodDesc method = methodInfo.Method; - string paramDeclaringListWithoutMethodInfoStr = string.Join(", ", method.ParamInfos.Select(p => $"{p.Type.GetTypeName()} __arg{p.Index}")); - string paramNameListWithoutMethodInfoStr = string.Join(", ", method.ParamInfos.Select(p => $"__arg{p.Index}").Concat(new string[] { "method" })); - string paramTypeListWithMethodInfoStr = string.Join(", ", method.ParamInfos.Select(p => $"{p.Type.GetTypeName()}").Concat(new string[] { "const MethodInfo*" })); - string methodTypeDef = $"typedef {method.ReturnInfo.Type.GetTypeName()} (*Callback)({paramTypeListWithMethodInfoStr})"; - for (int i = 0; i < methodInfo.Count; i++, methodIndex++) - { - codes.Add($@" - {method.ReturnInfo.Type.GetTypeName()} __ReversePInvokeMethod_{methodIndex}({paramDeclaringListWithoutMethodInfoStr}) - {{ - il2cpp::vm::ScopedThreadAttacher _vmThreadHelper; - const MethodInfo* method = MetadataModule::GetMethodInfoByReversePInvokeWrapperIndex({methodIndex}); - {methodTypeDef}; - {(method.ReturnInfo.IsVoid ? "" : "return ")}((Callback)(method->methodPointerCallByInterp))({paramNameListWithoutMethodInfoStr}); - }} -"); - stubCodes.Add($"\t\t{{\"{methodInfo.Signature}\", (Il2CppMethodPointer)__ReversePInvokeMethod_{methodIndex}}},\n"); - } - Debug.Log($"[ReversePInvokeWrap.Generator] method:{method.MethodDef} wrapperCount:{methodInfo.Count}"); - } - - codes.Add(@" - ReversePInvokeMethodData g_reversePInvokeMethodStub[] - { -"); - codes.AddRange(stubCodes); - - codes.Add(@" - {nullptr, nullptr}, - }; -"); - - frr.Replace("CODE", string.Join("", codes)); - frr.Commit(outputFile); - } - } -} diff --git a/Editor/ReversePInvokeWrap/Generator.cs.meta b/Editor/ReversePInvokeWrap/Generator.cs.meta deleted file mode 100644 index 36a7c55..0000000 --- a/Editor/ReversePInvokeWrap/Generator.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 7d883f182f206fa4db31f4085ce0ecdc -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: