[new] 支持MonoPInvokeCallback函数的参数或返回类型为struct类型
[fix] 修复ReversePInvokeWrapper函数定义未包含调用约定的bug [refactor] 合并ReversePInvokeMethodStub到MethodBridge,同时将MetadataModule中ReversePInvoke相关代码移到InterpreterModulemain
parent
63d0aaa6e6
commit
d431aeb019
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using dnlib.DotNet;
|
||||
using HybridCLR.Editor.ABI;
|
||||
using HybridCLR.Editor.Meta;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
|
|
@ -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[] =
|
||||
{{
|
||||
");
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 7d883f182f206fa4db31f4085ce0ecdc
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Loading…
Reference in New Issue