main
walon 2022-10-17 12:16:18 +08:00
parent d7a1765146
commit 9ea240ab82
46 changed files with 542 additions and 288 deletions

8
Editor/ABI.meta Normal file
View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: d26c8b77c84f09442a05f2c67e5e09b8
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -7,9 +7,9 @@ using System.Text;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace HybridCLR.Editor.MethodBridge namespace HybridCLR.Editor.ABI
{ {
public class MethodBridgeSig : IEquatable<MethodBridgeSig> public class MethodDesc : IEquatable<MethodDesc>
{ {
public MethodDef MethodDef { get; set; } public MethodDef MethodDef { get; set; }
@ -17,6 +17,8 @@ namespace HybridCLR.Editor.MethodBridge
public List<ParamInfo> ParamInfos { get; set; } public List<ParamInfo> ParamInfos { get; set; }
private int _hashCode;
public void Init() public void Init()
{ {
for(int i = 0; i < ParamInfos.Count; i++) for(int i = 0; i < ParamInfos.Count; i++)
@ -58,10 +60,10 @@ namespace HybridCLR.Editor.MethodBridge
public override bool Equals(object obj) public override bool Equals(object obj)
{ {
return Equals((MethodBridgeSig)obj); return Equals((MethodDesc)obj);
} }
public bool Equals(MethodBridgeSig other) public bool Equals(MethodDesc other)
{ {
if (other == null) if (other == null)
{ {
@ -88,6 +90,10 @@ namespace HybridCLR.Editor.MethodBridge
public override int GetHashCode() public override int GetHashCode()
{ {
if (_hashCode != 0)
{
return _hashCode;
}
int hash = 17; int hash = 17;
hash = hash * 23 + ReturnInfo.Type.GetHashCode(); hash = hash * 23 + ReturnInfo.Type.GetHashCode();
@ -97,7 +103,7 @@ namespace HybridCLR.Editor.MethodBridge
hash = hash * 23 + p.Type.GetHashCode(); hash = hash * 23 + p.Type.GetHashCode();
} }
return hash; return _hashCode = hash;
} }
} }
} }

View File

@ -5,7 +5,7 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace HybridCLR.Editor.MethodBridge namespace HybridCLR.Editor.ABI
{ {
public class ParamInfo public class ParamInfo

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: f97bd67938e4a9c4b9c8ddcdad621f60 guid: f2ba16cf4bf82374c814789b6ced3abd
MonoImporter: MonoImporter:
externalObjects: {} externalObjects: {}
serializedVersion: 2 serializedVersion: 2

View File

@ -4,7 +4,7 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace HybridCLR.Editor.MethodBridge namespace HybridCLR.Editor.ABI
{ {
public enum ParamOrReturnType public enum ParamOrReturnType
{ {

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: 6070162cd5afff74f99af129c50fda5a guid: 80682e47c38a2f04f8af94d356688cf0
MonoImporter: MonoImporter:
externalObjects: {} externalObjects: {}
serializedVersion: 2 serializedVersion: 2

View File

@ -1,4 +1,4 @@
namespace HybridCLR.Editor.MethodBridge namespace HybridCLR.Editor.ABI
{ {
public enum PlatformABI public enum PlatformABI
{ {

View File

@ -0,0 +1,46 @@
using dnlib.DotNet;
using HybridCLR.Editor.Meta;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HybridCLR.Editor.ABI
{
public class HFATypeInfo
{
public TypeSig Type { get; set; }
public int Count { get; set; }
}
public class TypeCreatorArm64 : TypeCreatorBase
{
public override bool IsArch32 => false;
public override bool IsSupportHFA => true;
protected override TypeInfo OptimizeSigType(TypeInfo type, bool returnType)
{
if (!type.IsGeneralValueType)
{
return type;
}
int typeSize = type.Size;
if (typeSize <= 8)
{
return TypeInfo.s_i8;
}
if (typeSize <= 16)
{
return TypeInfo.s_i16;
}
if (returnType)
{
return type.PorType != ParamOrReturnType.STRUCTURE_ALIGN1 ? new TypeInfo(ParamOrReturnType.STRUCTURE_ALIGN1, typeSize) : type;
}
return TypeInfo.s_ref;
}
}
}

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: 103704591750908419902643015e920a guid: a22846b73022cb2458d1c40549ab6877
MonoImporter: MonoImporter:
externalObjects: {} externalObjects: {}
serializedVersion: 2 serializedVersion: 2

View File

@ -3,66 +3,35 @@ using HybridCLR.Editor.Meta;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using UnityEngine;
namespace HybridCLR.Editor.MethodBridge namespace HybridCLR.Editor.ABI
{ {
public abstract class PlatformAdaptorBase public abstract class TypeCreatorBase
{ {
private static readonly ValueTypeSizeAligmentCalculator s_calculator64 = new ValueTypeSizeAligmentCalculator(false);
private static readonly ValueTypeSizeAligmentCalculator s_calculator32 = new ValueTypeSizeAligmentCalculator(true);
public abstract bool IsArch32 { get; } public abstract bool IsArch32 { get; }
public virtual bool IsSupportHFA => false; public virtual bool IsSupportHFA => false;
public TypeInfo GetNativeIntTypeInfo() => IsArch32 ? TypeInfo.s_i4 : TypeInfo.s_i8; public TypeInfo GetNativeIntTypeInfo() => IsArch32 ? TypeInfo.s_i4 : TypeInfo.s_i8;
public abstract void GenerateManaged2NativeMethod(MethodBridgeSig method, List<string> lines); public ValueTypeSizeAligmentCalculator Calculator => IsArch32 ? ValueTypeSizeAligmentCalculator.Caculator32 : ValueTypeSizeAligmentCalculator.Caculator64;
public abstract void GenerateNative2ManagedMethod(MethodBridgeSig method, List<string> lines);
public abstract void GenerateAdjustThunkMethod(MethodBridgeSig method, List<string> outputLines); private readonly Dictionary<TypeSig, (int, int)> _typeSizeCache = new Dictionary<TypeSig, (int, int)>(TypeEqualityComparer.Instance);
protected abstract TypeInfo OptimizeSigType(TypeInfo type, bool returnType); public (int Size, int Aligment) ComputeSizeAndAligment(TypeSig t)
public virtual void OptimizeMethod(MethodBridgeSig method)
{ {
method.TransfromSigTypes(OptimizeSigType); if (_typeSizeCache.TryGetValue(t, out var sizeAndAligment))
}
private readonly Dictionary<TypeSig, (int, int)> _typeSizeCache64 = new Dictionary<TypeSig, (int, int)>(TypeEqualityComparer.Instance);
private readonly Dictionary<TypeSig, (int, int)> _typeSizeCache32 = new Dictionary<TypeSig, (int, int)>(TypeEqualityComparer.Instance);
public (int Size, int Aligment) ComputeSizeAndAligmentOfArch64(TypeSig t)
{
if (_typeSizeCache64.TryGetValue(t, out var sizeAndAligment))
{ {
return sizeAndAligment; return sizeAndAligment;
} }
sizeAndAligment = s_calculator64.SizeAndAligmentOf(t); sizeAndAligment = Calculator.SizeAndAligmentOf(t);
_typeSizeCache64.Add(t, sizeAndAligment); _typeSizeCache.Add(t, sizeAndAligment);
return sizeAndAligment; return sizeAndAligment;
} }
protected (int Size, int Aligment) ComputeSizeAndAligmentOfArch32(TypeSig t)
{
if (_typeSizeCache32.TryGetValue(t, out var sa))
{
return sa;
}
// all this just to invoke one opcode with no arguments!
sa = s_calculator32.SizeAndAligmentOf(t);
_typeSizeCache32.Add(t, sa);
return sa;
}
public TypeInfo CreateTypeInfo(TypeSig type) public TypeInfo CreateTypeInfo(TypeSig type)
{ {
type = type.RemovePinnedAndModifiers(); type = type.RemovePinnedAndModifiers();
@ -70,7 +39,7 @@ namespace HybridCLR.Editor.MethodBridge
{ {
return GetNativeIntTypeInfo(); return GetNativeIntTypeInfo();
} }
switch(type.ElementType) switch (type.ElementType)
{ {
case ElementType.Void: return TypeInfo.s_void; case ElementType.Void: return TypeInfo.s_void;
case ElementType.Boolean: return TypeInfo.s_u1; case ElementType.Boolean: return TypeInfo.s_u1;
@ -147,7 +116,7 @@ namespace HybridCLR.Editor.MethodBridge
continue; continue;
} }
TypeSig ftype = ctx != null ? MetaUtil.Inflate(field.FieldType, ctx) : field.FieldType; TypeSig ftype = ctx != null ? MetaUtil.Inflate(field.FieldType, ctx) : field.FieldType;
switch(ftype.ElementType) switch (ftype.ElementType)
{ {
case ElementType.R4: case ElementType.R4:
case ElementType.R8: case ElementType.R8:
@ -203,7 +172,7 @@ namespace HybridCLR.Editor.MethodBridge
protected static TypeInfo CreateGeneralValueType(TypeSig type, int size, int aligment) protected static TypeInfo CreateGeneralValueType(TypeSig type, int size, int aligment)
{ {
Debug.Assert(size % aligment == 0); System.Diagnostics.Debug.Assert(size % aligment == 0);
switch (aligment) switch (aligment)
{ {
case 1: return new TypeInfo(ParamOrReturnType.STRUCTURE_ALIGN1, size); case 1: return new TypeInfo(ParamOrReturnType.STRUCTURE_ALIGN1, size);
@ -216,7 +185,7 @@ namespace HybridCLR.Editor.MethodBridge
protected TypeInfo CreateValueType(TypeSig type) protected TypeInfo CreateValueType(TypeSig type)
{ {
(int typeSize, int typeAligment) = IsArch32 ? ComputeSizeAndAligmentOfArch32(type) : ComputeSizeAndAligmentOfArch64(type); (int typeSize, int typeAligment) = ComputeSizeAndAligment(type);
if (IsSupportHFA && ComputHFATypeInfo(type, typeSize, out HFATypeInfo hfaTypeInfo)) if (IsSupportHFA && ComputHFATypeInfo(type, typeSize, out HFATypeInfo hfaTypeInfo))
{ {
bool isFloat = hfaTypeInfo.Type.ElementType == ElementType.R4; bool isFloat = hfaTypeInfo.Type.ElementType == ElementType.R4;
@ -235,52 +204,12 @@ namespace HybridCLR.Editor.MethodBridge
} }
} }
public void GenerateManaged2NativeStub(List<MethodBridgeSig> methods, List<string> lines)
protected abstract TypeInfo OptimizeSigType(TypeInfo type, bool returnType);
public virtual void OptimizeMethod(MethodDesc method)
{ {
lines.Add($@" method.TransfromSigTypes(OptimizeSigType);
Managed2NativeMethodInfo hybridclr::interpreter::g_managed2nativeStub[] =
{{
");
foreach (var method in methods)
{
lines.Add($"\t{{\"{method.CreateInvokeSigName()}\", __M2N_{method.CreateInvokeSigName()}}},");
}
lines.Add($"\t{{nullptr, nullptr}},");
lines.Add("};");
}
public void GenerateNative2ManagedStub(List<MethodBridgeSig> methods, List<string> lines)
{
lines.Add($@"
Native2ManagedMethodInfo hybridclr::interpreter::g_native2managedStub[] =
{{
");
foreach (var method in methods)
{
lines.Add($"\t{{\"{method.CreateInvokeSigName()}\", (Il2CppMethodPointer)__N2M_{method.CreateInvokeSigName()}}},");
}
lines.Add($"\t{{nullptr, nullptr}},");
lines.Add("};");
}
public void GenerateAdjustThunkStub(List<MethodBridgeSig> methods, List<string> lines)
{
lines.Add($@"
NativeAdjustThunkMethodInfo hybridclr::interpreter::g_adjustThunkStub[] =
{{
");
foreach (var method in methods)
{
lines.Add($"\t{{\"{method.CreateInvokeSigName()}\", (Il2CppMethodPointer)__N2M_AdjustorThunk_{method.CreateCallSigName()}}},");
}
lines.Add($"\t{{nullptr, nullptr}},");
lines.Add("};");
} }
} }
} }

View File

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

View File

@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HybridCLR.Editor.ABI
{
public static class TypeCreatorFactory
{
public static TypeCreatorBase CreateTypeCreator(PlatformABI abi)
{
switch(abi)
{
case PlatformABI.Arm64: return new TypeCreatorArm64();
case PlatformABI.Universal32: return new TypeCreatorUniversal32();
case PlatformABI.Universal64: return new TypeCreatorUniversal64();
default: throw new NotSupportedException(abi.ToString());
}
}
}
}

View File

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

View File

@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HybridCLR.Editor.ABI
{
public class TypeCreatorUniversal32 : TypeCreatorBase
{
public override bool IsArch32 => true;
public override bool IsSupportHFA => false;
protected override TypeInfo OptimizeSigType(TypeInfo type, bool returnType)
{
if (type.PorType > ParamOrReturnType.STRUCTURE_ALIGN1 && type.PorType <= ParamOrReturnType.STRUCTURE_ALIGN4)
{
return new TypeInfo(ParamOrReturnType.STRUCTURE_ALIGN1, type.Size);
}
return type;
}
}
}

View File

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

View File

@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HybridCLR.Editor.ABI
{
public class TypeCreatorUniversal64 : TypeCreatorBase
{
public override bool IsArch32 => false;
public override bool IsSupportHFA => true;
protected override TypeInfo OptimizeSigType(TypeInfo type, bool returnType)
{
if (type.PorType > ParamOrReturnType.STRUCTURE_ALIGN1 && type.PorType <= ParamOrReturnType.STRUCTURE_ALIGN8)
{
return new TypeInfo(ParamOrReturnType.STRUCTURE_ALIGN1, type.Size);
}
return type;
}
}
}

View File

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

View File

@ -4,7 +4,7 @@ using System.Collections.Generic;
using System.Reflection; using System.Reflection;
using UnityEngine; using UnityEngine;
namespace HybridCLR.Editor.MethodBridge namespace HybridCLR.Editor.ABI
{ {
public class TypeInfo : IEquatable<TypeInfo> public class TypeInfo : IEquatable<TypeInfo>
{ {

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: 804237f201e1f7a4da1729e0eb11f75f guid: ffafce7f1f0bf614d95b48ca39385377
MonoImporter: MonoImporter:
externalObjects: {} externalObjects: {}
serializedVersion: 2 serializedVersion: 2

View File

@ -9,10 +9,14 @@ using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using UnityEngine; using UnityEngine;
namespace HybridCLR.Editor.MethodBridge namespace HybridCLR.Editor.ABI
{ {
public class ValueTypeSizeAligmentCalculator public class ValueTypeSizeAligmentCalculator
{ {
public static ValueTypeSizeAligmentCalculator Caculator64 { get; } = new ValueTypeSizeAligmentCalculator(false);
public static ValueTypeSizeAligmentCalculator Caculator32 { get; } = new ValueTypeSizeAligmentCalculator(true);
public ValueTypeSizeAligmentCalculator(bool arch32) public ValueTypeSizeAligmentCalculator(bool arch32)
{ {
_referenceSize = arch32 ? 4 : 8; _referenceSize = arch32 ? 4 : 8;

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: 40dd1d9a2278f7846a9baa2041f74858 guid: b7af32bdf1cf55c42bfc449820d401cb
MonoImporter: MonoImporter:
externalObjects: {} externalObjects: {}
serializedVersion: 2 serializedVersion: 2

View File

@ -32,8 +32,8 @@ namespace HybridCLR.Editor.AOT
public override bool Equals(object obj) public override bool Equals(object obj)
{ {
ImplType o = (ImplType)obj; ImplType o = (ImplType)obj;
return EqualityUtil.EqualsTypeSig(this.BaseType, o.BaseType) return MetaUtil.EqualsTypeSig(this.BaseType, o.BaseType)
&& EqualityUtil.EqualsTypeSigArray(this.Interfaces, o.Interfaces) && MetaUtil.EqualsTypeSigArray(this.Interfaces, o.Interfaces)
&& this.ValueType == o.ValueType; && this.ValueType == o.ValueType;
} }

View File

@ -45,7 +45,7 @@ namespace HybridCLR.Editor.Commands
} }
} }
var analyzer = new Analyzer(MetaUtil.CreateBuildTargetAssemblyResolver(EditorUserBuildSettings.activeBuildTarget), HybridCLRSettings.Instance.collectAssetReferenceTypes); var analyzer = new Analyzer(Meta.MetaUtil.CreateBuildTargetAssemblyResolver(EditorUserBuildSettings.activeBuildTarget), HybridCLRSettings.Instance.collectAssetReferenceTypes);
var refTypes = analyzer.CollectRefs(hotfixAssembles); var refTypes = analyzer.CollectRefs(hotfixAssembles);
Debug.Log($"[LinkGeneratorCommand] hotfix assembly count:{hotfixAssembles.Count}, ref type count:{refTypes.Count} output:{Application.dataPath}/{ls.outputLinkFile}"); Debug.Log($"[LinkGeneratorCommand] hotfix assembly count:{hotfixAssembles.Count}, ref type count:{refTypes.Count} output:{Application.dataPath}/{ls.outputLinkFile}");

View File

@ -1,4 +1,5 @@
using HybridCLR.Editor; using HybridCLR.Editor;
using HybridCLR.Editor.ABI;
using HybridCLR.Editor.Meta; using HybridCLR.Editor.Meta;
using HybridCLR.Editor.MethodBridge; using HybridCLR.Editor.MethodBridge;
using System; using System;
@ -45,7 +46,7 @@ namespace HybridCLR.Editor.Commands
{ {
var g = new Generator(new Generator.Options() var g = new Generator(new Generator.Options()
{ {
CallConvention = platform, PlatformABI = platform,
TemplateCode = templateCode, TemplateCode = templateCode,
OutputFile = outputFile, OutputFile = outputFile,
GenericMethods = analyzer.GenericMethods, GenericMethods = analyzer.GenericMethods,

View File

@ -1,5 +1,6 @@
using HybridCLR.Editor.Link; using HybridCLR.Editor.ABI;
using HybridCLR.Editor.ReversePInvokeWrap; using HybridCLR.Editor.Link;
using HybridCLR.Editor.Meta;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
@ -19,13 +20,32 @@ namespace HybridCLR.Editor.Commands
[MenuItem("HybridCLR/Generate/ReversePInvokeWrapper", priority = 103)] [MenuItem("HybridCLR/Generate/ReversePInvokeWrapper", priority = 103)]
public static void GenerateReversePInvokeWrapper() public static void GenerateReversePInvokeWrapper()
{ {
string ReversePInvokeWrapperStubFile = $"{SettingsUtil.LocalIl2CppDir}/libil2cpp/hybridclr/metadata/ReversePInvokeMethodStub.cpp"; CompileDllCommand.CompileDllActiveBuildTarget();
string wrapperTemplateStr = File.ReadAllText($"{SettingsUtil.TemplatePathInPackage}/ReversePInvokeMethodStub.cpp.txt"); using (var cache = new AssemblyCache(MetaUtil.CreateBuildTargetAssemblyResolver(EditorUserBuildSettings.activeBuildTarget)))
int wrapperCount = SettingsUtil.HybridCLRSettings.ReversePInvokeWrapperCount; {
var generator = new Generator(); var analyzer = new ReversePInvokeWrap.Analyzer(cache, SettingsUtil.HotUpdateAssemblyNames);
generator.Generate(wrapperTemplateStr, wrapperCount,ReversePInvokeWrapperStubFile); var methods = analyzer.CollectMonoPInvokeCallbackMethods();
Debug.Log($"GenerateReversePInvokeWrapper. wraperCount:{wrapperCount} output:{ReversePInvokeWrapperStubFile}"); foreach (var method in methods)
MethodBridgeGeneratorCommand.CleanIl2CppBuildCache(); {
Debug.Log($"method:{method.Method}");
}
var generateJobs = new List<(PlatformABI, string)>()
{
(PlatformABI.Arm64, "HYBRIDCLR_ABI_ARM_64"),
(PlatformABI.Universal64, "HYBRIDCLR_ABI_UNIVERSAL_64"),
(PlatformABI.Universal32, "HYBRIDCLR_ABI_UNIVERSAL_32"),
};
}
return;
//string ReversePInvokeWrapperStubFile = $"{SettingsUtil.LocalIl2CppDir}/libil2cpp/hybridclr/metadata/ReversePInvokeMethodStub.cpp";
//string wrapperTemplateStr = File.ReadAllText($"{SettingsUtil.TemplatePathInPackage}/ReversePInvokeMethodStub.cpp.txt");
//int wrapperCount = SettingsUtil.HybridCLRSettings.ReversePInvokeWrapperCount;
//var generator = new Generator();
//generator.Generate(wrapperTemplateStr, wrapperCount,ReversePInvokeWrapperStubFile);
//Debug.Log($"GenerateReversePInvokeWrapper. wraperCount:{wrapperCount} output:{ReversePInvokeWrapperStubFile}");
//MethodBridgeGeneratorCommand.CleanIl2CppBuildCache();
} }
} }
} }

View File

@ -1,49 +0,0 @@
using dnlib.DotNet;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HybridCLR.Editor
{
public static class EqualityUtil
{
public static bool EqualsTypeSig(TypeSig a, TypeSig b)
{
if (a == b)
{
return true;
}
if (a != null && b != null)
{
return TypeEqualityComparer.Instance.Equals(a, b);
}
return false;
}
public static bool EqualsTypeSigArray(List<TypeSig> a, List<TypeSig> b)
{
if (a == b)
{
return true;
}
if (a != null && b != null)
{
if (a.Count != b.Count)
{
return false;
}
for (int i = 0; i < a.Count; i++)
{
if (!TypeEqualityComparer.Instance.Equals(a[i], b[i]))
{
return false;
}
}
return true;
}
return false;
}
}
}

View File

@ -1,7 +1,9 @@
{ {
"name": "HybridCLR.Editor", "name": "HybridCLR.Editor",
"rootNamespace": "", "rootNamespace": "",
"references": [], "references": [
"HybridCLR.Runtime"
],
"includePlatforms": [ "includePlatforms": [
"Editor" "Editor"
], ],

View File

@ -29,7 +29,7 @@ namespace HybridCLR.Editor.Meta
{ {
if (obj is GenericClass gc) if (obj is GenericClass gc)
{ {
return Type == gc.Type && EqualityUtil.EqualsTypeSigArray(KlassInst, gc.KlassInst); return Type == gc.Type && MetaUtil.EqualsTypeSigArray(KlassInst, gc.KlassInst);
} }
return false; return false;
} }

View File

@ -33,8 +33,8 @@ namespace HybridCLR.Editor.Meta
{ {
GenericMethod o = (GenericMethod)obj; GenericMethod o = (GenericMethod)obj;
return Method == o.Method return Method == o.Method
&& EqualityUtil.EqualsTypeSigArray(KlassInst, o.KlassInst) && MetaUtil.EqualsTypeSigArray(KlassInst, o.KlassInst)
&& EqualityUtil.EqualsTypeSigArray(MethodInst, o.MethodInst); && MetaUtil.EqualsTypeSigArray(MethodInst, o.MethodInst);
} }
public override int GetHashCode() public override int GetHashCode()

View File

@ -6,12 +6,49 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using IAssemblyResolver = HybridCLR.Editor.Meta.IAssemblyResolver;
namespace HybridCLR.Editor namespace HybridCLR.Editor.Meta
{ {
public static class MetaUtil public static class MetaUtil
{ {
public static bool EqualsTypeSig(TypeSig a, TypeSig b)
{
if (a == b)
{
return true;
}
if (a != null && b != null)
{
return TypeEqualityComparer.Instance.Equals(a, b);
}
return false;
}
public static bool EqualsTypeSigArray(List<TypeSig> a, List<TypeSig> b)
{
if (a == b)
{
return true;
}
if (a != null && b != null)
{
if (a.Count != b.Count)
{
return false;
}
for (int i = 0; i < a.Count; i++)
{
if (!TypeEqualityComparer.Instance.Equals(a[i], b[i]))
{
return false;
}
}
return true;
}
return false;
}
public static TypeSig Inflate(TypeSig sig, GenericArgumentContext ctx) public static TypeSig Inflate(TypeSig sig, GenericArgumentContext ctx)
{ {
if (!sig.ContainsGenericParameter) if (!sig.ContainsGenericParameter)

View File

@ -1,4 +1,5 @@
using dnlib.DotNet; using dnlib.DotNet;
using HybridCLR.Editor.ABI;
using HybridCLR.Editor.Meta; using HybridCLR.Editor.Meta;
using HybridCLR.Editor.Template; using HybridCLR.Editor.Template;
using System; using System;
@ -10,6 +11,7 @@ using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using UnityEditor; using UnityEditor;
using UnityEngine; using UnityEngine;
using TypeInfo = HybridCLR.Editor.ABI.TypeInfo;
namespace HybridCLR.Editor.MethodBridge namespace HybridCLR.Editor.MethodBridge
{ {
@ -17,7 +19,7 @@ namespace HybridCLR.Editor.MethodBridge
{ {
public class Options public class Options
{ {
public PlatformABI CallConvention { get; set; } public PlatformABI PlatformABI { get; set; }
public string TemplateCode { get; set; } public string TemplateCode { get; set; }
@ -36,19 +38,21 @@ namespace HybridCLR.Editor.MethodBridge
private readonly string _outputFile; private readonly string _outputFile;
private readonly PlatformAdaptorBase _platformAdaptor; private readonly PlatformGeneratorBase _platformAdaptor;
private readonly HashSet<MethodBridgeSig> _managed2nativeMethodSet = new HashSet<MethodBridgeSig>(); private readonly TypeCreatorBase _typeCreator;
private List<MethodBridgeSig> _managed2nativeMethodList; private readonly HashSet<MethodDesc> _managed2nativeMethodSet = new HashSet<MethodDesc>();
private readonly HashSet<MethodBridgeSig> _native2managedMethodSet = new HashSet<MethodBridgeSig>(); private List<MethodDesc> _managed2nativeMethodList;
private List<MethodBridgeSig> _native2managedMethodList; private readonly HashSet<MethodDesc> _native2managedMethodSet = new HashSet<MethodDesc>();
private readonly HashSet<MethodBridgeSig> _adjustThunkMethodSet = new HashSet<MethodBridgeSig>(); private List<MethodDesc> _native2managedMethodList;
private List<MethodBridgeSig> _adjustThunkMethodList; private readonly HashSet<MethodDesc> _adjustThunkMethodSet = new HashSet<MethodDesc>();
private List<MethodDesc> _adjustThunkMethodList;
public Generator(Options options) public Generator(Options options)
{ {
@ -56,21 +60,22 @@ namespace HybridCLR.Editor.MethodBridge
_genericMethods = options.GenericMethods; _genericMethods = options.GenericMethods;
_templateCode = options.TemplateCode; _templateCode = options.TemplateCode;
_outputFile = options.OutputFile; _outputFile = options.OutputFile;
_platformAdaptor = CreatePlatformAdaptor(options.CallConvention); _platformAdaptor = CreatePlatformAdaptor(options.PlatformABI);
_typeCreator = TypeCreatorFactory.CreateTypeCreator(options.PlatformABI);
} }
private static PlatformAdaptorBase CreatePlatformAdaptor(PlatformABI type) private static PlatformGeneratorBase CreatePlatformAdaptor(PlatformABI type)
{ {
switch (type) switch (type)
{ {
case PlatformABI.Universal32: return new PlatformAdaptor_Universal32(); case PlatformABI.Universal32: return new PlatformGeneratorUniversal32();
case PlatformABI.Universal64: return new PlatformAdaptor_Universal64(); case PlatformABI.Universal64: return new PlatformGeneratorUniversal64();
case PlatformABI.Arm64: return new PlatformAdaptor_Arm64(); case PlatformABI.Arm64: return new PlatformGeneratorArm64();
default: throw new NotSupportedException(); default: throw new NotSupportedException();
} }
} }
private MethodBridgeSig CreateMethodBridgeSig(MethodDef methodDef, bool forceRemoveThis, TypeSig returnType, List<TypeSig> parameters) private MethodDesc CreateMethodDesc(MethodDef methodDef, bool forceRemoveThis, TypeSig returnType, List<TypeSig> parameters)
{ {
var paramInfos = new List<ParamInfo>(); var paramInfos = new List<ParamInfo>();
if (forceRemoveThis && !methodDef.IsStatic) if (forceRemoveThis && !methodDef.IsStatic)
@ -79,19 +84,19 @@ namespace HybridCLR.Editor.MethodBridge
} }
foreach (var paramInfo in parameters) foreach (var paramInfo in parameters)
{ {
paramInfos.Add(new ParamInfo() { Type = _platformAdaptor.CreateTypeInfo(paramInfo) }); paramInfos.Add(new ParamInfo() { Type = _typeCreator.CreateTypeInfo(paramInfo) });
} }
var mbs = new MethodBridgeSig() var mbs = new MethodDesc()
{ {
MethodDef = methodDef, MethodDef = methodDef,
ReturnInfo = new ReturnInfo() { Type = returnType != null ? _platformAdaptor.CreateTypeInfo(returnType) : TypeInfo.s_void }, ReturnInfo = new ReturnInfo() { Type = returnType != null ? _typeCreator.CreateTypeInfo(returnType) : TypeInfo.s_void },
ParamInfos = paramInfos, ParamInfos = paramInfos,
}; };
_platformAdaptor.OptimizeMethod(mbs); _typeCreator.OptimizeMethod(mbs);
return mbs; return mbs;
} }
private void AddManaged2NativeMethod(MethodBridgeSig method) private void AddManaged2NativeMethod(MethodDesc method)
{ {
if (_managed2nativeMethodSet.Add(method)) if (_managed2nativeMethodSet.Add(method))
{ {
@ -99,7 +104,7 @@ namespace HybridCLR.Editor.MethodBridge
} }
} }
private void AddNative2ManagedMethod(MethodBridgeSig method) private void AddNative2ManagedMethod(MethodDesc method)
{ {
if (_native2managedMethodSet.Add(method)) if (_native2managedMethodSet.Add(method))
{ {
@ -107,7 +112,7 @@ namespace HybridCLR.Editor.MethodBridge
} }
} }
private void AddAdjustThunkMethod(MethodBridgeSig method) private void AddAdjustThunkMethod(MethodDesc method)
{ {
if (_adjustThunkMethodSet.Add(method)) if (_adjustThunkMethodSet.Add(method))
{ {
@ -136,7 +141,7 @@ namespace HybridCLR.Editor.MethodBridge
parameters = method.Parameters.Select(p => MetaUtil.Inflate(p.Type, gc)).ToList(); parameters = method.Parameters.Select(p => MetaUtil.Inflate(p.Type, gc)).ToList();
} }
var m2nMethod = CreateMethodBridgeSig(method, false, returnType, parameters); var m2nMethod = CreateMethodDesc(method, false, returnType, parameters);
AddManaged2NativeMethod(m2nMethod); AddManaged2NativeMethod(m2nMethod);
if (method.IsVirtual) if (method.IsVirtual)
@ -145,12 +150,12 @@ namespace HybridCLR.Editor.MethodBridge
{ {
AddAdjustThunkMethod(m2nMethod); AddAdjustThunkMethod(m2nMethod);
} }
//var adjustThunkMethod = CreateMethodBridgeSig(method, true, returnType, parameters); //var adjustThunkMethod = CreateMethodDesc(method, true, returnType, parameters);
AddNative2ManagedMethod(m2nMethod); AddNative2ManagedMethod(m2nMethod);
} }
if (method.Name == "Invoke" && method.DeclaringType.IsDelegate) if (method.Name == "Invoke" && method.DeclaringType.IsDelegate)
{ {
var openMethod = CreateMethodBridgeSig(method, true, returnType, parameters); var openMethod = CreateMethodDesc(method, true, returnType, parameters);
AddNative2ManagedMethod(openMethod); AddNative2ManagedMethod(openMethod);
} }
} }
@ -168,7 +173,7 @@ namespace HybridCLR.Editor.MethodBridge
} }
{ {
var sortedMethods = new SortedDictionary<string, MethodBridgeSig>(); var sortedMethods = new SortedDictionary<string, MethodDesc>();
foreach (var method in _managed2nativeMethodSet) foreach (var method in _managed2nativeMethodSet)
{ {
sortedMethods.Add(method.CreateCallSigName(), method); sortedMethods.Add(method.CreateCallSigName(), method);
@ -176,7 +181,7 @@ namespace HybridCLR.Editor.MethodBridge
_managed2nativeMethodList = sortedMethods.Values.ToList(); _managed2nativeMethodList = sortedMethods.Values.ToList();
} }
{ {
var sortedMethods = new SortedDictionary<string, MethodBridgeSig>(); var sortedMethods = new SortedDictionary<string, MethodDesc>();
foreach (var method in _native2managedMethodSet) foreach (var method in _native2managedMethodSet)
{ {
sortedMethods.Add(method.CreateCallSigName(), method); sortedMethods.Add(method.CreateCallSigName(), method);
@ -184,7 +189,7 @@ namespace HybridCLR.Editor.MethodBridge
_native2managedMethodList = sortedMethods.Values.ToList(); _native2managedMethodList = sortedMethods.Values.ToList();
} }
{ {
var sortedMethods = new SortedDictionary<string, MethodBridgeSig>(); var sortedMethods = new SortedDictionary<string, MethodDesc>();
foreach (var method in _adjustThunkMethodSet) foreach (var method in _adjustThunkMethodSet)
{ {
sortedMethods.Add(method.CreateCallSigName(), method); sortedMethods.Add(method.CreateCallSigName(), method);

View File

@ -1,4 +1,5 @@
using dnlib.DotNet; using dnlib.DotNet;
using HybridCLR.Editor.ABI;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@ -10,48 +11,17 @@ using UnityEngine;
namespace HybridCLR.Editor.MethodBridge namespace HybridCLR.Editor.MethodBridge
{ {
public class HFATypeInfo
{
public TypeSig Type { get; set; }
public int Count { get; set; }
}
public class PlatformAdaptor_Arm64 : PlatformAdaptorBase public class PlatformGeneratorArm64 : PlatformGeneratorBase
{ {
public PlatformABI CallConventionType { get; } = PlatformABI.Universal64; public override PlatformABI PlatformABI { get; } = PlatformABI.Universal64;
public override bool IsArch32 => false; public override void GenerateManaged2NativeMethod(MethodDesc method, List<string> lines)
public override bool IsSupportHFA => true;
protected override TypeInfo OptimizeSigType(TypeInfo type, bool returnType)
{ {
if (!type.IsGeneralValueType) int totalQuadWordNum = method.ParamInfos.Count + method.ReturnInfo.GetParamSlotNum(this.PlatformABI);
{
return type;
}
int typeSize = type.Size;
if (typeSize <= 8)
{
return TypeInfo.s_i8;
}
if (typeSize <= 16)
{
return TypeInfo.s_i16;
}
if (returnType)
{
return type.PorType != ParamOrReturnType.STRUCTURE_ALIGN1 ? new TypeInfo(ParamOrReturnType.STRUCTURE_ALIGN1, typeSize) : type;
}
return TypeInfo.s_ref;
}
public override void GenerateManaged2NativeMethod(MethodBridgeSig method, List<string> lines)
{
int totalQuadWordNum = method.ParamInfos.Count + method.ReturnInfo.GetParamSlotNum(this.CallConventionType);
string paramListStr = string.Join(", ", method.ParamInfos.Select(p => $"{p.Type.GetTypeName()} __arg{p.Index}").Concat(new string[] { "const MethodInfo* method" })); 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 => p.Managed2NativeParamValue(this.CallConventionType)).Concat(new string[] { "method" })); string paramNameListStr = string.Join(", ", method.ParamInfos.Select(p => p.Managed2NativeParamValue(this.PlatformABI)).Concat(new string[] { "method" }));
lines.Add($@" lines.Add($@"
// {method.MethodDef} // {method.MethodDef}
@ -63,16 +33,16 @@ static void __M2N_{method.CreateCallSigName()}(const MethodInfo* method, uint16_
"); ");
} }
public override void GenerateNative2ManagedMethod(MethodBridgeSig method, List<string> lines) public override void GenerateNative2ManagedMethod(MethodDesc method, List<string> lines)
{ {
int totalQuadWordNum = method.ParamInfos.Count + method.ReturnInfo.GetParamSlotNum(this.CallConventionType); int totalQuadWordNum = method.ParamInfos.Count + method.ReturnInfo.GetParamSlotNum(this.PlatformABI);
string paramListStr = string.Join(", ", method.ParamInfos.Select(p => $"{p.Type.GetTypeName()} __arg{p.Index}").Concat(new string[] { "const MethodInfo* method" })); string paramListStr = string.Join(", ", method.ParamInfos.Select(p => $"{p.Type.GetTypeName()} __arg{p.Index}").Concat(new string[] { "const MethodInfo* method" }));
lines.Add($@" lines.Add($@"
// {method.MethodDef} // {method.MethodDef}
static {method.ReturnInfo.Type.GetTypeName()} __N2M_{method.CreateCallSigName()}({paramListStr}) static {method.ReturnInfo.Type.GetTypeName()} __N2M_{method.CreateCallSigName()}({paramListStr})
{{ {{
StackObject args[{Math.Max(totalQuadWordNum, 1)}] = {{{string.Join(", ", method.ParamInfos.Select(p => p.Native2ManagedParamValue(this.CallConventionType)))} }}; StackObject args[{Math.Max(totalQuadWordNum, 1)}] = {{{string.Join(", ", method.ParamInfos.Select(p => p.Native2ManagedParamValue(this.PlatformABI)))} }};
StackObject* ret = {(method.ReturnInfo.IsVoid ? "nullptr" : "args + " + method.ParamInfos.Count)}; StackObject* ret = {(method.ReturnInfo.IsVoid ? "nullptr" : "args + " + method.ParamInfos.Count)};
Interpreter::Execute(method, args, ret); Interpreter::Execute(method, args, ret);
{(!method.ReturnInfo.IsVoid ? $"return *({method.ReturnInfo.Type.GetTypeName()}*)ret;" : "")} {(!method.ReturnInfo.IsVoid ? $"return *({method.ReturnInfo.Type.GetTypeName()}*)ret;" : "")}
@ -80,9 +50,9 @@ static {method.ReturnInfo.Type.GetTypeName()} __N2M_{method.CreateCallSigName()}
"); ");
} }
public override void GenerateAdjustThunkMethod(MethodBridgeSig method, List<string> lines) public override void GenerateAdjustThunkMethod(MethodDesc method, List<string> lines)
{ {
int totalQuadWordNum = method.ParamInfos.Count + method.ReturnInfo.GetParamSlotNum(this.CallConventionType); int totalQuadWordNum = method.ParamInfos.Count + method.ReturnInfo.GetParamSlotNum(this.PlatformABI);
string paramListStr = string.Join(", ", method.ParamInfos.Select(p => $"{p.Type.GetTypeName()} __arg{p.Index}").Concat(new string[] { "const MethodInfo* method" })); string paramListStr = string.Join(", ", method.ParamInfos.Select(p => $"{p.Type.GetTypeName()} __arg{p.Index}").Concat(new string[] { "const MethodInfo* method" }));
@ -90,7 +60,7 @@ static {method.ReturnInfo.Type.GetTypeName()} __N2M_{method.CreateCallSigName()}
// {method.MethodDef} // {method.MethodDef}
static {method.ReturnInfo.Type.GetTypeName()} __N2M_AdjustorThunk_{method.CreateCallSigName()}({paramListStr}) static {method.ReturnInfo.Type.GetTypeName()} __N2M_AdjustorThunk_{method.CreateCallSigName()}({paramListStr})
{{ {{
StackObject args[{Math.Max(totalQuadWordNum, 1)}] = {{{string.Join(", ", method.ParamInfos.Select(p => (p.Index == 0 ? $"(uint64_t)(*(uint8_t**)&__arg{p.Index} + sizeof(Il2CppObject))" : p.Native2ManagedParamValue(this.CallConventionType))))} }}; StackObject args[{Math.Max(totalQuadWordNum, 1)}] = {{{string.Join(", ", method.ParamInfos.Select(p => (p.Index == 0 ? $"(uint64_t)(*(uint8_t**)&__arg{p.Index} + sizeof(Il2CppObject))" : p.Native2ManagedParamValue(this.PlatformABI))))} }};
StackObject* ret = {(method.ReturnInfo.IsVoid ? "nullptr" : "args + " + method.ParamInfos.Count)}; StackObject* ret = {(method.ReturnInfo.IsVoid ? "nullptr" : "args + " + method.ParamInfos.Count)};
Interpreter::Execute(method, args, ret); Interpreter::Execute(method, args, ret);
{(!method.ReturnInfo.IsVoid ? $"return *({method.ReturnInfo.Type.GetTypeName()}*)ret;" : "")} {(!method.ReturnInfo.IsVoid ? $"return *({method.ReturnInfo.Type.GetTypeName()}*)ret;" : "")}

View File

@ -0,0 +1,75 @@
using dnlib.DotNet;
using HybridCLR.Editor.ABI;
using HybridCLR.Editor.Meta;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
using TypeInfo = HybridCLR.Editor.ABI.TypeInfo;
namespace HybridCLR.Editor.MethodBridge
{
public abstract class PlatformGeneratorBase
{
public abstract PlatformABI PlatformABI { get; }
public abstract void GenerateManaged2NativeMethod(MethodDesc method, List<string> lines);
public abstract void GenerateNative2ManagedMethod(MethodDesc method, List<string> lines);
public abstract void GenerateAdjustThunkMethod(MethodDesc method, List<string> outputLines);
public void GenerateManaged2NativeStub(List<MethodDesc> methods, List<string> lines)
{
lines.Add($@"
Managed2NativeMethodInfo hybridclr::interpreter::g_managed2nativeStub[] =
{{
");
foreach (var method in methods)
{
lines.Add($"\t{{\"{method.CreateInvokeSigName()}\", __M2N_{method.CreateInvokeSigName()}}},");
}
lines.Add($"\t{{nullptr, nullptr}},");
lines.Add("};");
}
public void GenerateNative2ManagedStub(List<MethodDesc> methods, List<string> lines)
{
lines.Add($@"
Native2ManagedMethodInfo hybridclr::interpreter::g_native2managedStub[] =
{{
");
foreach (var method in methods)
{
lines.Add($"\t{{\"{method.CreateInvokeSigName()}\", (Il2CppMethodPointer)__N2M_{method.CreateInvokeSigName()}}},");
}
lines.Add($"\t{{nullptr, nullptr}},");
lines.Add("};");
}
public void GenerateAdjustThunkStub(List<MethodDesc> methods, List<string> lines)
{
lines.Add($@"
NativeAdjustThunkMethodInfo hybridclr::interpreter::g_adjustThunkStub[] =
{{
");
foreach (var method in methods)
{
lines.Add($"\t{{\"{method.CreateInvokeSigName()}\", (Il2CppMethodPointer)__N2M_AdjustorThunk_{method.CreateCallSigName()}}},");
}
lines.Add($"\t{{nullptr, nullptr}},");
lines.Add("};");
}
}
}

View File

@ -1,4 +1,5 @@
using dnlib.DotNet; using dnlib.DotNet;
using HybridCLR.Editor.ABI;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@ -9,11 +10,9 @@ using UnityEngine;
namespace HybridCLR.Editor.MethodBridge namespace HybridCLR.Editor.MethodBridge
{ {
internal class PlatformAdaptor_Universal32 : PlatformAdaptorBase public class PlatformGeneratorUniversal32 : PlatformGeneratorBase
{ {
public PlatformABI CallConventionType { get; } = PlatformABI.Universal32; public override PlatformABI PlatformABI { get; } = PlatformABI.Universal32;
public override bool IsArch32 => true;
//protected override TypeInfo CreateValueType(TypeSig type, bool returnValue) //protected override TypeInfo CreateValueType(TypeSig type, bool returnValue)
//{ //{
@ -22,19 +21,11 @@ namespace HybridCLR.Editor.MethodBridge
// return CreateGeneralValueType(type, typeSize, actualAliment); // return CreateGeneralValueType(type, typeSize, actualAliment);
//} //}
protected override TypeInfo OptimizeSigType(TypeInfo type, bool returnType)
{
if (type.PorType > ParamOrReturnType.STRUCTURE_ALIGN1 && type.PorType <= ParamOrReturnType.STRUCTURE_ALIGN4)
{
return new TypeInfo(ParamOrReturnType.STRUCTURE_ALIGN1, type.Size);
}
return type;
}
public override void GenerateManaged2NativeMethod(MethodBridgeSig method, List<string> lines) public override 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 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 => p.Managed2NativeParamValue(this.CallConventionType)).Concat(new string[] { "method" })); string paramNameListStr = string.Join(", ", method.ParamInfos.Select(p => p.Managed2NativeParamValue(this.PlatformABI)).Concat(new string[] { "method" }));
lines.Add($@" lines.Add($@"
// {method.MethodDef} // {method.MethodDef}
@ -45,25 +36,25 @@ static void __M2N_{method.CreateCallSigName()}(const MethodInfo* method, uint16_
}} }}
"); ");
} }
public override void GenerateNative2ManagedMethod(MethodBridgeSig method, List<string> lines) public override void GenerateNative2ManagedMethod(MethodDesc method, List<string> lines)
{ {
int totalQuadWordNum = method.ParamInfos.Count + method.ReturnInfo.GetParamSlotNum(this.CallConventionType); int totalQuadWordNum = method.ParamInfos.Count + method.ReturnInfo.GetParamSlotNum(this.PlatformABI);
string paramListStr = string.Join(", ", method.ParamInfos.Select(p => $"{p.Type.GetTypeName()} __arg{p.Index}").Concat(new string[] { "const MethodInfo* method" })); string paramListStr = string.Join(", ", method.ParamInfos.Select(p => $"{p.Type.GetTypeName()} __arg{p.Index}").Concat(new string[] { "const MethodInfo* method" }));
lines.Add($@" lines.Add($@"
// {method.MethodDef} // {method.MethodDef}
static {method.ReturnInfo.Type.GetTypeName()} __N2M_{method.CreateCallSigName()}({paramListStr}) static {method.ReturnInfo.Type.GetTypeName()} __N2M_{method.CreateCallSigName()}({paramListStr})
{{ {{
StackObject args[{Math.Max(totalQuadWordNum, 1)}] = {{{string.Join(", ", method.ParamInfos.Select(p => p.Native2ManagedParamValue(this.CallConventionType)))} }}; StackObject args[{Math.Max(totalQuadWordNum, 1)}] = {{{string.Join(", ", method.ParamInfos.Select(p => p.Native2ManagedParamValue(this.PlatformABI)))} }};
StackObject* ret = {(method.ReturnInfo.IsVoid ? "nullptr" : "args + " + method.ParamInfos.Count)}; StackObject* ret = {(method.ReturnInfo.IsVoid ? "nullptr" : "args + " + method.ParamInfos.Count)};
Interpreter::Execute(method, args, ret); Interpreter::Execute(method, args, ret);
{(!method.ReturnInfo.IsVoid ? $"return *({method.ReturnInfo.Type.GetTypeName()}*)ret;" : "")} {(!method.ReturnInfo.IsVoid ? $"return *({method.ReturnInfo.Type.GetTypeName()}*)ret;" : "")}
}} }}
"); ");
} }
public override void GenerateAdjustThunkMethod(MethodBridgeSig method, List<string> lines) public override void GenerateAdjustThunkMethod(MethodDesc method, List<string> lines)
{ {
int totalQuadWordNum = method.ParamInfos.Count + method.ReturnInfo.GetParamSlotNum(this.CallConventionType); int totalQuadWordNum = method.ParamInfos.Count + method.ReturnInfo.GetParamSlotNum(this.PlatformABI);
string paramListStr = string.Join(", ", method.ParamInfos.Select(p => $"{p.Type.GetTypeName()} __arg{p.Index}").Concat(new string[] { "const MethodInfo* method" })); string paramListStr = string.Join(", ", method.ParamInfos.Select(p => $"{p.Type.GetTypeName()} __arg{p.Index}").Concat(new string[] { "const MethodInfo* method" }));
@ -71,7 +62,7 @@ static {method.ReturnInfo.Type.GetTypeName()} __N2M_{method.CreateCallSigName()}
// {method.MethodDef} // {method.MethodDef}
static {method.ReturnInfo.Type.GetTypeName()} __N2M_AdjustorThunk_{method.CreateCallSigName()}({paramListStr}) static {method.ReturnInfo.Type.GetTypeName()} __N2M_AdjustorThunk_{method.CreateCallSigName()}({paramListStr})
{{ {{
StackObject args[{Math.Max(totalQuadWordNum, 1)}] = {{{string.Join(", ", method.ParamInfos.Select(p => (p.Index == 0 ? $"(uint64_t)(*(uint8_t**)&__arg{p.Index} + sizeof(Il2CppObject))" : p.Native2ManagedParamValue(this.CallConventionType))))} }}; StackObject args[{Math.Max(totalQuadWordNum, 1)}] = {{{string.Join(", ", method.ParamInfos.Select(p => (p.Index == 0 ? $"(uint64_t)(*(uint8_t**)&__arg{p.Index} + sizeof(Il2CppObject))" : p.Native2ManagedParamValue(this.PlatformABI))))} }};
StackObject* ret = {(method.ReturnInfo.IsVoid ? "nullptr" : "args + " + method.ParamInfos.Count)}; StackObject* ret = {(method.ReturnInfo.IsVoid ? "nullptr" : "args + " + method.ParamInfos.Count)};
Interpreter::Execute(method, args, ret); Interpreter::Execute(method, args, ret);
{(!method.ReturnInfo.IsVoid ? $"return *({method.ReturnInfo.Type.GetTypeName()}*)ret;" : "")} {(!method.ReturnInfo.IsVoid ? $"return *({method.ReturnInfo.Type.GetTypeName()}*)ret;" : "")}

View File

@ -1,4 +1,5 @@
using dnlib.DotNet; using dnlib.DotNet;
using HybridCLR.Editor.ABI;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@ -6,33 +7,21 @@ using System.Reflection;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using UnityEngine; using UnityEngine;
using TypeInfo = HybridCLR.Editor.ABI.TypeInfo;
namespace HybridCLR.Editor.MethodBridge namespace HybridCLR.Editor.MethodBridge
{ {
public class PlatformAdaptor_Universal64 : PlatformAdaptorBase public class PlatformGeneratorUniversal64 : PlatformGeneratorBase
{ {
public PlatformABI CallConventionType { get; } = PlatformABI.Universal64; public override PlatformABI PlatformABI { get; } = PlatformABI.Universal64;
public override bool IsArch32 => false; public override void GenerateManaged2NativeMethod(MethodDesc method, List<string> lines)
public override bool IsSupportHFA => true;
protected override TypeInfo OptimizeSigType(TypeInfo type, bool returnType)
{ {
if (type.PorType > ParamOrReturnType.STRUCTURE_ALIGN1 && type.PorType <= ParamOrReturnType.STRUCTURE_ALIGN8) int totalQuadWordNum = method.ParamInfos.Count + method.ReturnInfo.GetParamSlotNum(this.PlatformABI);
{
return new TypeInfo(ParamOrReturnType.STRUCTURE_ALIGN1, type.Size);
}
return type;
}
public override void GenerateManaged2NativeMethod(MethodBridgeSig method, List<string> lines)
{
int totalQuadWordNum = method.ParamInfos.Count + method.ReturnInfo.GetParamSlotNum(this.CallConventionType);
string paramListStr = string.Join(", ", method.ParamInfos.Select(p => $"{p.Type.GetTypeName()} __arg{p.Index}").Concat(new string[] { "const MethodInfo* method" })); string paramListStr = string.Join(", ", method.ParamInfos.Select(p => $"{p.Type.GetTypeName()} __arg{p.Index}").Concat(new string[] { "const MethodInfo* method" }));
string paramTypeListStr = string.Join(", ", method.ParamInfos.Select(p => $"{p.Type.GetTypeName()}").Concat(new string[] { "const MethodInfo*" })); ; string paramTypeListStr = string.Join(", ", method.ParamInfos.Select(p => $"{p.Type.GetTypeName()}").Concat(new string[] { "const MethodInfo*" })); ;
string paramNameListStr = string.Join(", ", method.ParamInfos.Select(p => p.Managed2NativeParamValue(this.CallConventionType)).Concat(new string[] { "method" })); string paramNameListStr = string.Join(", ", method.ParamInfos.Select(p => p.Managed2NativeParamValue(this.PlatformABI)).Concat(new string[] { "method" }));
lines.Add($@" lines.Add($@"
// {method.MethodDef} // {method.MethodDef}
@ -43,15 +32,15 @@ static void __M2N_{method.CreateCallSigName()}(const MethodInfo* method, uint16_
}} }}
"); ");
} }
public override void GenerateNative2ManagedMethod(MethodBridgeSig method, List<string> lines) public override void GenerateNative2ManagedMethod(MethodDesc method, List<string> lines)
{ {
int totalQuadWordNum = method.ParamInfos.Count + method.ReturnInfo.GetParamSlotNum(this.CallConventionType); int totalQuadWordNum = method.ParamInfos.Count + method.ReturnInfo.GetParamSlotNum(this.PlatformABI);
string paramListStr = string.Join(", ", method.ParamInfos.Select(p => $"{p.Type.GetTypeName()} __arg{p.Index}").Concat(new string[] { "const MethodInfo* method" })); string paramListStr = string.Join(", ", method.ParamInfos.Select(p => $"{p.Type.GetTypeName()} __arg{p.Index}").Concat(new string[] { "const MethodInfo* method" }));
lines.Add($@" lines.Add($@"
// {method.MethodDef} // {method.MethodDef}
static {method.ReturnInfo.Type.GetTypeName()} __N2M_{method.CreateCallSigName()}({paramListStr}) static {method.ReturnInfo.Type.GetTypeName()} __N2M_{method.CreateCallSigName()}({paramListStr})
{{ {{
StackObject args[{Math.Max(totalQuadWordNum, 1)}] = {{{string.Join(", ", method.ParamInfos.Select(p => p.Native2ManagedParamValue(this.CallConventionType)))} }}; StackObject args[{Math.Max(totalQuadWordNum, 1)}] = {{{string.Join(", ", method.ParamInfos.Select(p => p.Native2ManagedParamValue(this.PlatformABI)))} }};
StackObject* ret = {(method.ReturnInfo.IsVoid ? "nullptr" : "args + " + method.ParamInfos.Count)}; StackObject* ret = {(method.ReturnInfo.IsVoid ? "nullptr" : "args + " + method.ParamInfos.Count)};
Interpreter::Execute(method, args, ret); Interpreter::Execute(method, args, ret);
{(!method.ReturnInfo.IsVoid ? $"return *({method.ReturnInfo.Type.GetTypeName()}*)ret;" : "")} {(!method.ReturnInfo.IsVoid ? $"return *({method.ReturnInfo.Type.GetTypeName()}*)ret;" : "")}
@ -59,15 +48,15 @@ static {method.ReturnInfo.Type.GetTypeName()} __N2M_{method.CreateCallSigName()}
"); ");
} }
public override void GenerateAdjustThunkMethod(MethodBridgeSig method, List<string> lines) public override void GenerateAdjustThunkMethod(MethodDesc method, List<string> lines)
{ {
int totalQuadWordNum = method.ParamInfos.Count + method.ReturnInfo.GetParamSlotNum(this.CallConventionType); int totalQuadWordNum = method.ParamInfos.Count + method.ReturnInfo.GetParamSlotNum(this.PlatformABI);
string paramListStr = string.Join(", ", method.ParamInfos.Select(p => $"{p.Type.GetTypeName()} __arg{p.Index}").Concat(new string[] { "const MethodInfo* method" })); string paramListStr = string.Join(", ", method.ParamInfos.Select(p => $"{p.Type.GetTypeName()} __arg{p.Index}").Concat(new string[] { "const MethodInfo* method" }));
lines.Add($@" lines.Add($@"
// {method.MethodDef} // {method.MethodDef}
static {method.ReturnInfo.Type.GetTypeName()} __N2M_AdjustorThunk_{method.CreateCallSigName()}({paramListStr}) static {method.ReturnInfo.Type.GetTypeName()} __N2M_AdjustorThunk_{method.CreateCallSigName()}({paramListStr})
{{ {{
StackObject args[{Math.Max(totalQuadWordNum, 1)}] = {{{string.Join(", ", method.ParamInfos.Select(p => (p.Index == 0 ? $"(uint64_t)(*(uint8_t**)&__arg{p.Index} + sizeof(Il2CppObject))" : p.Native2ManagedParamValue(this.CallConventionType))))} }}; StackObject args[{Math.Max(totalQuadWordNum, 1)}] = {{{string.Join(", ", method.ParamInfos.Select(p => (p.Index == 0 ? $"(uint64_t)(*(uint8_t**)&__arg{p.Index} + sizeof(Il2CppObject))" : p.Native2ManagedParamValue(this.PlatformABI))))} }};
StackObject* ret = {(method.ReturnInfo.IsVoid ? "nullptr" : "args + " + method.ParamInfos.Count)}; StackObject* ret = {(method.ReturnInfo.IsVoid ? "nullptr" : "args + " + method.ParamInfos.Count)};
Interpreter::Execute(method, args, ret); Interpreter::Execute(method, args, ret);
{(!method.ReturnInfo.IsVoid ? $"return *({method.ReturnInfo.Type.GetTypeName()}*)ret;" : "")} {(!method.ReturnInfo.IsVoid ? $"return *({method.ReturnInfo.Type.GetTypeName()}*)ret;" : "")}

View File

@ -0,0 +1,65 @@
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.ReversePInvokeWrap
{
public class ReversePInvokeMethodInfo
{
public MethodDef Method { get; set; }
public CustomAttribute GenerationAttribute { get; set; }
}
public class Analyzer
{
private readonly List<ModuleDefMD> _rootModules = new List<ModuleDefMD>();
public Analyzer(AssemblyCache cache, List<string> assemblyNames)
{
foreach(var assemblyName in assemblyNames)
{
_rootModules.Add(cache.LoadModule(assemblyName));
}
}
public List<ReversePInvokeMethodInfo> CollectMonoPInvokeCallbackMethods()
{
var wrapperMethods = new List<ReversePInvokeMethodInfo>();
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.IsStatic || !method.HasCustomAttributes)
{
continue;
}
CustomAttribute wa = method.CustomAttributes.FirstOrDefault(ca => ca.AttributeType.FullName == "AOT.MonoPInvokeCallbackAttribute");
if (wa == null)
{
continue;
}
//foreach (var ca in method.CustomAttributes)
//{
// Debug.Log($"{ca.AttributeType.FullName} {ca.TypeFullName}");
//}
wrapperMethods.Add(new ReversePInvokeMethodInfo()
{
Method = method,
GenerationAttribute = method.CustomAttributes.FirstOrDefault(ca => ca.AttributeType.FullName == "HybridCLR.ReversePInvokeWrapperGenerationAttribute"),
});
}
}
return wrapperMethods;
}
}
}

View File

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

View File

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HybridCLR
{
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class ReversePInvokeWrapperGenerationAttribute : Attribute
{
public int ReserveWrapperCount { get; }
public ReversePInvokeWrapperGenerationAttribute(int reserveWrapperCount)
{
ReserveWrapperCount = reserveWrapperCount;
}
}
}

View File

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