@@ -1,5 +1,4 @@
|
||||
using dnlib.DotNet;
|
||||
using HybridCLR.Editor.ABI;
|
||||
using HybridCLR.Editor.Meta;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ee1ec106190e514489c7ba32bc7bc2e7
|
||||
guid: 5a1027c0dd7b35b4fbd5eacd6933f83f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
using dnlib.DotNet;
|
||||
|
||||
namespace HybridCLR.Editor.MethodBridge
|
||||
{
|
||||
public class CallNativeMethodSignatureInfo
|
||||
{
|
||||
public MethodSig MethodSig { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d2e4ca0a49975a84a8a72dbc70ec7795
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,65 +0,0 @@
|
||||
using dnlib.DotNet;
|
||||
using HybridCLR.Editor.Meta;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
|
||||
namespace HybridCLR.Editor.MethodBridge
|
||||
{
|
||||
|
||||
public class CalliAnalyzer
|
||||
{
|
||||
private readonly List<ModuleDefMD> _rootModules = new List<ModuleDefMD>();
|
||||
|
||||
private readonly List<CallNativeMethodSignatureInfo> _calliMethodSignatures = new List<CallNativeMethodSignatureInfo>();
|
||||
|
||||
public List<CallNativeMethodSignatureInfo> CalliMethodSignatures => _calliMethodSignatures;
|
||||
|
||||
public CalliAnalyzer(AssemblyCache cache, List<string> assemblyNames)
|
||||
{
|
||||
foreach (var assemblyName in assemblyNames)
|
||||
{
|
||||
_rootModules.Add(cache.LoadModule(assemblyName));
|
||||
}
|
||||
}
|
||||
|
||||
private void CollectCalli()
|
||||
{
|
||||
foreach (var mod in _rootModules)
|
||||
{
|
||||
Debug.Log($"ass:{mod.FullName} methodcount:{mod.Metadata.TablesStream.MethodTable.Rows}");
|
||||
for (uint rid = 1, n = mod.Metadata.TablesStream.MethodTable.Rows; rid <= n; rid++)
|
||||
{
|
||||
var method = mod.ResolveMethod(rid);
|
||||
//Debug.Log($"method:{method}");
|
||||
if (!method.HasBody)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (var il in method.Body.Instructions)
|
||||
{
|
||||
if (il.OpCode.Code == dnlib.DotNet.Emit.Code.Calli)
|
||||
{
|
||||
MethodSig methodSig = (MethodSig)il.Operand;
|
||||
|
||||
_calliMethodSignatures.Add(new CallNativeMethodSignatureInfo()
|
||||
{
|
||||
MethodSig = methodSig,
|
||||
});
|
||||
Debug.Log($"method:{method} calli method signature:{methodSig}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Run()
|
||||
{
|
||||
CollectCalli();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6ce33c8e48da5a649b261ba3a60fd3b9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -13,9 +13,6 @@ using System.Threading.Tasks;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using TypeInfo = HybridCLR.Editor.ABI.TypeInfo;
|
||||
using CallingConvention = System.Runtime.InteropServices.CallingConvention;
|
||||
using TypeAttributes = dnlib.DotNet.TypeAttributes;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace HybridCLR.Editor.MethodBridge
|
||||
{
|
||||
@@ -28,46 +25,14 @@ namespace HybridCLR.Editor.MethodBridge
|
||||
public string OutputFile { get; set; }
|
||||
|
||||
public IReadOnlyCollection<GenericMethod> GenericMethods { get; set; }
|
||||
|
||||
public List<RawMonoPInvokeCallbackMethodInfo> ReversePInvokeMethods { get; set; }
|
||||
|
||||
public IReadOnlyCollection<CallNativeMethodSignatureInfo> CalliMethodSignatures { get; set; }
|
||||
|
||||
public bool Development { get; set; }
|
||||
}
|
||||
|
||||
private class ABIReversePInvokeMethodInfo
|
||||
{
|
||||
public MethodDesc Method { get; set; }
|
||||
|
||||
public CallingConvention Callvention { get; set; }
|
||||
|
||||
public int Count { get; set; }
|
||||
|
||||
public string Signature { get; set; }
|
||||
}
|
||||
|
||||
private class CalliMethodInfo
|
||||
{
|
||||
public MethodDesc Method { get; set; }
|
||||
|
||||
public CallingConvention Callvention { get; set; }
|
||||
|
||||
public string Signature { get; set; }
|
||||
}
|
||||
|
||||
private readonly List<GenericMethod> _genericMethods;
|
||||
|
||||
private readonly List<RawMonoPInvokeCallbackMethodInfo> _originalReversePInvokeMethods;
|
||||
|
||||
private readonly List<CallNativeMethodSignatureInfo> _originalCalliMethodSignatures;
|
||||
|
||||
private readonly string _templateCode;
|
||||
|
||||
private readonly string _outputFile;
|
||||
|
||||
private readonly bool _development;
|
||||
|
||||
private readonly TypeCreator _typeCreator;
|
||||
|
||||
private readonly HashSet<MethodDesc> _managed2nativeMethodSet = new HashSet<MethodDesc>();
|
||||
@@ -76,22 +41,15 @@ namespace HybridCLR.Editor.MethodBridge
|
||||
|
||||
private readonly HashSet<MethodDesc> _adjustThunkMethodSet = new HashSet<MethodDesc>();
|
||||
|
||||
private List<ABIReversePInvokeMethodInfo> _reversePInvokeMethods;
|
||||
|
||||
private List<CalliMethodInfo> _callidMethods;
|
||||
|
||||
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;
|
||||
_originalCalliMethodSignatures = options.CalliMethodSignatures.ToList();
|
||||
|
||||
|
||||
_templateCode = options.TemplateCode;
|
||||
_outputFile = options.OutputFile;
|
||||
_typeCreator = new TypeCreator();
|
||||
_development = options.Development;
|
||||
}
|
||||
|
||||
private readonly Dictionary<string, TypeInfo> _sig2Types = new Dictionary<string, TypeInfo>();
|
||||
@@ -140,30 +98,6 @@ namespace HybridCLR.Editor.MethodBridge
|
||||
return mbs;
|
||||
}
|
||||
|
||||
private MethodDesc CreateMethodDesc(TypeSig returnType, List<TypeSig> parameters)
|
||||
{
|
||||
var paramInfos = new List<ParamInfo>();
|
||||
if (returnType.ContainsGenericParameter)
|
||||
{
|
||||
throw new Exception($"[PreservedMethod] method has generic parameters");
|
||||
}
|
||||
foreach (var paramInfo in parameters)
|
||||
{
|
||||
if (paramInfo.ContainsGenericParameter)
|
||||
{
|
||||
throw new Exception($"[PreservedMethod] method has generic parameters");
|
||||
}
|
||||
paramInfos.Add(new ParamInfo() { Type = GetSharedTypeInfo(paramInfo) });
|
||||
}
|
||||
var mbs = new MethodDesc()
|
||||
{
|
||||
MethodDef = null,
|
||||
ReturnInfo = new ReturnInfo() { Type = returnType != null ? GetSharedTypeInfo(returnType) : TypeInfo.s_void },
|
||||
ParamInfos = paramInfos,
|
||||
};
|
||||
return mbs;
|
||||
}
|
||||
|
||||
private void AddManaged2NativeMethod(MethodDesc method)
|
||||
{
|
||||
method.Init();
|
||||
@@ -233,23 +167,12 @@ namespace HybridCLR.Editor.MethodBridge
|
||||
}
|
||||
}
|
||||
|
||||
private void PrepareMethodBridges()
|
||||
public void PrepareMethods()
|
||||
{
|
||||
foreach (var method in _genericMethods)
|
||||
foreach(var method in _genericMethods)
|
||||
{
|
||||
ProcessMethod(method.Method, method.KlassInst, method.MethodInst);
|
||||
}
|
||||
foreach (var reversePInvokeMethod in _originalReversePInvokeMethods)
|
||||
{
|
||||
MethodDef method = reversePInvokeMethod.Method;
|
||||
ICorLibTypes corLibTypes = method.Module.CorLibTypes;
|
||||
|
||||
var returnType = MetaUtil.ToShareTypeSig(corLibTypes, method.ReturnType);
|
||||
var parameters = method.Parameters.Select(p => MetaUtil.ToShareTypeSig(corLibTypes, p.Type)).ToList();
|
||||
var sharedMethod = CreateMethodDesc(method, true, returnType, parameters);
|
||||
sharedMethod.Init();
|
||||
AddNative2ManagedMethod(sharedMethod);
|
||||
}
|
||||
}
|
||||
|
||||
static void CheckUnique(IEnumerable<string> names)
|
||||
@@ -297,114 +220,39 @@ namespace HybridCLR.Editor.MethodBridge
|
||||
_managed2NativeMethodList0.Count, _native2ManagedMethodList0.Count, _adjustThunkMethodList0.Count, _structTypes0.Count);
|
||||
}
|
||||
|
||||
private class AnalyzeFieldInfo
|
||||
{
|
||||
public FieldDef field;
|
||||
|
||||
public TypeInfo type;
|
||||
}
|
||||
|
||||
private class AnalyzeTypeInfo
|
||||
{
|
||||
public TypeInfo isoType;
|
||||
public List<AnalyzeFieldInfo> fields;
|
||||
public TypeInfo toSharedType;
|
||||
public List<TypeInfo> fields;
|
||||
public string signature;
|
||||
public uint originalPackingSize;
|
||||
public uint packingSize;
|
||||
public uint classSize;
|
||||
public LayoutKind layout;
|
||||
public bool blittable;
|
||||
}
|
||||
|
||||
private readonly Dictionary<TypeInfo, AnalyzeTypeInfo> _analyzeTypeInfos = new Dictionary<TypeInfo, AnalyzeTypeInfo>();
|
||||
|
||||
private readonly Dictionary<string, TypeInfo> _signature2Type = new Dictionary<string, TypeInfo>();
|
||||
|
||||
|
||||
|
||||
private bool IsBlittable(TypeSig typeSig)
|
||||
{
|
||||
typeSig = typeSig.RemovePinnedAndModifiers();
|
||||
if (typeSig.IsByRef)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
switch (typeSig.ElementType)
|
||||
{
|
||||
case ElementType.Void: return false;
|
||||
case ElementType.Boolean:
|
||||
case ElementType.I1:
|
||||
case ElementType.U1:
|
||||
case ElementType.I2:
|
||||
case ElementType.Char:
|
||||
case ElementType.U2:
|
||||
case ElementType.I4:
|
||||
case ElementType.U4:
|
||||
case ElementType.I8:
|
||||
case ElementType.U8:
|
||||
case ElementType.R4:
|
||||
case ElementType.R8:
|
||||
case ElementType.I:
|
||||
case ElementType.U:
|
||||
case ElementType.Ptr:
|
||||
case ElementType.ByRef:
|
||||
case ElementType.FnPtr:
|
||||
case ElementType.TypedByRef: return true;
|
||||
case ElementType.String:
|
||||
case ElementType.Class:
|
||||
case ElementType.Array:
|
||||
case ElementType.SZArray:
|
||||
case ElementType.Object:
|
||||
case ElementType.Module:
|
||||
case ElementType.Var:
|
||||
case ElementType.MVar: return false;
|
||||
case ElementType.ValueType:
|
||||
{
|
||||
TypeDef typeDef = typeSig.ToTypeDefOrRef().ResolveTypeDef();
|
||||
if (typeDef == null)
|
||||
{
|
||||
throw new Exception($"type:{typeSig} definition could not be found. Please try `HybridCLR/Genergate/LinkXml`, then Build once to generate the AOT dll, and then regenerate the bridge function");
|
||||
}
|
||||
if (typeDef.IsEnum)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return CalculateAnalyzeTypeInfoBasic(GetSharedTypeInfo(typeSig)).blittable;
|
||||
}
|
||||
case ElementType.GenericInst:
|
||||
{
|
||||
GenericInstSig gis = (GenericInstSig)typeSig;
|
||||
if (!gis.GenericType.IsValueType)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
TypeDef typeDef = gis.GenericType.ToTypeDefOrRef().ResolveTypeDef();
|
||||
if (typeDef.IsEnum)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return CalculateAnalyzeTypeInfoBasic(GetSharedTypeInfo(typeSig)).blittable;
|
||||
}
|
||||
default: throw new NotSupportedException($"{typeSig.ElementType}");
|
||||
}
|
||||
}
|
||||
|
||||
private AnalyzeTypeInfo CalculateAnalyzeTypeInfoBasic(TypeInfo typeInfo)
|
||||
{
|
||||
Debug.Assert(typeInfo.IsStruct);
|
||||
if (_analyzeTypeInfos.TryGetValue(typeInfo, out var ati))
|
||||
{
|
||||
return ati;
|
||||
}
|
||||
TypeSig type = typeInfo.Klass;
|
||||
TypeDef typeDef = type.ToTypeDefOrRef().ResolveTypeDefThrow();
|
||||
|
||||
List<TypeSig> klassInst = type.ToGenericInstSig()?.GenericArguments?.ToList();
|
||||
GenericArgumentContext ctx = klassInst != null ? new GenericArgumentContext(klassInst, null) : null;
|
||||
|
||||
var fields = new List<AnalyzeFieldInfo>();
|
||||
ClassLayout sa = typeDef.ClassLayout;
|
||||
var analyzeTypeInfo = new AnalyzeTypeInfo();
|
||||
|
||||
// don't share type with explicit layout
|
||||
if (sa != null)
|
||||
{
|
||||
analyzeTypeInfo.toSharedType = typeInfo;
|
||||
analyzeTypeInfo.signature = typeInfo.CreateSigName();
|
||||
_signature2Type.Add(analyzeTypeInfo.signature, typeInfo);
|
||||
return analyzeTypeInfo;
|
||||
}
|
||||
|
||||
var fields = analyzeTypeInfo.fields = new List<TypeInfo>();
|
||||
|
||||
bool blittable = true;
|
||||
foreach (FieldDef field in typeDef.Fields)
|
||||
{
|
||||
if (field.IsStatic)
|
||||
@@ -412,39 +260,8 @@ namespace HybridCLR.Editor.MethodBridge
|
||||
continue;
|
||||
}
|
||||
TypeSig fieldType = ctx != null ? MetaUtil.Inflate(field.FieldType, ctx) : field.FieldType;
|
||||
blittable &= IsBlittable(fieldType);
|
||||
TypeInfo sharedFieldTypeInfo = GetSharedTypeInfo(fieldType);
|
||||
TypeInfo isoType = ToIsomorphicType(sharedFieldTypeInfo);
|
||||
fields.Add(new AnalyzeFieldInfo { field = field, type = isoType });
|
||||
fields.Add(GetSharedTypeInfo(fieldType));
|
||||
}
|
||||
//analyzeTypeInfo.blittable = blittable;
|
||||
//analyzeTypeInfo.packingSize = blittable ? analyzeTypeInfo.originalPackingSize : 0;
|
||||
|
||||
ClassLayout sa = typeDef.ClassLayout;
|
||||
uint originalPackingSize = sa?.PackingSize ?? 0;
|
||||
var analyzeTypeInfo = new AnalyzeTypeInfo()
|
||||
{
|
||||
originalPackingSize = originalPackingSize,
|
||||
packingSize = blittable && !typeDef.IsAutoLayout ? originalPackingSize : 0,
|
||||
classSize = sa?.ClassSize ?? 0,
|
||||
layout = typeDef.IsAutoLayout ? LayoutKind.Auto : (typeDef.IsExplicitLayout ? LayoutKind.Explicit : LayoutKind.Sequential),
|
||||
fields = fields,
|
||||
blittable = blittable,
|
||||
};
|
||||
_analyzeTypeInfos.Add(typeInfo, analyzeTypeInfo);
|
||||
analyzeTypeInfo.signature = GetOrCalculateTypeInfoSignature(typeInfo);
|
||||
|
||||
if (_signature2Type.TryGetValue(analyzeTypeInfo.signature, out var sharedType))
|
||||
{
|
||||
// Debug.Log($"[ToIsomorphicType] type:{type.Klass} ==> sharedType:{sharedType.Klass} signature:{signature} ");
|
||||
analyzeTypeInfo.isoType = sharedType;
|
||||
}
|
||||
else
|
||||
{
|
||||
analyzeTypeInfo.isoType = typeInfo;
|
||||
_signature2Type.Add(analyzeTypeInfo.signature, typeInfo);
|
||||
}
|
||||
|
||||
return analyzeTypeInfo;
|
||||
}
|
||||
|
||||
@@ -467,16 +284,11 @@ namespace HybridCLR.Editor.MethodBridge
|
||||
{
|
||||
return ati.signature;
|
||||
}
|
||||
|
||||
|
||||
var sigBuf = new StringBuilder();
|
||||
if (ati.packingSize != 0 || ati.classSize != 0 || ati.layout != LayoutKind.Sequential || !ati.blittable)
|
||||
{
|
||||
sigBuf.Append($"[{ati.classSize}|{ati.packingSize}|{ati.layout}|{(ati.blittable ? 0 : 1)}]");
|
||||
}
|
||||
foreach (var field in ati.fields)
|
||||
{
|
||||
string fieldOffset = field.field.FieldOffset != null ? field.field.FieldOffset.ToString() + "|" : "";
|
||||
sigBuf.Append("{" + fieldOffset + GetOrCalculateTypeInfoSignature(ToIsomorphicType(field.type)) + "}");
|
||||
sigBuf.Append(GetOrCalculateTypeInfoSignature(ToIsomorphicType(field)));
|
||||
}
|
||||
return ati.signature = sigBuf.ToString();
|
||||
}
|
||||
@@ -487,7 +299,27 @@ namespace HybridCLR.Editor.MethodBridge
|
||||
{
|
||||
return type;
|
||||
}
|
||||
return CalculateAnalyzeTypeInfoBasic(type).isoType;
|
||||
if (!_analyzeTypeInfos.TryGetValue(type, out var ati))
|
||||
{
|
||||
ati = CalculateAnalyzeTypeInfoBasic(type);
|
||||
_analyzeTypeInfos.Add(type, ati);
|
||||
}
|
||||
if (ati.toSharedType == null)
|
||||
{
|
||||
string signature = GetOrCalculateTypeInfoSignature(type);
|
||||
Debug.Assert(signature == ati.signature);
|
||||
if (_signature2Type.TryGetValue(signature, out var sharedType))
|
||||
{
|
||||
// Debug.Log($"[ToIsomorphicType] type:{type.Klass} ==> sharedType:{sharedType.Klass} signature:{signature} ");
|
||||
ati.toSharedType = sharedType;
|
||||
}
|
||||
else
|
||||
{
|
||||
ati.toSharedType = type;
|
||||
_signature2Type.Add(signature, type);
|
||||
}
|
||||
}
|
||||
return ati.toSharedType;
|
||||
}
|
||||
|
||||
private MethodDesc ToIsomorphicMethod(MethodDesc method)
|
||||
@@ -538,131 +370,11 @@ namespace HybridCLR.Editor.MethodBridge
|
||||
return methodMap.Values.ToList();
|
||||
}
|
||||
|
||||
|
||||
|
||||
private static string MakeReversePInvokeSignature(MethodDesc desc, CallingConvention CallingConventionention)
|
||||
{
|
||||
string convStr = ((char)('A' + (int)CallingConventionention - 1)).ToString();
|
||||
return $"{convStr}{desc.Sig}";
|
||||
}
|
||||
private static string MakeCalliSignature(MethodDesc desc, CallingConvention CallingConventionention)
|
||||
{
|
||||
string convStr = ((char)('A' + Math.Max((int)CallingConventionention - 1, 0))).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}");
|
||||
}
|
||||
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<RawMonoPInvokeCallbackMethodInfo> rawMethods)
|
||||
{
|
||||
var methodsBySig = new Dictionary<string, ABIReversePInvokeMethodInfo>();
|
||||
foreach (var method in rawMethods)
|
||||
{
|
||||
var sharedMethod = new MethodDesc
|
||||
{
|
||||
MethodDef = method.Method,
|
||||
ReturnInfo = new ReturnInfo { Type = GetSharedTypeInfo(method.Method.ReturnType) },
|
||||
ParamInfos = method.Method.Parameters.Select(p => new ParamInfo { Type = GetSharedTypeInfo(p.Type) }).ToList(),
|
||||
};
|
||||
sharedMethod.Init();
|
||||
sharedMethod = ToIsomorphicMethod(sharedMethod);
|
||||
|
||||
CallingConvention callingConv = GetCallingConvention(method.Method);
|
||||
string signature = MakeReversePInvokeSignature(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 List<CalliMethodInfo> BuildCalliMethods(List<CallNativeMethodSignatureInfo> rawMethods)
|
||||
{
|
||||
var methodsBySig = new Dictionary<string, CalliMethodInfo>();
|
||||
foreach (var method in rawMethods)
|
||||
{
|
||||
var sharedMethod = new MethodDesc
|
||||
{
|
||||
MethodDef = null,
|
||||
ReturnInfo = new ReturnInfo { Type = GetSharedTypeInfo(method.MethodSig.RetType) },
|
||||
ParamInfos = method.MethodSig.Params.Select(p => new ParamInfo { Type = GetSharedTypeInfo(p) }).ToList(),
|
||||
};
|
||||
sharedMethod.Init();
|
||||
sharedMethod = ToIsomorphicMethod(sharedMethod);
|
||||
|
||||
CallingConvention callingConv = (CallingConvention)((int)(method.MethodSig.CallingConvention & dnlib.DotNet.CallingConvention.Mask) + 1);
|
||||
string signature = MakeCalliSignature(sharedMethod, callingConv);
|
||||
|
||||
if (!methodsBySig.TryGetValue(signature, out var arm))
|
||||
{
|
||||
arm = new CalliMethodInfo()
|
||||
{
|
||||
Method = sharedMethod,
|
||||
Signature = signature,
|
||||
Callvention = callingConv,
|
||||
};
|
||||
methodsBySig.Add(signature, arm);
|
||||
}
|
||||
}
|
||||
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);
|
||||
_callidMethods = BuildCalliMethods(_originalCalliMethodSignatures);
|
||||
}
|
||||
|
||||
private void OptimizationTypesAndMethods()
|
||||
@@ -677,15 +389,10 @@ namespace HybridCLR.Editor.MethodBridge
|
||||
{
|
||||
var frr = new FileRegionReplace(_templateCode);
|
||||
|
||||
List<string> lines = new List<string>(20_0000)
|
||||
{
|
||||
"\n",
|
||||
$"// DEVELOPMENT={(_development ? 1 : 0)}",
|
||||
"\n"
|
||||
};
|
||||
List<string> lines = new List<string>(20_0000);
|
||||
|
||||
var classInfos = new List<ClassInfo>();
|
||||
var classTypeSet = new Dictionary<TypeInfo, ClassInfo>();
|
||||
var classTypeSet = new HashSet<TypeInfo>();
|
||||
foreach (var type in structTypes)
|
||||
{
|
||||
GenerateClassInfo(type, classTypeSet, classInfos);
|
||||
@@ -717,15 +424,6 @@ namespace HybridCLR.Editor.MethodBridge
|
||||
|
||||
GenerateAdjustThunkStub(_adjustThunkMethodList, lines);
|
||||
|
||||
GenerateReversePInvokeWrappers(_reversePInvokeMethods, lines);
|
||||
|
||||
foreach (var method in _callidMethods)
|
||||
{
|
||||
GenerateManaged2NativeFunctionPointerMethod(method, lines);
|
||||
}
|
||||
GenerateManaged2NativeFunctionPointerMethodStub(_callidMethods, lines);
|
||||
|
||||
|
||||
frr.Replace("CODE", string.Join("\n", lines));
|
||||
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(_outputFile));
|
||||
@@ -733,69 +431,8 @@ 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()
|
||||
{
|
||||
PrepareMethodBridges();
|
||||
CollectTypesAndMethods();
|
||||
OptimizationTypesAndMethods();
|
||||
GenerateCode();
|
||||
@@ -838,68 +475,47 @@ const ReversePInvokeMethodData hybridclr::interpreter::g_reversePInvokeMethodStu
|
||||
class ClassInfo
|
||||
{
|
||||
public TypeInfo type;
|
||||
public List<AnalyzeFieldInfo> fields;
|
||||
public uint packingSize;
|
||||
public uint classSize;
|
||||
public LayoutKind layout;
|
||||
public bool blittable;
|
||||
|
||||
public TypeDef typeDef;
|
||||
|
||||
public List<FieldInfo> fields = new List<FieldInfo>();
|
||||
|
||||
public ClassLayout layout;
|
||||
}
|
||||
|
||||
private void GenerateClassInfo(TypeInfo type, Dictionary<TypeInfo, ClassInfo> typeSet, List<ClassInfo> classInfos)
|
||||
private void GenerateClassInfo(TypeInfo type, HashSet<TypeInfo> typeSet, List<ClassInfo> classInfos)
|
||||
{
|
||||
if (typeSet.ContainsKey(type))
|
||||
if (!typeSet.Add(type))
|
||||
{
|
||||
return;
|
||||
}
|
||||
TypeSig typeSig = type.Klass;
|
||||
var fields = new List<FieldInfo>();
|
||||
|
||||
AnalyzeTypeInfo ati = CalculateAnalyzeTypeInfoBasic(type);
|
||||
//TypeSig typeSig = type.Klass;
|
||||
//var fields = new List<FieldInfo>();
|
||||
TypeDef typeDef = typeSig.ToTypeDefOrRef().ResolveTypeDefThrow();
|
||||
|
||||
//TypeDef typeDef = typeSig.ToTypeDefOrRef().ResolveTypeDefThrow();
|
||||
List<TypeSig> klassInst = typeSig.ToGenericInstSig()?.GenericArguments?.ToList();
|
||||
GenericArgumentContext ctx = klassInst != null ? new GenericArgumentContext(klassInst, null) : null;
|
||||
|
||||
//List<TypeSig> klassInst = typeSig.ToGenericInstSig()?.GenericArguments?.ToList();
|
||||
//GenericArgumentContext ctx = klassInst != null ? new GenericArgumentContext(klassInst, null) : null;
|
||||
|
||||
//ClassLayout sa = typeDef.ClassLayout;
|
||||
|
||||
//ICorLibTypes corLibTypes = typeDef.Module.CorLibTypes;
|
||||
//bool blittable = true;
|
||||
//foreach (FieldDef field in typeDef.Fields)
|
||||
//{
|
||||
// if (field.IsStatic)
|
||||
// {
|
||||
// continue;
|
||||
// }
|
||||
// TypeSig fieldType = ctx != null ? MetaUtil.Inflate(field.FieldType, ctx) : field.FieldType;
|
||||
// fieldType = MetaUtil.ToShareTypeSig(corLibTypes, fieldType);
|
||||
// var fieldTypeInfo = ToIsomorphicType(GetSharedTypeInfo(fieldType));
|
||||
// if (fieldTypeInfo.IsStruct)
|
||||
// {
|
||||
// GenerateClassInfo(fieldTypeInfo, typeSet, classInfos);
|
||||
// }
|
||||
// blittable &= IsBlittable(fieldType, fieldTypeInfo, typeSet);
|
||||
// fields.Add(new FieldInfo { field = field, type = fieldTypeInfo });
|
||||
//}
|
||||
|
||||
foreach (var field in ati.fields)
|
||||
ClassLayout sa = typeDef.ClassLayout;
|
||||
|
||||
ICorLibTypes corLibTypes = typeDef.Module.CorLibTypes;
|
||||
foreach (FieldDef field in typeDef.Fields)
|
||||
{
|
||||
if (field.type.IsStruct)
|
||||
if (field.IsStatic)
|
||||
{
|
||||
GenerateClassInfo(field.type, typeSet, classInfos);
|
||||
continue;
|
||||
}
|
||||
TypeSig fieldType = ctx != null ? MetaUtil.Inflate(field.FieldType, ctx) : field.FieldType;
|
||||
fieldType = MetaUtil.ToShareTypeSig(corLibTypes, fieldType);
|
||||
var fieldTypeInfo = ToIsomorphicType(_typeCreator.CreateTypeInfo(fieldType));
|
||||
if (fieldTypeInfo.IsStruct)
|
||||
{
|
||||
GenerateClassInfo(fieldTypeInfo, typeSet, classInfos);
|
||||
}
|
||||
fields.Add(new FieldInfo { field = field, type = fieldTypeInfo });
|
||||
}
|
||||
var classInfo = new ClassInfo()
|
||||
{
|
||||
type = type,
|
||||
fields = ati.fields,
|
||||
packingSize = ati.packingSize,
|
||||
classSize = ati.classSize,
|
||||
layout = ati.layout,
|
||||
blittable = ati.blittable,
|
||||
};
|
||||
typeSet.Add(type, classInfo);
|
||||
classInfos.Add(classInfo);
|
||||
classInfos.Add(new ClassInfo() { type = type, typeDef = typeDef, fields = fields, layout = sa });
|
||||
}
|
||||
|
||||
private void GenerateStructDefines(List<ClassInfo> classInfos, List<string> lines)
|
||||
@@ -907,13 +523,16 @@ const ReversePInvokeMethodData hybridclr::interpreter::g_reversePInvokeMethodStu
|
||||
foreach (var ci in classInfos)
|
||||
{
|
||||
lines.Add($"// {ci.type.Klass}");
|
||||
uint packingSize = ci.packingSize;
|
||||
uint classSize = ci.classSize;
|
||||
|
||||
if (ci.layout == LayoutKind.Explicit)
|
||||
uint packingSize = ci.layout?.PackingSize ?? 0;
|
||||
if (packingSize != 0)
|
||||
{
|
||||
lines.Add($"struct {ci.type.GetTypeName()} {{");
|
||||
lines.Add("\tunion {");
|
||||
lines.Add($"#pragma pack(push, {packingSize})");
|
||||
}
|
||||
uint classSize = ci.layout?.ClassSize ?? 0;
|
||||
|
||||
if (ci.typeDef.IsExplicitLayout)
|
||||
{
|
||||
lines.Add($"union {ci.type.GetTypeName()} {{");
|
||||
if (classSize > 0)
|
||||
{
|
||||
lines.Add($"\tstruct {{ char __fieldSize_offsetPadding[{classSize}];}};");
|
||||
@@ -925,28 +544,14 @@ const ReversePInvokeMethodData hybridclr::interpreter::g_reversePInvokeMethodStu
|
||||
string fieldName = $"__{index}";
|
||||
string commentFieldName = $"{field.field.Name}";
|
||||
lines.Add("\t#pragma pack(push, 1)");
|
||||
lines.Add($"\tstruct {{ {(offset > 0 ? $"char {fieldName}_offsetPadding[{offset}]; " : "")}{field.type.GetTypeName()} {fieldName};}}; // {commentFieldName}");
|
||||
lines.Add($"\tstruct {{ {(offset > 0 ? $"char {fieldName}_offsetPadding[{offset}];" : "")} {field.type.GetTypeName()} {fieldName};}}; // {commentFieldName}");
|
||||
lines.Add($"\t#pragma pack(pop)");
|
||||
if (packingSize > 0)
|
||||
{
|
||||
lines.Add($"\t#pragma pack(push, {packingSize})");
|
||||
}
|
||||
lines.Add($"\tstruct {{ {(offset > 0 ? $"char {fieldName}_offsetPadding_forAlignmentOnly[{offset}]; " : "")}{field.type.GetTypeName()} {fieldName}_forAlignmentOnly;}}; // {commentFieldName}");
|
||||
if (packingSize > 0)
|
||||
{
|
||||
lines.Add($"\t#pragma pack(pop)");
|
||||
}
|
||||
lines.Add($"\tstruct {{ {field.type.GetTypeName()} {fieldName}_forAlignmentOnly;}}; // {commentFieldName}");
|
||||
++index;
|
||||
}
|
||||
lines.Add("\t};");
|
||||
lines.Add("};");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (packingSize != 0)
|
||||
{
|
||||
lines.Add($"#pragma pack(push, {packingSize})");
|
||||
}
|
||||
lines.Add($"{(classSize > 0 ? "union" : "struct")} {ci.type.GetTypeName()} {{");
|
||||
if (classSize > 0)
|
||||
{
|
||||
@@ -965,18 +570,18 @@ const ReversePInvokeMethodData hybridclr::interpreter::g_reversePInvokeMethodStu
|
||||
{
|
||||
lines.Add("\t};");
|
||||
}
|
||||
lines.Add("};");
|
||||
if (packingSize != 0)
|
||||
{
|
||||
lines.Add($"#pragma pack(pop)");
|
||||
}
|
||||
}
|
||||
lines.Add("};");
|
||||
if (packingSize != 0)
|
||||
{
|
||||
lines.Add($"#pragma pack(pop)");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private const string SigOfObj = "u";
|
||||
public const string SigOfObj = "u";
|
||||
|
||||
private static string ToFullName(TypeSig type)
|
||||
public static string ToFullName(TypeSig type)
|
||||
{
|
||||
type = type.RemovePinnedAndModifiers();
|
||||
switch (type.ElementType)
|
||||
@@ -1071,9 +676,9 @@ const ReversePInvokeMethodData hybridclr::interpreter::g_reversePInvokeMethodStu
|
||||
return $"{Path.GetFileNameWithoutExtension(typeDef.Module.Name)}:{typeDef.FullName}";
|
||||
}
|
||||
|
||||
private void GenerateStructureSignatureStub(List<TypeInfo> types, List<string> lines)
|
||||
public void GenerateStructureSignatureStub(List<TypeInfo> types, List<string> lines)
|
||||
{
|
||||
lines.Add("const FullName2Signature hybridclr::interpreter::g_fullName2SignatureStub[] = {");
|
||||
lines.Add("FullName2Signature hybridclr::interpreter::g_fullName2SignatureStub[] = {");
|
||||
foreach (var type in types)
|
||||
{
|
||||
TypeInfo isoType = ToIsomorphicType(type);
|
||||
@@ -1083,10 +688,10 @@ const ReversePInvokeMethodData hybridclr::interpreter::g_reversePInvokeMethodStu
|
||||
lines.Add("};");
|
||||
}
|
||||
|
||||
private void GenerateManaged2NativeStub(List<MethodDesc> methods, List<string> lines)
|
||||
public void GenerateManaged2NativeStub(List<MethodDesc> methods, List<string> lines)
|
||||
{
|
||||
lines.Add($@"
|
||||
const Managed2NativeMethodInfo hybridclr::interpreter::g_managed2nativeStub[] =
|
||||
Managed2NativeMethodInfo hybridclr::interpreter::g_managed2nativeStub[] =
|
||||
{{
|
||||
");
|
||||
|
||||
@@ -1099,10 +704,10 @@ const Managed2NativeMethodInfo hybridclr::interpreter::g_managed2nativeStub[] =
|
||||
lines.Add("};");
|
||||
}
|
||||
|
||||
private void GenerateNative2ManagedStub(List<MethodDesc> methods, List<string> lines)
|
||||
public void GenerateNative2ManagedStub(List<MethodDesc> methods, List<string> lines)
|
||||
{
|
||||
lines.Add($@"
|
||||
const Native2ManagedMethodInfo hybridclr::interpreter::g_native2managedStub[] =
|
||||
Native2ManagedMethodInfo hybridclr::interpreter::g_native2managedStub[] =
|
||||
{{
|
||||
");
|
||||
|
||||
@@ -1115,10 +720,10 @@ const Native2ManagedMethodInfo hybridclr::interpreter::g_native2managedStub[] =
|
||||
lines.Add("};");
|
||||
}
|
||||
|
||||
private void GenerateAdjustThunkStub(List<MethodDesc> methods, List<string> lines)
|
||||
public void GenerateAdjustThunkStub(List<MethodDesc> methods, List<string> lines)
|
||||
{
|
||||
lines.Add($@"
|
||||
const NativeAdjustThunkMethodInfo hybridclr::interpreter::g_adjustThunkStub[] =
|
||||
NativeAdjustThunkMethodInfo hybridclr::interpreter::g_adjustThunkStub[] =
|
||||
{{
|
||||
");
|
||||
|
||||
@@ -1141,7 +746,7 @@ const NativeAdjustThunkMethodInfo hybridclr::interpreter::g_adjustThunkStub[] =
|
||||
return type.NeedExpandValue() ? $"(uint64_t)({varName})" : $"N2MAsUint64ValueOrAddress<{type.GetTypeName()}>({varName})";
|
||||
}
|
||||
|
||||
private void GenerateManaged2NativeMethod(MethodDesc method, List<string> lines)
|
||||
public void GenerateManaged2NativeMethod(MethodDesc method, List<string> lines)
|
||||
{
|
||||
string paramListStr = string.Join(", ", method.ParamInfos.Select(p => $"{p.Type.GetTypeName()} __arg{p.Index}").Concat(new string[] { "const MethodInfo* method" }));
|
||||
string paramNameListStr = string.Join(", ", method.ParamInfos.Select(p => GetManaged2NativePassParam(p.Type, $"localVarBase+argVarIndexs[{p.Index}]")).Concat(new string[] { "method" }));
|
||||
@@ -1155,7 +760,7 @@ static void __M2N_{method.CreateCallSigName()}(const MethodInfo* method, uint16_
|
||||
");
|
||||
}
|
||||
|
||||
private string GenerateArgumentSizeAndOffset(List<ParamInfo> paramInfos)
|
||||
public string GenerateArgumentSizeAndOffset(List<ParamInfo> paramInfos)
|
||||
{
|
||||
StringBuilder s = new StringBuilder();
|
||||
int index = 0;
|
||||
@@ -1169,7 +774,7 @@ static void __M2N_{method.CreateCallSigName()}(const MethodInfo* method, uint16_
|
||||
return s.ToString();
|
||||
}
|
||||
|
||||
private string GenerateCopyArgumentToInterpreterStack(List<ParamInfo> paramInfos)
|
||||
public string GenerateCopyArgumentToInterpreterStack(List<ParamInfo> paramInfos)
|
||||
{
|
||||
StringBuilder s = new StringBuilder();
|
||||
int index = 0;
|
||||
@@ -1210,46 +815,14 @@ static {method.ReturnInfo.Type.GetTypeName()} __N2M_{(adjustorThunk ? "AdjustorT
|
||||
");
|
||||
}
|
||||
|
||||
private void GenerateNative2ManagedMethod(MethodDesc method, List<string> lines)
|
||||
public void GenerateNative2ManagedMethod(MethodDesc method, List<string> lines)
|
||||
{
|
||||
GenerateNative2ManagedMethod0(method, false, lines);
|
||||
}
|
||||
|
||||
private void GenerateAdjustThunkMethod(MethodDesc method, List<string> lines)
|
||||
public void GenerateAdjustThunkMethod(MethodDesc method, List<string> lines)
|
||||
{
|
||||
GenerateNative2ManagedMethod0(method, true, lines);
|
||||
}
|
||||
|
||||
private void GenerateManaged2NativeFunctionPointerMethod(CalliMethodInfo methodInfo, List<string> lines)
|
||||
{
|
||||
MethodDesc method = methodInfo.Method;
|
||||
string paramListStr = string.Join(", ", method.ParamInfos.Select(p => $"{p.Type.GetTypeName()} __arg{p.Index}"));
|
||||
string paramNameListStr = string.Join(", ", method.ParamInfos.Select(p => GetManaged2NativePassParam(p.Type, $"localVarBase+argVarIndexs[{p.Index}]")));
|
||||
string il2cppCallConventionName = GetIl2cppCallConventionName(methodInfo.Callvention);
|
||||
lines.Add($@"
|
||||
static void __M2NF_{methodInfo.Signature}(Il2CppMethodPointer methodPointer, uint16_t* argVarIndexs, StackObject* localVarBase, void* ret)
|
||||
{{
|
||||
typedef {method.ReturnInfo.Type.GetTypeName()} ({il2cppCallConventionName} *NativeMethod)({paramListStr});
|
||||
{(!method.ReturnInfo.IsVoid ? $"*({method.ReturnInfo.Type.GetTypeName()}*)ret = " : "")}((NativeMethod)(methodPointer))({paramNameListStr});
|
||||
}}
|
||||
");
|
||||
}
|
||||
|
||||
private void GenerateManaged2NativeFunctionPointerMethodStub(List<CalliMethodInfo> calliMethodSignatures, List<string> lines)
|
||||
{
|
||||
lines.Add(@"
|
||||
const Managed2NativeFunctionPointerCallData hybridclr::interpreter::g_managed2NativeFunctionPointerCallStub[]
|
||||
{
|
||||
");
|
||||
foreach (var method in calliMethodSignatures)
|
||||
{
|
||||
lines.Add($"\t{{\"{method.Signature}\", __M2NF_{method.Signature}}},");
|
||||
}
|
||||
|
||||
lines.Add(@"
|
||||
{nullptr, nullptr},
|
||||
};
|
||||
");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e42a0f3bcbc5ddf438a85ae16c1b3116
|
||||
guid: d550ac0e8f92e464c824432e14d33824
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
using dnlib.DotNet;
|
||||
using HybridCLR.Editor.ABI;
|
||||
using HybridCLR.Editor.Meta;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using CallingConvention = System.Runtime.InteropServices.CallingConvention;
|
||||
using UnityEngine;
|
||||
|
||||
namespace HybridCLR.Editor.MethodBridge
|
||||
{
|
||||
public class RawMonoPInvokeCallbackMethodInfo
|
||||
{
|
||||
public MethodDef Method { get; set; }
|
||||
|
||||
public CustomAttribute GenerationAttribute { get; set; }
|
||||
}
|
||||
|
||||
public class MonoPInvokeCallbackAnalyzer
|
||||
{
|
||||
|
||||
private readonly List<ModuleDefMD> _rootModules = new List<ModuleDefMD>();
|
||||
|
||||
private readonly List<RawMonoPInvokeCallbackMethodInfo> _reversePInvokeMethods = new List<RawMonoPInvokeCallbackMethodInfo>();
|
||||
|
||||
public List<RawMonoPInvokeCallbackMethodInfo> ReversePInvokeMethods => _reversePInvokeMethods;
|
||||
|
||||
public MonoPInvokeCallbackAnalyzer(AssemblyCache cache, List<string> assemblyNames)
|
||||
{
|
||||
foreach (var assemblyName in assemblyNames)
|
||||
{
|
||||
_rootModules.Add(cache.LoadModule(assemblyName));
|
||||
}
|
||||
}
|
||||
|
||||
private void CollectReversePInvokeMethods()
|
||||
{
|
||||
foreach (var mod in _rootModules)
|
||||
{
|
||||
Debug.Log($"ass:{mod.FullName} method count:{mod.Metadata.TablesStream.MethodTable.Rows}");
|
||||
for (uint rid = 1, n = mod.Metadata.TablesStream.MethodTable.Rows; rid <= n; rid++)
|
||||
{
|
||||
var method = mod.ResolveMethod(rid);
|
||||
//Debug.Log($"method:{method}");
|
||||
if (!method.IsStatic || !method.HasCustomAttributes)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
CustomAttribute wa = method.CustomAttributes.FirstOrDefault(ca => ca.AttributeType.Name == "MonoPInvokeCallbackAttribute");
|
||||
if (wa == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (!MetaUtil.IsSupportedPInvokeMethodSignature(method.MethodSig))
|
||||
{
|
||||
Debug.LogError($"MonoPInvokeCallback method {method.FullName} has unsupported parameter or return type. Please check the method signature.");
|
||||
}
|
||||
//foreach (var ca in method.CustomAttributes)
|
||||
//{
|
||||
// Debug.Log($"{ca.AttributeType.FullName} {ca.TypeFullName}");
|
||||
//}
|
||||
_reversePInvokeMethods.Add(new RawMonoPInvokeCallbackMethodInfo()
|
||||
{
|
||||
Method = method,
|
||||
GenerationAttribute = method.CustomAttributes.FirstOrDefault(ca => ca.AttributeType.FullName == "HybridCLR.ReversePInvokeWrapperGenerationAttribute"),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Run()
|
||||
{
|
||||
CollectReversePInvokeMethods();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c172068b408c0e349b2ceee4c4635085
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,50 +0,0 @@
|
||||
using dnlib.DotNet;
|
||||
using HybridCLR.Editor.Meta;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
|
||||
namespace HybridCLR.Editor.MethodBridge
|
||||
{
|
||||
|
||||
public class PInvokeAnalyzer
|
||||
{
|
||||
private readonly List<ModuleDefMD> _rootModules = new List<ModuleDefMD>();
|
||||
|
||||
private readonly List<CallNativeMethodSignatureInfo> _pinvokeMethodSignatures = new List<CallNativeMethodSignatureInfo>();
|
||||
|
||||
public List<CallNativeMethodSignatureInfo> PInvokeMethodSignatures => _pinvokeMethodSignatures;
|
||||
|
||||
public PInvokeAnalyzer(AssemblyCache cache, List<string> assemblyNames)
|
||||
{
|
||||
foreach (var assemblyName in assemblyNames)
|
||||
{
|
||||
_rootModules.Add(cache.LoadModule(assemblyName));
|
||||
}
|
||||
}
|
||||
|
||||
public void Run()
|
||||
{
|
||||
foreach (var mod in _rootModules)
|
||||
{
|
||||
foreach (TypeDef type in mod.GetTypes())
|
||||
{
|
||||
foreach (MethodDef method in type.Methods)
|
||||
{
|
||||
if (method.IsPinvokeImpl)
|
||||
{
|
||||
if (!MetaUtil.IsSupportedPInvokeMethodSignature(method.MethodSig))
|
||||
{
|
||||
Debug.LogError($"PInvoke method {method.FullName} has unsupported parameter or return type. Please check the method signature.");
|
||||
}
|
||||
_pinvokeMethodSignatures.Add(new CallNativeMethodSignatureInfo { MethodSig = method.MethodSig });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9923175c961b78849aeaf99708e294ce
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user