[new] 支持MonoPInvokeCallback函数的参数或返回类型为struct类型

[fix] 修复ReversePInvokeWrapper函数定义未包含调用约定的bug
[refactor] 合并ReversePInvokeMethodStub到MethodBridge,同时将MetadataModule中ReversePInvoke相关代码移到InterpreterModule
main
walon 2024-05-26 11:59:54 +08:00
parent 63d0aaa6e6
commit d431aeb019
11 changed files with 261 additions and 276 deletions

View File

@ -27,8 +27,7 @@ namespace HybridCLR.Editor.Commands
var gs = SettingsUtil.HybridCLRSettings; var gs = SettingsUtil.HybridCLRSettings;
List<string> hotUpdateDllNames = SettingsUtil.HotUpdateAssemblyNamesExcludePreserved; List<string> 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), MaxIterationCount = Math.Min(20, gs.maxGenericReferenceIteration),
@ -43,4 +42,3 @@ namespace HybridCLR.Editor.Commands
} }
} }
} }
}

View File

@ -2,6 +2,7 @@
using HybridCLR.Editor.ABI; using HybridCLR.Editor.ABI;
using HybridCLR.Editor.Meta; using HybridCLR.Editor.Meta;
using HybridCLR.Editor.MethodBridge; using HybridCLR.Editor.MethodBridge;
using HybridCLR.Editor.ReversePInvokeWrap;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
@ -30,30 +31,30 @@ namespace HybridCLR.Editor.Commands
Directory.Delete(il2cppBuildCachePath, true); Directory.Delete(il2cppBuildCachePath, true);
} }
private static void GenerateMethodBridgeCppFile(Analyzer analyzer, string outputFile) private static void GenerateMethodBridgeCppFile(IReadOnlyCollection<GenericMethod> genericMethods, List<RawReversePInvokeMethodInfo> reversePInvokeMethods, string outputFile)
{ {
string templateCode = File.ReadAllText(outputFile, Encoding.UTF8); string templateCode = File.ReadAllText(outputFile, Encoding.UTF8);
var g = new Generator(new Generator.Options() var g = new Generator(new Generator.Options()
{ {
TemplateCode = templateCode, TemplateCode = templateCode,
OutputFile = outputFile, OutputFile = outputFile,
GenericMethods = analyzer.GenericMethods, GenericMethods = genericMethods,
ReversePInvokeMethods = reversePInvokeMethods,
Development = EditorUserBuildSettings.development, Development = EditorUserBuildSettings.development,
}); });
g.PrepareMethods();
g.Generate(); g.Generate();
Debug.LogFormat("[MethodBridgeGeneratorCommand] output:{0}", outputFile); Debug.LogFormat("[MethodBridgeGeneratorCommand] output:{0}", outputFile);
} }
[MenuItem("HybridCLR/Generate/MethodBridge", priority = 101)] [MenuItem("HybridCLR/Generate/MethodBridgeAndReversePInvokeWrapper", priority = 101)]
public static void CompileAndGenerateMethodBridge() public static void GenerateMethodBridgeAndReversePInvokeWrapper()
{ {
BuildTarget target = EditorUserBuildSettings.activeBuildTarget; 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); string aotDllDir = SettingsUtil.GetAssembliesPostIl2CppStripDir(target);
List<string> aotAssemblyNames = Directory.Exists(aotDllDir) ? List<string> 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`"); 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)) AssemblyReferenceDeepCollector collector = new AssemblyReferenceDeepCollector(MetaUtil.CreateAOTAssemblyResolver(target), aotAssemblyNames);
{
var analyzer = new Analyzer(new Analyzer.Options var methodBridgeAnalyzer = new Analyzer(new Analyzer.Options
{ {
MaxIterationCount = Math.Min(20, SettingsUtil.HybridCLRSettings.maxMethodBridgeGenericIteration), MaxIterationCount = Math.Min(20, SettingsUtil.HybridCLRSettings.maxMethodBridgeGenericIteration),
Collector = collector, Collector = collector,
}); });
analyzer.Run(); methodBridgeAnalyzer.Run();
List<string> 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"; string outputFile = $"{SettingsUtil.GeneratedCppDir}/MethodBridge.cpp";
GenerateMethodBridgeCppFile(analyzer, outputFile);
} GenerateMethodBridgeCppFile(methodBridgeAnalyzer.GenericMethods, reversePInvokeAnalyzer.ReversePInvokeMethods, outputFile);
CleanIl2CppBuildCache(); CleanIl2CppBuildCache();
} }

View File

@ -32,8 +32,7 @@ namespace HybridCLR.Editor.Commands
StripAOTDllCommand.GenerateStripedAOTDlls(target); StripAOTDllCommand.GenerateStripedAOTDlls(target);
// 桥接函数生成依赖于AOT dll必须保证已经build过生成AOT dll // 桥接函数生成依赖于AOT dll必须保证已经build过生成AOT dll
MethodBridgeGeneratorCommand.GenerateMethodBridge(target); MethodBridgeGeneratorCommand.GenerateMethodBridgeAndReversePInvokeWrapper(target);
ReversePInvokeWrapperGeneratorCommand.GenerateReversePInvokeWrapper(target);
AOTReferenceGeneratorCommand.GenerateAOTGenericReference(target); AOTReferenceGeneratorCommand.GenerateAOTGenericReference(target);
} }
} }

View File

@ -1,49 +1,49 @@
using HybridCLR.Editor.ABI; //using HybridCLR.Editor.ABI;
using HybridCLR.Editor.Link; //using HybridCLR.Editor.Link;
using HybridCLR.Editor.Meta; //using HybridCLR.Editor.Meta;
using HybridCLR.Editor.ReversePInvokeWrap; //using HybridCLR.Editor.ReversePInvokeWrap;
using System; //using System;
using System.Collections.Generic; //using System.Collections.Generic;
using System.IO; //using System.IO;
using System.Linq; //using System.Linq;
using System.Reflection; //using System.Reflection;
using System.Text; //using System.Text;
using System.Threading.Tasks; //using System.Threading.Tasks;
using UnityEditor; //using UnityEditor;
using UnityEngine; //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() // public static void CompileAndGenerateReversePInvokeWrapper()
{ // {
BuildTarget target = EditorUserBuildSettings.activeBuildTarget; // BuildTarget target = EditorUserBuildSettings.activeBuildTarget;
CompileDllCommand.CompileDll(target); // CompileDllCommand.CompileDll(target);
GenerateReversePInvokeWrapper(target); // GenerateReversePInvokeWrapper(target);
} // }
public static void GenerateReversePInvokeWrapper(BuildTarget target) // public static void GenerateReversePInvokeWrapper(BuildTarget target)
{ // {
List<string> hotUpdateDlls = SettingsUtil.HotUpdateAssemblyNamesExcludePreserved; // List<string> hotUpdateDlls = SettingsUtil.HotUpdateAssemblyNamesExcludePreserved;
using (var cache = new AssemblyCache(MetaUtil.CreateHotUpdateAndAOTAssemblyResolver(target, hotUpdateDlls))) // var cache = new AssemblyCache(MetaUtil.CreateHotUpdateAndAOTAssemblyResolver(target, hotUpdateDlls));
{ // {
var analyzer = new ReversePInvokeWrap.Analyzer(cache, hotUpdateDlls); // var analyzer = new ReversePInvokeWrap.Analyzer(cache, hotUpdateDlls);
analyzer.Run(); // analyzer.Run();
string outputFile = $"{SettingsUtil.GeneratedCppDir}/ReversePInvokeMethodStub.cpp"; // string outputFile = $"{SettingsUtil.GeneratedCppDir}/ReversePInvokeMethodStub.cpp";
List<ABIReversePInvokeMethodInfo> methods = analyzer.BuildABIMethods(); // List<ABIReversePInvokeMethodInfo> methods = analyzer.BuildABIMethods();
Debug.Log($"GenerateReversePInvokeWrapper. wraperCount:{methods.Sum(m => m.Count)} output:{outputFile}"); // Debug.Log($"GenerateReversePInvokeWrapper. wraperCount:{methods.Sum(m => m.Count)} output:{outputFile}");
var generator = new Generator(); // var generator = new Generator();
generator.Generate(methods, outputFile); // generator.Generate(methods, outputFile);
Debug.LogFormat("[ReversePInvokeWrapperGeneratorCommand] output:{0}", outputFile); // Debug.LogFormat("[ReversePInvokeWrapperGeneratorCommand] output:{0}", outputFile);
} // }
MethodBridgeGeneratorCommand.CleanIl2CppBuildCache(); // MethodBridgeGeneratorCommand.CleanIl2CppBuildCache();
} // }
} // }
} //}

View File

@ -23,8 +23,7 @@ namespace HybridCLR.Editor.Link
public HashSet<TypeRef> CollectRefs(List<string> rootAssemblies) public HashSet<TypeRef> CollectRefs(List<string> rootAssemblies)
{ {
using (var assCollector = new AssemblyCache(_resolver)) var assCollector = new AssemblyCache(_resolver);
{
var rootAssemblyNames = new HashSet<string>(rootAssemblies); var rootAssemblyNames = new HashSet<string>(rootAssemblies);
var typeRefs = new HashSet<TypeRef>(TypeEqualityComparer.Instance); var typeRefs = new HashSet<TypeRef>(TypeEqualityComparer.Instance);
@ -44,10 +43,7 @@ namespace HybridCLR.Editor.Link
} }
} }
} }
assCollector.Dispose();
return typeRefs; return typeRefs;
} }
} }
} }
}

View File

@ -8,12 +8,11 @@ using System.Threading.Tasks;
namespace HybridCLR.Editor.Meta namespace HybridCLR.Editor.Meta
{ {
public abstract class AssemblyCacheBase : IDisposable public abstract class AssemblyCacheBase
{ {
private readonly IAssemblyResolver _assemblyPathResolver; private readonly IAssemblyResolver _assemblyPathResolver;
private readonly ModuleContext _modCtx; private readonly ModuleContext _modCtx;
private readonly AssemblyResolver _asmResolver; private readonly AssemblyResolver _asmResolver;
private bool disposedValue;
private bool _loadedNetstandard; private bool _loadedNetstandard;
@ -96,28 +95,5 @@ namespace HybridCLR.Editor.Meta
_loadedModulesIncludeNetstandard.Add(mod); _loadedModulesIncludeNetstandard.Add(mod);
return 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);
}
} }
} }

View File

@ -1,4 +1,5 @@
using dnlib.DotNet; using dnlib.DotNet;
using HybridCLR.Editor.ABI;
using HybridCLR.Editor.Meta; using HybridCLR.Editor.Meta;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;

View File

@ -1,6 +1,7 @@
using dnlib.DotNet; using dnlib.DotNet;
using HybridCLR.Editor.ABI; using HybridCLR.Editor.ABI;
using HybridCLR.Editor.Meta; using HybridCLR.Editor.Meta;
using HybridCLR.Editor.ReversePInvokeWrap;
using HybridCLR.Editor.Template; using HybridCLR.Editor.Template;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -13,6 +14,7 @@ using System.Threading.Tasks;
using UnityEditor; using UnityEditor;
using UnityEngine; using UnityEngine;
using TypeInfo = HybridCLR.Editor.ABI.TypeInfo; using TypeInfo = HybridCLR.Editor.ABI.TypeInfo;
using CallingConvention = System.Runtime.InteropServices.CallingConvention;
namespace HybridCLR.Editor.MethodBridge namespace HybridCLR.Editor.MethodBridge
{ {
@ -26,11 +28,15 @@ namespace HybridCLR.Editor.MethodBridge
public IReadOnlyCollection<GenericMethod> GenericMethods { get; set; } public IReadOnlyCollection<GenericMethod> GenericMethods { get; set; }
public List<RawReversePInvokeMethodInfo> ReversePInvokeMethods { get; set; }
public bool Development { get; set; } public bool Development { get; set; }
} }
private readonly List<GenericMethod> _genericMethods; private readonly List<GenericMethod> _genericMethods;
private readonly List<RawReversePInvokeMethodInfo> _originalReversePInvokeMethods;
private readonly string _templateCode; private readonly string _templateCode;
private readonly string _outputFile; private readonly string _outputFile;
@ -45,11 +51,14 @@ namespace HybridCLR.Editor.MethodBridge
private readonly HashSet<MethodDesc> _adjustThunkMethodSet = new HashSet<MethodDesc>(); private readonly HashSet<MethodDesc> _adjustThunkMethodSet = new HashSet<MethodDesc>();
private List<ABIReversePInvokeMethodInfo> _reversePInvokeMethods;
public Generator(Options options) public Generator(Options options)
{ {
List<(GenericMethod, string)> genericMethodInfo = options.GenericMethods.Select(m => (m, m.ToString())).ToList(); List<(GenericMethod, string)> genericMethodInfo = options.GenericMethods.Select(m => (m, m.ToString())).ToList();
genericMethodInfo.Sort((a, b) => string.CompareOrdinal(a.Item2, b.Item2)); genericMethodInfo.Sort((a, b) => string.CompareOrdinal(a.Item2, b.Item2));
_genericMethods = genericMethodInfo.Select(m => m.Item1).ToList(); _genericMethods = genericMethodInfo.Select(m => m.Item1).ToList();
_originalReversePInvokeMethods = options.ReversePInvokeMethods;
_templateCode = options.TemplateCode; _templateCode = options.TemplateCode;
_outputFile = options.OutputFile; _outputFile = options.OutputFile;
@ -172,7 +181,7 @@ namespace HybridCLR.Editor.MethodBridge
} }
} }
public void PrepareMethods() private void PrepareGenericMethods()
{ {
foreach(var method in _genericMethods) foreach(var method in _genericMethods)
{ {
@ -375,11 +384,92 @@ namespace HybridCLR.Editor.MethodBridge
return methodMap.Values.ToList(); 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<ABIReversePInvokeMethodInfo> BuildABIMethods(List<RawReversePInvokeMethodInfo> rawMethods)
{
var methodsBySig = new Dictionary<string, ABIReversePInvokeMethodInfo>();
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() private void BuildOptimizedMethods()
{ {
_managed2NativeMethodList = ToUniqueOrderedList(_managed2NativeMethodList0); _managed2NativeMethodList = ToUniqueOrderedList(_managed2NativeMethodList0);
_native2ManagedMethodList = ToUniqueOrderedList(_native2ManagedMethodList0); _native2ManagedMethodList = ToUniqueOrderedList(_native2ManagedMethodList0);
_adjustThunkMethodList = ToUniqueOrderedList(_adjustThunkMethodList0); _adjustThunkMethodList = ToUniqueOrderedList(_adjustThunkMethodList0);
_reversePInvokeMethods = BuildABIMethods(_originalReversePInvokeMethods);
} }
private void OptimizationTypesAndMethods() private void OptimizationTypesAndMethods()
@ -394,11 +484,12 @@ namespace HybridCLR.Editor.MethodBridge
{ {
var frr = new FileRegionReplace(_templateCode); var frr = new FileRegionReplace(_templateCode);
List<string> lines = new List<string>(20_0000); List<string> lines = new List<string>(20_0000)
{
lines.Add("\n"); "\n",
lines.Add($"// DEVELOPMENT={(_development ? 1 : 0)}"); $"// DEVELOPMENT={(_development ? 1 : 0)}",
lines.Add("\n"); "\n"
};
var classInfos = new List<ClassInfo>(); var classInfos = new List<ClassInfo>();
var classTypeSet = new HashSet<TypeInfo>(); var classTypeSet = new HashSet<TypeInfo>();
@ -433,6 +524,8 @@ namespace HybridCLR.Editor.MethodBridge
GenerateAdjustThunkStub(_adjustThunkMethodList, lines); GenerateAdjustThunkStub(_adjustThunkMethodList, lines);
GenerateReversePInvokeWrappers(_reversePInvokeMethods, lines);
frr.Replace("CODE", string.Join("\n", lines)); frr.Replace("CODE", string.Join("\n", lines));
Directory.CreateDirectory(Path.GetDirectoryName(_outputFile)); Directory.CreateDirectory(Path.GetDirectoryName(_outputFile));
@ -440,8 +533,69 @@ namespace HybridCLR.Editor.MethodBridge
frr.Commit(_outputFile); 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<ABIReversePInvokeMethodInfo> methods, List<string> lines)
{
int methodIndex = 0;
var stubCodes = new List<string>();
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() public void Generate()
{ {
PrepareGenericMethods();
CollectTypesAndMethods(); CollectTypesAndMethods();
OptimizationTypesAndMethods(); OptimizationTypesAndMethods();
GenerateCode(); GenerateCode();
@ -687,7 +841,7 @@ namespace HybridCLR.Editor.MethodBridge
public void GenerateStructureSignatureStub(List<TypeInfo> types, List<string> lines) public void GenerateStructureSignatureStub(List<TypeInfo> types, List<string> lines)
{ {
lines.Add("FullName2Signature hybridclr::interpreter::g_fullName2SignatureStub[] = {"); lines.Add("const FullName2Signature hybridclr::interpreter::g_fullName2SignatureStub[] = {");
foreach (var type in types) foreach (var type in types)
{ {
TypeInfo isoType = ToIsomorphicType(type); TypeInfo isoType = ToIsomorphicType(type);
@ -700,7 +854,7 @@ namespace HybridCLR.Editor.MethodBridge
public void GenerateManaged2NativeStub(List<MethodDesc> methods, List<string> lines) public void GenerateManaged2NativeStub(List<MethodDesc> methods, List<string> lines)
{ {
lines.Add($@" 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<MethodDesc> methods, List<string> lines) public void GenerateNative2ManagedStub(List<MethodDesc> methods, List<string> lines)
{ {
lines.Add($@" 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<MethodDesc> methods, List<string> lines) public void GenerateAdjustThunkStub(List<MethodDesc> methods, List<string> lines)
{ {
lines.Add($@" lines.Add($@"
NativeAdjustThunkMethodInfo hybridclr::interpreter::g_adjustThunkStub[] = const NativeAdjustThunkMethodInfo hybridclr::interpreter::g_adjustThunkStub[] =
{{ {{
"); ");

View File

@ -36,6 +36,8 @@ namespace HybridCLR.Editor.ReversePInvokeWrap
private readonly List<RawReversePInvokeMethodInfo> _reversePInvokeMethods = new List<RawReversePInvokeMethodInfo>(); private readonly List<RawReversePInvokeMethodInfo> _reversePInvokeMethods = new List<RawReversePInvokeMethodInfo>();
public List<RawReversePInvokeMethodInfo> ReversePInvokeMethods => _reversePInvokeMethods;
public Analyzer(AssemblyCache cache, List<string> assemblyNames) public Analyzer(AssemblyCache cache, List<string> assemblyNames)
{ {
foreach (var assemblyName in 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<ABIReversePInvokeMethodInfo> BuildABIMethods()
{
var methodsBySig = new Dictionary<string, ABIReversePInvokeMethodInfo>();
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() public void Run()
{ {
CollectReversePInvokeMethods(); CollectReversePInvokeMethods();

View File

@ -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<ABIReversePInvokeMethodInfo> methods, string outputFile)
{
string template = File.ReadAllText(outputFile, Encoding.UTF8);
var frr = new FileRegionReplace(template);
var codes = new List<string>();
int methodIndex = 0;
var stubCodes = new List<string>();
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);
}
}
}

View File

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 7d883f182f206fa4db31f4085ce0ecdc
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: