[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;
|
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),
|
||||||
{
|
Collector = collector,
|
||||||
MaxIterationCount = Math.Min(20, gs.maxGenericReferenceIteration),
|
});
|
||||||
Collector = collector,
|
|
||||||
});
|
|
||||||
|
|
||||||
analyzer.Run();
|
analyzer.Run();
|
||||||
|
|
||||||
var writer = new GenericReferenceWriter();
|
var writer = new GenericReferenceWriter();
|
||||||
writer.Write(analyzer.AotGenericTypes.ToList(), analyzer.AotGenericMethods.ToList(), $"{Application.dataPath}/{gs.outputAOTGenericReferenceFile}");
|
writer.Write(analyzer.AotGenericTypes.ToList(), analyzer.AotGenericMethods.ToList(), $"{Application.dataPath}/{gs.outputAOTGenericReferenceFile}");
|
||||||
AssetDatabase.Refresh();
|
AssetDatabase.Refresh();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
|
||||||
{
|
|
||||||
MaxIterationCount = Math.Min(20, SettingsUtil.HybridCLRSettings.maxMethodBridgeGenericIteration),
|
|
||||||
Collector = collector,
|
|
||||||
});
|
|
||||||
|
|
||||||
analyzer.Run();
|
var methodBridgeAnalyzer = new Analyzer(new Analyzer.Options
|
||||||
string outputFile = $"{SettingsUtil.GeneratedCppDir}/MethodBridge.cpp";
|
{
|
||||||
GenerateMethodBridgeCppFile(analyzer, outputFile);
|
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();
|
CleanIl2CppBuildCache();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
|
|
|
@ -23,31 +23,27 @@ 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);
|
||||||
foreach (var rootAss in rootAssemblies)
|
foreach (var rootAss in rootAssemblies)
|
||||||
|
{
|
||||||
|
var dnAss = assCollector.LoadModule(rootAss, false);
|
||||||
|
foreach (var type in dnAss.GetTypeRefs())
|
||||||
{
|
{
|
||||||
var dnAss = assCollector.LoadModule(rootAss, false);
|
if (type.DefinitionAssembly == null)
|
||||||
foreach (var type in dnAss.GetTypeRefs())
|
|
||||||
{
|
{
|
||||||
if (type.DefinitionAssembly == null)
|
Debug.LogWarning($"assembly:{dnAss.Name} TypeRef {type.FullName} has no DefinitionAssembly");
|
||||||
{
|
continue;
|
||||||
Debug.LogWarning($"assembly:{dnAss.Name} TypeRef {type.FullName} has no DefinitionAssembly");
|
}
|
||||||
continue;
|
if (!rootAssemblyNames.Contains(type.DefinitionAssembly.Name.ToString()))
|
||||||
}
|
{
|
||||||
if (!rootAssemblyNames.Contains(type.DefinitionAssembly.Name.ToString()))
|
typeRefs.Add(type);
|
||||||
{
|
|
||||||
typeRefs.Add(type);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
assCollector.Dispose();
|
|
||||||
return typeRefs;
|
|
||||||
}
|
}
|
||||||
|
return typeRefs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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[] =
|
||||||
{{
|
{{
|
||||||
");
|
");
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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