[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,20 +27,18 @@ namespace HybridCLR.Editor.Commands
var gs = SettingsUtil.HybridCLRSettings;
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),
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();
}
}
}

View File

@ -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<GenericMethod> genericMethods, List<RawReversePInvokeMethodInfo> 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<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`");
}
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<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";
GenerateMethodBridgeCppFile(methodBridgeAnalyzer.GenericMethods, reversePInvokeAnalyzer.ReversePInvokeMethods, outputFile);
CleanIl2CppBuildCache();
}

View File

@ -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);
}
}

View File

@ -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<string> 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<string> 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<ABIReversePInvokeMethodInfo> 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<ABIReversePInvokeMethodInfo> 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();
// }
// }
//}

View File

@ -23,31 +23,27 @@ namespace HybridCLR.Editor.Link
public HashSet<TypeRef> CollectRefs(List<string> rootAssemblies)
{
using (var assCollector = new AssemblyCache(_resolver))
{
var rootAssemblyNames = new HashSet<string>(rootAssemblies);
var assCollector = new AssemblyCache(_resolver);
var rootAssemblyNames = new HashSet<string>(rootAssemblies);
var typeRefs = new HashSet<TypeRef>(TypeEqualityComparer.Instance);
foreach (var rootAss in rootAssemblies)
var typeRefs = new HashSet<TypeRef>(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;
}
}
}

View File

@ -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);
}
}
}

View File

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

View File

@ -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<GenericMethod> GenericMethods { get; set; }
public List<RawReversePInvokeMethodInfo> ReversePInvokeMethods { get; set; }
public bool Development { get; set; }
}
private readonly List<GenericMethod> _genericMethods;
private readonly List<RawReversePInvokeMethodInfo> _originalReversePInvokeMethods;
private readonly string _templateCode;
private readonly string _outputFile;
@ -45,11 +51,14 @@ namespace HybridCLR.Editor.MethodBridge
private readonly HashSet<MethodDesc> _adjustThunkMethodSet = new HashSet<MethodDesc>();
private List<ABIReversePInvokeMethodInfo> _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<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()
{
_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<string> lines = new List<string>(20_0000);
lines.Add("\n");
lines.Add($"// DEVELOPMENT={(_development ? 1 : 0)}");
lines.Add("\n");
List<string> lines = new List<string>(20_0000)
{
"\n",
$"// DEVELOPMENT={(_development ? 1 : 0)}",
"\n"
};
var classInfos = new List<ClassInfo>();
var classTypeSet = new HashSet<TypeInfo>();
@ -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<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()
{
PrepareGenericMethods();
CollectTypesAndMethods();
OptimizationTypesAndMethods();
GenerateCode();
@ -687,7 +841,7 @@ namespace HybridCLR.Editor.MethodBridge
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)
{
TypeInfo isoType = ToIsomorphicType(type);
@ -700,7 +854,7 @@ namespace HybridCLR.Editor.MethodBridge
public void GenerateManaged2NativeStub(List<MethodDesc> methods, List<string> 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<MethodDesc> methods, List<string> 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<MethodDesc> methods, List<string> lines)
{
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>();
public List<RawReversePInvokeMethodInfo> ReversePInvokeMethods => _reversePInvokeMethods;
public Analyzer(AssemblyCache cache, List<string> 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()
{
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: