更新HybirdCLR

更新HybirdCLR
This commit is contained in:
ALEXTANG
2022-10-24 20:36:52 +08:00
parent 6eb4f25137
commit 5186b2f8fc
60 changed files with 1 additions and 2861 deletions

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 5441af6e690e22643970bc4bafba0eb9
guid: f775bd6af30f702448064119d19be43f
folderAsset: yes
DefaultImporter:
externalObjects: {}

View File

@@ -1,42 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using HybridCLR.Editor;
using TEngine.Runtime;
using UnityEditor;
using UnityEngine;
namespace TEngine.Editor
{
/// <summary>
/// HybirdCLR 热更新 打包插入管线
/// </summary>
public static class HybirdCLRInjectorEditor
{
[TEngineBuilderInjector(BuilderInjectorMoment.BeforeCollect_AssetBundle)]
public static void BeforeCollectAssetBundle()
{
CompileDllHelper.CompileDllActiveBuildTarget();
Log.Warning("CompileDllHelper.CompileDllActiveBuildTarget()");
var target = EditorUserBuildSettings.activeBuildTarget;
var dllDir = Constant.Setting.AssetRootPath+"/Dll";
string hotfixDllSrcDir = BuildConfig.GetHotFixDllsOutputDirByTarget(target);
foreach (var dll in BuildConfig.HotUpdateAssemblies)
{
string dllPath = $"{hotfixDllSrcDir}/{dll}";
string dllBytesPath = $"{dllDir}/{dll}.bytes";
try
{
File.Copy(dllPath, dllBytesPath, true);
}
catch (Exception e)
{
Log.Fatal(e.Message);
}
}
}
}
}

View File

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

View File

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

View File

@@ -1,69 +0,0 @@
using System;
using System.IO;
using UnityEditor;
using UnityEngine;
namespace HybridCLR.Editor
{
#pragma warning disable CS0162
public static partial class BuildConfig
{
#if !UNITY_IOS
[InitializeOnLoadMethod]
private static void Setup()
{
//TODO
return;
var localIl2cppDir = LocalIl2CppDir;
if (!Directory.Exists(localIl2cppDir))
{
Debug.LogError($"本地il2cpp目录:{localIl2cppDir} 不存在未安装本地il2cpp。请在菜单 HybridCLR/Installer 中执行安装");
}
Environment.SetEnvironmentVariable("UNITY_IL2CPP_PATH", localIl2cppDir);
}
#endif
public static string ProjectDir => Directory.GetParent(Application.dataPath).ToString();
public static string ScriptingAssembliesJsonFile { get; } = "ScriptingAssemblies.json";
public static string HybridCLRBuildCacheDir => Application.dataPath + "/HybridCLRBuildCache";
public static string HotFixDllsOutputDir => $"{HybridCLRDataDir}/HotFixDlls";
public static string AssetBundleOutputDir => $"{HybridCLRBuildCacheDir}/AssetBundleOutput";
public static string AssetBundleSourceDataTempDir => $"{HybridCLRBuildCacheDir}/AssetBundleSourceData";
public static string HybridCLRDataDir { get; } = $"{ProjectDir}/HybridCLRData";
public static string AssembliesPostIl2CppStripDir => $"{HybridCLRDataDir}/AssembliesPostIl2CppStrip";
public static string LocalIl2CppDir => $"{HybridCLRDataDir}/LocalIl2CppData/il2cpp";
public static string MethodBridgeCppDir => $"{LocalIl2CppDir}/libil2cpp/hybridclr/interpreter";
public static string Il2CppBuildCacheDir { get; } = $"{ProjectDir}/Library/Il2cppBuildCache";
public static string GetHotFixDllsOutputDirByTarget(BuildTarget target)
{
return $"{HotFixDllsOutputDir}/{target}";
}
public static string GetAssembliesPostIl2CppStripDir(BuildTarget target)
{
return $"{AssembliesPostIl2CppStripDir}/{target}";
}
public static string GetAssetBundleOutputDirByTarget(BuildTarget target)
{
return $"{AssetBundleOutputDir}/{target}";
}
public static string GetAssetBundleTempDirByTarget(BuildTarget target)
{
return $"{AssetBundleSourceDataTempDir}/{target}";
}
}
}

View File

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

View File

@@ -1,22 +0,0 @@
using System.Collections.Generic;
namespace HybridCLR.Editor
{
public static partial class BuildConfig
{
/// <summary>
/// 所有热更新dll列表。放到此列表中的dll在构建AB的插入管线执行。
/// </summary>
public static List<string> HotUpdateAssemblies { get; } = new List<string>
{
"HotFix.dll",
};
public static List<string> AOTMetaAssemblies { get; } = new List<string>()
{
"mscorlib.dll",
"System.dll",
"System.Core.dll",
};
}
}

View File

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

View File

@@ -1,65 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEditor;
using UnityEditor.Build.Player;
using UnityEngine;
namespace HybridCLR.Editor
{
internal class CompileDllHelper
{
public static void CompileDll(string buildDir, BuildTarget target)
{
var group = BuildPipeline.GetBuildTargetGroup(target);
ScriptCompilationSettings scriptCompilationSettings = new ScriptCompilationSettings();
scriptCompilationSettings.group = group;
scriptCompilationSettings.target = target;
Directory.CreateDirectory(buildDir);
ScriptCompilationResult scriptCompilationResult = PlayerBuildInterface.CompilePlayerScripts(scriptCompilationSettings, buildDir);
foreach (var ass in scriptCompilationResult.assemblies)
{
Debug.LogFormat("compile assemblies:{1}/{0}", ass, buildDir);
}
}
public static void CompileDll(BuildTarget target)
{
CompileDll(BuildConfig.GetHotFixDllsOutputDirByTarget(target), target);
}
[MenuItem("HybridCLR/CompileDll/ActiveBuildTarget")]
public static void CompileDllActiveBuildTarget()
{
CompileDll(EditorUserBuildSettings.activeBuildTarget);
}
[MenuItem("HybridCLR/CompileDll/Win32")]
public static void CompileDllWin32()
{
CompileDll(BuildTarget.StandaloneWindows);
}
[MenuItem("HybridCLR/CompileDll/Win64")]
public static void CompileDllWin64()
{
CompileDll(BuildTarget.StandaloneWindows64);
}
[MenuItem("HybridCLR/CompileDll/Android")]
public static void CompileDllAndroid()
{
CompileDll(BuildTarget.Android);
}
[MenuItem("HybridCLR/CompileDll/IOS")]
public static void CompileDllIOS()
{
CompileDll(BuildTarget.iOS);
}
}
}

View File

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

View File

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

View File

@@ -1,13 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HybridCLR.Editor.Generators
{
internal static class ConstStrings
{
public const string typeObjectPtr = "Il2CppObject*";
}
}

View File

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

View File

@@ -1,40 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HybridCLR.Editor.Generators
{
public class FileRegionReplace
{
private readonly string _tplFile;
private readonly Dictionary<string, string> _regionReplaceContents = new Dictionary<string, string>();
public FileRegionReplace(string tplFile)
{
_tplFile = tplFile;
}
public void Replace(string regionName, string regionContent)
{
_regionReplaceContents.Add(regionName, regionContent);
}
public void Commit(string outputFile)
{
string originContent = File.ReadAllText(_tplFile, Encoding.UTF8);
string resultContent = originContent;
foreach (var c in _regionReplaceContents)
{
resultContent = TemplateUtil.ReplaceRegion(resultContent, c.Key, c.Value);
}
var utf8WithoutBOM = new System.Text.UTF8Encoding(false);
File.WriteAllText(outputFile, resultContent, utf8WithoutBOM);
}
}
}

View File

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

View File

@@ -1,70 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
namespace HybridCLR.Editor.Generators
{
internal class GeneratorConfig
{
/// <summary>
/// 目前已经根据热更新dll的依赖自动计算需要扫描哪些dll来收集桥接函数。
/// 只要你的热更新以assembly def形式放到项目中是不需要改这个的
/// </summary>
/// <returns></returns>
public static List<string> GetExtraAssembiles()
{
return new List<string>
{
// "mscorlib",
};
}
/// <summary>
/// 暂时没有仔细扫描泛型,如果运行时发现有生成缺失,先手动在此添加类
/// </summary>
/// <returns></returns>
public static List<Type> PrepareCustomGenericTypes()
{
return new List<Type>
{
typeof(Action<int, string, Vector3>),
};
}
/// <summary>
/// 如果提示缺失桥接函数,将提示缺失的签名加入到下列列表是简单的做法。
/// 这里添加64位App缺失的桥接函数签名
/// </summary>
/// <returns></returns>
public static List<string> PrepareCustomMethodSignatures64()
{
return new List<string>
{
"vi8i8",
"i4i8i8i4i4i8i8",
"i8i8S12",
"S12i8S12",
"S12i8S12S12",
"i16i8i16i16",
};
}
/// <summary>
/// 如果提示缺失桥接函数,将提示缺失的签名加入到下列列表是简单的做法。
/// 这里添加32位App缺失的桥接函数签名
/// </summary>
/// <returns></returns>
public static List<string> PrepareCustomMethodSignatures32()
{
return new List<string>
{
"vi4i4",
"S12i4S12S12",
};
}
}
}

View File

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

View File

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

View File

@@ -1,28 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace HybridCLR.Editor.Generators.MethodBridge
{
public interface IPlatformAdaptor
{
bool IsArch32 { get; }
TypeInfo CreateTypeInfo(Type type, bool returnValue);
void GenerateManaged2NativeMethod(MethodBridgeSig method, List<string> outputLines);
void GenerateManaged2NativeStub(List<MethodBridgeSig> methods, List<string> lines);
void GenerateNative2ManagedMethod(MethodBridgeSig method, List<string> outputLines);
void GenerateNative2ManagedStub(List<MethodBridgeSig> methods, List<string> lines);
void GenerateAdjustThunkMethod(MethodBridgeSig method, List<string> outputLines);
void GenerateAdjustThunkStub(List<MethodBridgeSig> methods, List<string> lines);
}
}

View File

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

View File

@@ -1,353 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using UnityEditor;
using UnityEngine;
namespace HybridCLR.Editor.Generators.MethodBridge
{
public class TypeGenInfo
{
public Type Type { get; set; }
public List<MethodInfo> GenericMethods { get; set; }
}
public class MethodBridgeGeneratorOptions
{
public List<Assembly> HotfixAssemblies { get; set; }
public List<Assembly> AllAssemblies { get; set; }
public PlatformABI CallConvention { get; set; }
public string OutputFile { get; set; }
public bool Optimized { get; set; }
}
public class MethodBridgeGenerator
{
private readonly HashSet<Assembly> _hotfixAssemblies;
private readonly List<Assembly> _assemblies;
private readonly PlatformABI _callConvention;
private readonly string _outputFile;
public readonly bool _optimized;
private readonly IPlatformAdaptor _platformAdaptor;
private readonly HashSet<MethodBridgeSig> _managed2nativeMethodSet = new HashSet<MethodBridgeSig>();
private List<MethodBridgeSig> _managed2nativeMethodList;
private readonly HashSet<MethodBridgeSig> _native2managedMethodSet = new HashSet<MethodBridgeSig>();
private List<MethodBridgeSig> _native2managedMethodList;
private readonly HashSet<MethodBridgeSig> _adjustThunkMethodSet = new HashSet<MethodBridgeSig>();
private List<MethodBridgeSig> _adjustThunkMethodList;
public bool IsHotFixType(Type type)
{
return _hotfixAssemblies.Contains(type.Assembly);
}
public MethodBridgeGenerator(MethodBridgeGeneratorOptions options)
{
_hotfixAssemblies = new HashSet<Assembly>(options.HotfixAssemblies);
_assemblies = options.AllAssemblies;
_callConvention = options.CallConvention;
_outputFile = options.OutputFile;
_platformAdaptor = CreatePlatformAdaptor(options.CallConvention);
_optimized = options.Optimized;
}
private static IPlatformAdaptor CreatePlatformAdaptor(PlatformABI type)
{
switch (type)
{
case PlatformABI.Universal32: return new PlatformAdaptor_Universal32();
case PlatformABI.Universal64: return new PlatformAdaptor_Universal64();
case PlatformABI.Arm64: return new PlatformAdaptor_Arm64();
default: throw new NotSupportedException();
}
}
private string GetTemplateFile()
{
string tplFile;
switch (_callConvention)
{
case PlatformABI.Universal32: tplFile = "Universal32"; break;
case PlatformABI.Universal64: tplFile = "Universal64"; break;
case PlatformABI.Arm64: tplFile = "Arm64"; break;
default: throw new NotSupportedException();
};
return $"{Application.dataPath}/Editor/HybridCLR/Generators/Templates/MethodBridge_{tplFile}.cpp";
}
public IEnumerable<TypeGenInfo> GetGenerateTypes()
{
return new List<TypeGenInfo>();
}
private MethodBridgeSig CreateMethodBridgeSig(bool isStatic, ParameterInfo returnType, ParameterInfo[] parameters)
{
var paramInfos = new List<ParamInfo>();
if (!isStatic)
{
// FIXME arm32 is s_i4u4
paramInfos.Add(new ParamInfo() { Type = _platformAdaptor.IsArch32 ? TypeInfo.s_i4u4 : TypeInfo.s_i8u8 });
}
foreach (var paramInfo in parameters)
{
paramInfos.Add(new ParamInfo() { Type = _platformAdaptor.CreateTypeInfo(paramInfo.ParameterType, false) });
}
var mbs = new MethodBridgeSig()
{
ReturnInfo = new ReturnInfo() { Type = returnType != null ? _platformAdaptor.CreateTypeInfo(returnType.ParameterType, true) : TypeInfo.s_void },
ParamInfos = paramInfos,
};
return mbs;
}
private void AddManaged2NativeMethod(MethodBridgeSig method)
{
if (_managed2nativeMethodSet.Add(method))
{
method.Init();
}
}
private void AddNative2ManagedMethod(MethodBridgeSig method)
{
if (_native2managedMethodSet.Add(method))
{
method.Init();
}
}
private void AddAdjustThunkMethod(MethodBridgeSig method)
{
if (_adjustThunkMethodSet.Add(method))
{
method.Init();
}
}
private void ScanType(Type type)
{
if (type.IsGenericTypeDefinition)
{
return;
}
if (_optimized)
{
if (!type.IsNested)
{
if (!type.IsPublic)
{
return;
}
}
else
{
if (type.IsNestedPrivate)
{
return;
}
}
}
var typeDel = typeof(MulticastDelegate);
if (typeDel.IsAssignableFrom(type))
{
var method = type.GetMethod("Invoke");
if (method == null)
{
//Debug.LogError($"delegate:{typeDel.FullName} Invoke not exists");
return;
}
// Debug.Log($"== delegate:{type}");
var instanceCallMethod = CreateMethodBridgeSig(false, method.ReturnParameter, method.GetParameters());
AddManaged2NativeMethod(instanceCallMethod);
AddNative2ManagedMethod(instanceCallMethod);
var staticCallMethod = CreateMethodBridgeSig(true, method.ReturnParameter, method.GetParameters());
AddManaged2NativeMethod(staticCallMethod);
AddNative2ManagedMethod(staticCallMethod);
return;
}
foreach (var method in type.GetMethods(BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public
| BindingFlags.NonPublic | BindingFlags.CreateInstance | BindingFlags.InvokeMethod | BindingFlags.FlattenHierarchy))
{
if (method.IsGenericMethodDefinition)
{
continue;
}
if (_optimized && (method.IsPrivate || (method.IsAssembly && !method.IsPublic && !method.IsFamily)))
{
continue;
}
if (!_optimized || (method.IsFamily || method.IsPublic))
{
var m2nMethod = CreateMethodBridgeSig(method.IsStatic, method.ReturnParameter, method.GetParameters());
AddManaged2NativeMethod(m2nMethod);
if (type.IsValueType && !method.IsStatic)
{
var adjustThunkMethod = CreateMethodBridgeSig(false, method.ReturnParameter, method.GetParameters());
AddAdjustThunkMethod(adjustThunkMethod);
}
if (method.IsVirtual)
{
AddNative2ManagedMethod(m2nMethod);
}
}
}
foreach (var method in type.GetConstructors(BindingFlags.Instance | BindingFlags.Public
| BindingFlags.NonPublic | BindingFlags.CreateInstance | BindingFlags.InvokeMethod | BindingFlags.FlattenHierarchy))
{
if (_optimized && (method.IsPrivate || (method.IsAssembly && !method.IsPublic && !method.IsFamily)))
{
continue;
}
if (!_optimized || (method.IsFamily || method.IsPublic))
{
var callMethod = CreateMethodBridgeSig(false, null, method.GetParameters());
AddManaged2NativeMethod(callMethod);
if (type.IsValueType && !method.IsStatic)
{
var invokeMethod = CreateMethodBridgeSig(false, null, method.GetParameters());
AddAdjustThunkMethod(invokeMethod);
}
}
}
foreach (var subType in type.GetNestedTypes(BindingFlags.Public | BindingFlags.NonPublic))
{
ScanType(subType);
}
}
public void PrepareFromAssemblies()
{
foreach (var ass in _assemblies)
{
if (_hotfixAssemblies.Contains(ass))
{
continue;
}
//Debug.Log("prepare assembly:" + ass.FullName);
foreach (var type in ass.GetTypes())
{
ScanType(type);
}
}
}
private void PrepareMethodsFromCustomeGenericTypes()
{
foreach (var type in GeneratorConfig.PrepareCustomGenericTypes())
{
ScanType(type);
}
}
public void PrepareMethods()
{
PrepareMethodsFromCustomeGenericTypes();
foreach(var methodSig in _platformAdaptor.IsArch32 ? GeneratorConfig.PrepareCustomMethodSignatures32() : GeneratorConfig.PrepareCustomMethodSignatures64())
{
var method = MethodBridgeSig.CreateBySignatuer(methodSig);
AddManaged2NativeMethod(method);
AddAdjustThunkMethod(method);
}
PrepareFromAssemblies();
{
var sortedMethods = new SortedDictionary<string, MethodBridgeSig>();
foreach (var method in _managed2nativeMethodSet)
{
sortedMethods.Add(method.CreateCallSigName(), method);
}
_managed2nativeMethodList = sortedMethods.Values.ToList();
}
{
var sortedMethods = new SortedDictionary<string, MethodBridgeSig>();
foreach (var method in _native2managedMethodSet)
{
sortedMethods.Add(method.CreateCallSigName(), method);
}
_native2managedMethodList = sortedMethods.Values.ToList();
}
{
var sortedMethods = new SortedDictionary<string, MethodBridgeSig>();
foreach (var method in _adjustThunkMethodSet)
{
sortedMethods.Add(method.CreateCallSigName(), method);
}
_adjustThunkMethodList = sortedMethods.Values.ToList();
}
}
public void Generate()
{
var frr = new FileRegionReplace(GetTemplateFile());
List<string> lines = new List<string>(20_0000);
Debug.LogFormat("== managed2native method count:{0}", _managed2nativeMethodList.Count);
foreach(var method in _managed2nativeMethodList)
{
_platformAdaptor.GenerateManaged2NativeMethod(method, lines);
}
_platformAdaptor.GenerateManaged2NativeStub(_managed2nativeMethodList, lines);
Debug.LogFormat("== native2managed method count:{0}", _native2managedMethodList.Count);
foreach (var method in _native2managedMethodList)
{
_platformAdaptor.GenerateNative2ManagedMethod(method, lines);
}
_platformAdaptor.GenerateNative2ManagedStub(_native2managedMethodList, lines);
Debug.LogFormat("== adjustThunk method count:{0}", _adjustThunkMethodList.Count);
foreach (var method in _adjustThunkMethodList)
{
_platformAdaptor.GenerateAdjustThunkMethod(method, lines);
}
_platformAdaptor.GenerateAdjustThunkStub(_adjustThunkMethodList, lines);
frr.Replace("INVOKE_STUB", string.Join("\n", lines));
Directory.CreateDirectory(Path.GetDirectoryName(_outputFile));
frr.Commit(_outputFile);
}
}
}

View File

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

View File

@@ -1,156 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace HybridCLR.Editor.Generators.MethodBridge
{
public class MethodBridgeSig : IEquatable<MethodBridgeSig>
{
private readonly static Regex s_sigPattern = new Regex(@"^(v|i1|i2|i4|i8|r4|r8|i16|sr|vf2|vf3|vf4|vd2|vd3|vd4|S\d+|A\d+|B\d+|C\d+)+$");
public static MethodBridgeSig CreateBySignatuer(string sigName)
{
var re = s_sigPattern.Match(sigName);
if (!re.Success)
{
throw new ArgumentException($"{sigName} is not valid signature");
}
var mbs = new MethodBridgeSig() { ParamInfos = new List<ParamInfo>()};
var sigs = re.Groups[1].Captures;
mbs.ReturnInfo = new ReturnInfo() { Type = CreateTypeInfoBySignature(sigs[0].Value)};
for(int i = 1; i < sigs.Count; i++)
{
mbs.ParamInfos.Add(new ParamInfo() { Type = CreateTypeInfoBySignature(sigs[i].Value)});
}
return mbs;
}
private static TypeInfo CreateTypeInfoBySignature(string sigName)
{
switch(sigName)
{
case "v": return new TypeInfo(typeof(void), ParamOrReturnType.VOID);
case "i1": return new TypeInfo(typeof(sbyte), ParamOrReturnType.I1_U1);
case "i2": return new TypeInfo(typeof(short), ParamOrReturnType.I2_U2);
case "i4": return new TypeInfo(typeof(int), ParamOrReturnType.I4_U4);
case "i8": return new TypeInfo(typeof(long), ParamOrReturnType.I8_U8);
case "r4": return new TypeInfo(typeof(float), ParamOrReturnType.R4);
case "r8": return new TypeInfo(typeof(double), ParamOrReturnType.R8);
case "i16": return TypeInfo.s_i16;
case "sr": return TypeInfo.s_ref;
case "vf2": return new TypeInfo(null, ParamOrReturnType.ARM64_HFA_FLOAT_2);
case "vf3": return new TypeInfo(null, ParamOrReturnType.ARM64_HFA_FLOAT_3);
case "vf4": return new TypeInfo(null, ParamOrReturnType.ARM64_HFA_FLOAT_4);
case "vd2": return new TypeInfo(null, ParamOrReturnType.ARM64_HFA_DOUBLE_2);
case "vd3": return new TypeInfo(null, ParamOrReturnType.ARM64_HFA_DOUBLE_3);
case "vd4": return new TypeInfo(null, ParamOrReturnType.ARM64_HFA_DOUBLE_4);
default:
{
if (sigName.StartsWith("S"))
{
return new TypeInfo(null, ParamOrReturnType.STRUCTURE_ALIGN1, int.Parse(sigName.Substring(1)));
}
if (sigName.StartsWith("A"))
{
return new TypeInfo(null, ParamOrReturnType.STRUCTURE_ALIGN2, int.Parse(sigName.Substring(1)));
}
if (sigName.StartsWith("B"))
{
return new TypeInfo(null, ParamOrReturnType.STRUCTURE_ALIGN4, int.Parse(sigName.Substring(1)));
}
if (sigName.StartsWith("C"))
{
return new TypeInfo(null, ParamOrReturnType.STRUCTURE_ALIGN8, int.Parse(sigName.Substring(1)));
}
throw new ArgumentException($"invalid signature:{sigName}");
}
}
}
public ReturnInfo ReturnInfo { get; set; }
public List<ParamInfo> ParamInfos { get; set; }
public void Init()
{
for(int i = 0; i < ParamInfos.Count; i++)
{
ParamInfos[i].Index = i;
}
}
public string CreateCallSigName()
{
var n = new StringBuilder();
n.Append(ReturnInfo.Type.CreateSigName());
foreach(var param in ParamInfos)
{
n.Append(param.Type.CreateSigName());
}
return n.ToString();
}
public string CreateInvokeSigName()
{
var n = new StringBuilder();
n.Append(ReturnInfo.Type.CreateSigName());
foreach (var param in ParamInfos)
{
n.Append(param.Type.CreateSigName());
}
return n.ToString();
}
public override bool Equals(object obj)
{
return Equals((MethodBridgeSig)obj);
}
public bool Equals(MethodBridgeSig other)
{
if (other == null)
{
return false;
}
if (!ReturnInfo.Type.Equals(other.ReturnInfo.Type))
{
return false;
}
if (ParamInfos.Count != other.ParamInfos.Count)
{
return false;
}
for(int i = 0; i < ParamInfos.Count; i++)
{
if (!ParamInfos[i].Type.Equals(other.ParamInfos[i].Type))
{
return false;
}
}
return true;
}
public override int GetHashCode()
{
int hash = 17;
hash = hash * 23 + ReturnInfo.Type.GetHashCode();
foreach(var p in ParamInfos)
{
hash = hash * 23 + p.Type.GetHashCode();
}
return hash;
}
}
}

View File

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

View File

@@ -1,44 +0,0 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HybridCLR.Editor.Generators.MethodBridge
{
public class ParamInfo
{
public TypeInfo Type { get; set; }
public int Index { get; set; }
//public bool IsNative2ManagedByAddress => Type.PorType >= ParamOrReturnType.STRUCT_NOT_PASS_AS_VALUE;
public bool IsPassToManagedByAddress => Type.GetParamSlotNum() > 1;
public bool IsPassToNativeByAddress => Type.PorType == ParamOrReturnType.STRUCTURE_AS_REF_PARAM;
public string Native2ManagedParamValue(PlatformABI canv)
{
return IsPassToManagedByAddress ? $"(uint64_t)&__arg{Index}" : $"*(uint64_t*)&__arg{Index}";
}
public string Managed2NativeParamValue(PlatformABI canv)
{
return IsPassToNativeByAddress ? $"(uint64_t)(localVarBase+argVarIndexs[{Index}])" : $"*({Type.GetTypeName()}*)(localVarBase+argVarIndexs[{Index}])";
}
}
public class ReturnInfo
{
public TypeInfo Type { get; set; }
public bool IsVoid => Type.PorType == ParamOrReturnType.VOID;
public int GetParamSlotNum(PlatformABI canv)
{
return Type.GetParamSlotNum();
}
}
}

View File

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

View File

@@ -1,38 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HybridCLR.Editor.Generators.MethodBridge
{
public enum ParamOrReturnType
{
VOID,
I1_U1,
//U1,
I2_U2,
//U2,
I4_U4,
I8_U8,
//I_U,
R4,
R8,
ARM64_HFA_FLOAT_2,
VALUE_TYPE_SIZE_LESS_EQUAL_8,
I16, // 8 < size <= 16
STRUCT_NOT_PASS_AS_VALUE, // struct pass not as value
STRUCTURE_AS_REF_PARAM, // size > 16
ARM64_HFA_FLOAT_3,
ARM64_HFA_FLOAT_4,
ARM64_HFA_DOUBLE_2,
ARM64_HFA_DOUBLE_3,
ARM64_HFA_DOUBLE_4,
ARM64_HVA_8,
ARM64_HVA_16,
STRUCTURE_ALIGN1, // size > 16
STRUCTURE_ALIGN2,
STRUCTURE_ALIGN4,
STRUCTURE_ALIGN8,
}
}

View File

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

View File

@@ -1,9 +0,0 @@
namespace HybridCLR.Editor.Generators.MethodBridge
{
public enum PlatformABI
{
Universal32,
Universal64,
Arm64,
}
}

View File

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

View File

@@ -1,160 +0,0 @@
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;
namespace HybridCLR.Editor.Generators.MethodBridge
{
internal abstract class PlatformAdaptorBase : IPlatformAdaptor
{
public abstract bool IsArch32 { get; }
public abstract TypeInfo PointerType { get; }
protected abstract Dictionary<Type, TypeInfo> CacheTypes { get; }
protected abstract TypeInfo CreateValueType(Type type, bool returnValue);
public abstract void GenerateManaged2NativeMethod(MethodBridgeSig method, List<string> lines);
public abstract void GenerateNative2ManagedMethod(MethodBridgeSig method, List<string> lines);
public abstract void GenerateAdjustThunkMethod(MethodBridgeSig method, List<string> outputLines);
private static Dictionary<Type, (int, int)> _typeSizeCache64 = new Dictionary<Type, (int, int)>();
private static Dictionary<Type, (int, int)> _typeSizeCache32 = new Dictionary<Type, (int, int)>();
private static ValueTypeSizeAligmentCalculator s_calculator64 = new ValueTypeSizeAligmentCalculator(false);
private static ValueTypeSizeAligmentCalculator s_calculator32 = new ValueTypeSizeAligmentCalculator(true);
public static (int Size, int Aligment) ComputeSizeAndAligmentOfArch64(Type t)
{
if (_typeSizeCache64.TryGetValue(t, out var sizeAndAligment))
{
return sizeAndAligment;
}
// all this just to invoke one opcode with no arguments!
var method = new DynamicMethod("ComputeSizeOfImpl", typeof(int), Type.EmptyTypes, typeof(PlatformAdaptorBase), false);
var gen = method.GetILGenerator();
gen.Emit(OpCodes.Sizeof, t);
gen.Emit(OpCodes.Ret);
int clrSize = ((Func<int>)method.CreateDelegate(typeof(Func<int>)))();
sizeAndAligment = s_calculator64.SizeAndAligmentOf(t);
int customSize = sizeAndAligment.Item1;
if (customSize != clrSize)
{
s_calculator64.SizeAndAligmentOf(t);
Debug.LogError($"type:{t} size calculate error. HybridCLR Comput:{sizeAndAligment} CLR:{clrSize}");
}
_typeSizeCache64.Add(t, sizeAndAligment);
return sizeAndAligment;
}
protected static (int Size, int Aligment) ComputeSizeAndAligmentOfArch32(Type 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(Type type, bool returnValue)
{
if (type.IsByRef)
{
return PointerType;
}
if (type == typeof(void))
{
return TypeInfo.s_void;
}
if (!type.IsValueType)
{
return PointerType;
}
if (CacheTypes.TryGetValue(type, out var cache))
{
return cache;
}
if (type.IsEnum)
{
return CreateTypeInfo(type.GetEnumUnderlyingType(), returnValue);
}
var ti = CreateValueType(type, returnValue);
// s_typeInfoCaches.Add(type, ti);
return ti;
}
protected static TypeInfo CreateGeneralValueType(Type type, int size, int aligment)
{
Debug.Assert(size % aligment == 0);
switch (aligment)
{
case 1: return new TypeInfo(type, ParamOrReturnType.STRUCTURE_ALIGN1, size);
case 2: return new TypeInfo(type, ParamOrReturnType.STRUCTURE_ALIGN2, size);
case 4: return new TypeInfo(type, ParamOrReturnType.STRUCTURE_ALIGN4, size);
case 8: return new TypeInfo(type, ParamOrReturnType.STRUCTURE_ALIGN8, size);
default: throw new NotSupportedException($"type:{type} not support aligment:{aligment}");
}
}
public void GenerateManaged2NativeStub(List<MethodBridgeSig> 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<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

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

View File

@@ -1,208 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
namespace HybridCLR.Editor.Generators.MethodBridge
{
internal class PlatformAdaptor_Arm64 : PlatformAdaptorBase
{
private static readonly Dictionary<Type, TypeInfo> s_typeInfoCaches = new Dictionary<Type, TypeInfo>()
{
{ typeof(void), new TypeInfo(typeof(void), ParamOrReturnType.VOID)},
{ typeof(bool), new TypeInfo(typeof(bool), ParamOrReturnType.I1_U1)},
{ typeof(byte), new TypeInfo(typeof(byte), ParamOrReturnType.I1_U1)},
{ typeof(sbyte), new TypeInfo(typeof(sbyte), ParamOrReturnType.I1_U1) },
{ typeof(short), new TypeInfo(typeof(short), ParamOrReturnType.I2_U2) },
{ typeof(ushort), new TypeInfo(typeof(ushort), ParamOrReturnType.I2_U2) },
{ typeof(char), new TypeInfo(typeof(char), ParamOrReturnType.I2_U2) },
{ typeof(int), new TypeInfo(typeof(int), ParamOrReturnType.I4_U4) },
{ typeof(uint), new TypeInfo(typeof(uint), ParamOrReturnType.I4_U4) },
{ typeof(long), new TypeInfo(typeof(long), ParamOrReturnType.I8_U8) },
{ typeof(ulong), new TypeInfo(typeof(ulong), ParamOrReturnType.I8_U8)},
{ typeof(float), new TypeInfo(typeof(float), ParamOrReturnType.R4)},
{ typeof(double), new TypeInfo(typeof(double), ParamOrReturnType.R8)},
{ typeof(IntPtr), new TypeInfo(null, ParamOrReturnType.I8_U8)},
{ typeof(UIntPtr), new TypeInfo(null, ParamOrReturnType.I8_U8)},
{ typeof(Vector2), new TypeInfo(typeof(Vector2), ParamOrReturnType.ARM64_HFA_FLOAT_2) },
{ typeof(Vector3), new TypeInfo(typeof(Vector3), ParamOrReturnType.ARM64_HFA_FLOAT_3) },
{ typeof(Vector4), new TypeInfo(typeof(Vector4), ParamOrReturnType.ARM64_HFA_FLOAT_4) },
{ typeof(System.Numerics.Vector2), new TypeInfo(typeof(System.Numerics.Vector2), ParamOrReturnType.ARM64_HFA_FLOAT_2) },
{ typeof(System.Numerics.Vector3), new TypeInfo(typeof(System.Numerics.Vector3), ParamOrReturnType.ARM64_HFA_FLOAT_3) },
{ typeof(System.Numerics.Vector4), new TypeInfo(typeof(System.Numerics.Vector4), ParamOrReturnType.ARM64_HFA_FLOAT_4) },
};
public PlatformABI CallConventionType { get; } = PlatformABI.Universal64;
public override bool IsArch32 => false;
public override TypeInfo PointerType => TypeInfo.s_i8u8;
protected override Dictionary<Type, TypeInfo> CacheTypes => s_typeInfoCaches;
public class HFATypeInfo
{
public Type Type { get; set; }
public int Count { get; set; }
}
private static bool IsNotHFAFastCheck(int typeSize)
{
return typeSize != 8 && typeSize != 12 && typeSize != 16 && typeSize != 24 && typeSize != 32;
}
private static bool ComputHFATypeInfo0(Type type, HFATypeInfo typeInfo)
{
var fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
foreach (var field in fields)
{
Type ftype = field.FieldType;
if (ftype != typeof(float) && ftype != typeof(double))
{
if (!ftype.IsPrimitive && ftype.IsValueType)
{
if (!ComputHFATypeInfo0(ftype, typeInfo))
{
return false;
}
}
else
{
return false;
}
}
else if (ftype == typeInfo.Type || typeInfo.Type == null)
{
typeInfo.Type = ftype;
++typeInfo.Count;
}
else
{
return false;
}
}
return typeInfo.Count <= 4;
}
public static bool ComputHFATypeInfo(Type type, int typeSize, out HFATypeInfo typeInfo)
{
typeInfo = new HFATypeInfo();
if (IsNotHFAFastCheck(typeSize))
{
return false;
}
bool ok = ComputHFATypeInfo0(type, typeInfo);
if (ok && typeInfo.Count >= 2 && typeInfo.Count <= 4)
{
int fieldSize = typeInfo.Type == typeof(float) ? 4 : 8;
return typeSize == fieldSize * typeInfo.Count;
}
return false;
}
protected override TypeInfo CreateValueType(Type type, bool returnValue)
{
(int typeSize, int typeAligment) = ComputeSizeAndAligmentOfArch64(type);
if (ComputHFATypeInfo(type, typeSize, out HFATypeInfo hfaTypeInfo))
{
if (hfaTypeInfo.Type == typeof(float))
{
switch (hfaTypeInfo.Count)
{
case 2: return new TypeInfo(type, ParamOrReturnType.ARM64_HFA_FLOAT_2);
case 3: return new TypeInfo(type, ParamOrReturnType.ARM64_HFA_FLOAT_3);
case 4: return new TypeInfo(type, ParamOrReturnType.ARM64_HFA_FLOAT_4);
default: throw new NotSupportedException();
}
}
else
{
Debug.Assert(hfaTypeInfo.Type == typeof(double));
switch (hfaTypeInfo.Count)
{
case 2: return new TypeInfo(type, ParamOrReturnType.ARM64_HFA_DOUBLE_2);
case 3: return new TypeInfo(type, ParamOrReturnType.ARM64_HFA_DOUBLE_3);
case 4: return new TypeInfo(type, ParamOrReturnType.ARM64_HFA_DOUBLE_4);
default: throw new NotSupportedException();
}
}
}
else
{
// 64位下结构体内存对齐规则是一样的
return CreateArm64GeneralValueType(type, typeSize,returnValue);
}
}
private TypeInfo CreateArm64GeneralValueType(Type type, int typeSize, bool returnValue)
{
if (typeSize <= 8)
{
return TypeInfo.s_i8u8;
}
if (typeSize <= 16)
{
return TypeInfo.s_i16;
}
if (returnValue)
{
return new TypeInfo(type, ParamOrReturnType.STRUCTURE_ALIGN1, typeSize);
}
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 paramNameListStr = string.Join(", ", method.ParamInfos.Select(p => p.Managed2NativeParamValue(this.CallConventionType)).Concat(new string[] { "method" }));
lines.Add($@"
static void __M2N_{method.CreateCallSigName()}(const MethodInfo* method, uint16_t* argVarIndexs, StackObject* localVarBase, void* ret)
{{
typedef {method.ReturnInfo.Type.GetTypeName()} (*NativeMethod)({paramListStr});
{(!method.ReturnInfo.IsVoid ? $"*({method.ReturnInfo.Type.GetTypeName()}*)ret = " : "")}((NativeMethod)(GetInterpreterDirectlyCallMethodPointer(method)))({paramNameListStr});
}}
");
}
public override void GenerateNative2ManagedMethod(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" }));
lines.Add($@"
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* ret = {(method.ReturnInfo.IsVoid ? "nullptr" : "args + " + method.ParamInfos.Count)};
Interpreter::Execute(method, args, ret);
{(!method.ReturnInfo.IsVoid ? $"return *({method.ReturnInfo.Type.GetTypeName()}*)ret;" : "")}
}}
");
}
public override void GenerateAdjustThunkMethod(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" }));
lines.Add($@"
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* ret = {(method.ReturnInfo.IsVoid ? "nullptr" : "args + " + method.ParamInfos.Count)};
Interpreter::Execute(method, args, ret);
{(!method.ReturnInfo.IsVoid ? $"return *({method.ReturnInfo.Type.GetTypeName()}*)ret;" : "")}
}}
");
}
}
}

View File

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

View File

@@ -1,96 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
namespace HybridCLR.Editor.Generators.MethodBridge
{
internal class PlatformAdaptor_Universal32 : PlatformAdaptorBase
{
private static readonly Dictionary<Type, TypeInfo> s_typeInfoCaches = new Dictionary<Type, TypeInfo>()
{
{ typeof(void), new TypeInfo(typeof(void), ParamOrReturnType.VOID)},
{ typeof(bool), new TypeInfo(typeof(bool), ParamOrReturnType.I1_U1)},
{ typeof(byte), new TypeInfo(typeof(byte), ParamOrReturnType.I1_U1)},
{ typeof(sbyte), new TypeInfo(typeof(sbyte), ParamOrReturnType.I1_U1) },
{ typeof(short), new TypeInfo(typeof(short), ParamOrReturnType.I2_U2) },
{ typeof(ushort), new TypeInfo(typeof(ushort), ParamOrReturnType.I2_U2) },
{ typeof(char), new TypeInfo(typeof(char), ParamOrReturnType.I2_U2) },
{ typeof(int), new TypeInfo(typeof(int), ParamOrReturnType.I4_U4) },
{ typeof(uint), new TypeInfo(typeof(uint), ParamOrReturnType.I4_U4) },
{ typeof(long), new TypeInfo(typeof(long), ParamOrReturnType.I8_U8) },
{ typeof(ulong), new TypeInfo(typeof(ulong), ParamOrReturnType.I8_U8)},
{ typeof(float), new TypeInfo(typeof(float), ParamOrReturnType.R4)},
{ typeof(double), new TypeInfo(typeof(double), ParamOrReturnType.R8)},
{ typeof(IntPtr), new TypeInfo(null, ParamOrReturnType.I4_U4)},
{ typeof(UIntPtr), new TypeInfo(null, ParamOrReturnType.I4_U4)},
};
public PlatformABI CallConventionType { get; } = PlatformABI.Universal32;
public override bool IsArch32 => true;
public override TypeInfo PointerType => TypeInfo.s_i4u4;
protected override Dictionary<Type, TypeInfo> CacheTypes => s_typeInfoCaches;
protected override TypeInfo CreateValueType(Type type, bool returnValue)
{
(int typeSize, int typeAligment) = ComputeSizeAndAligmentOfArch32(type);
int actualAliment = typeAligment <= 4 ? 1 : 8;
return CreateGeneralValueType(type, typeSize, actualAliment);
}
public override void GenerateManaged2NativeMethod(MethodBridgeSig 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 => p.Managed2NativeParamValue(this.CallConventionType)).Concat(new string[] { "method" }));
lines.Add($@"
static void __M2N_{method.CreateCallSigName()}(const MethodInfo* method, uint16_t* argVarIndexs, StackObject* localVarBase, void* ret)
{{
typedef {method.ReturnInfo.Type.GetTypeName()} (*NativeMethod)({paramListStr});
{(!method.ReturnInfo.IsVoid ? $"*({method.ReturnInfo.Type.GetTypeName()}*)ret = " : "")}((NativeMethod)(GetInterpreterDirectlyCallMethodPointer(method)))({paramNameListStr});
}}
");
}
public override void GenerateNative2ManagedMethod(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" }));
lines.Add($@"
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* ret = {(method.ReturnInfo.IsVoid ? "nullptr" : "args + " + method.ParamInfos.Count)};
Interpreter::Execute(method, args, ret);
{(!method.ReturnInfo.IsVoid ? $"return *({method.ReturnInfo.Type.GetTypeName()}*)ret;" : "")}
}}
");
}
public override void GenerateAdjustThunkMethod(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" }));
lines.Add($@"
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* ret = {(method.ReturnInfo.IsVoid ? "nullptr" : "args + " + method.ParamInfos.Count)};
Interpreter::Execute(method, args, ret);
{(!method.ReturnInfo.IsVoid ? $"return *({method.ReturnInfo.Type.GetTypeName()}*)ret;" : "")}
}}
");
}
}
}

View File

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

View File

@@ -1,189 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
namespace HybridCLR.Editor.Generators.MethodBridge
{
internal class PlatformAdaptor_Universal64 : PlatformAdaptorBase
{
private static readonly Dictionary<Type, TypeInfo> s_typeInfoCaches = new Dictionary<Type, TypeInfo>()
{
{ typeof(void), new TypeInfo(typeof(void), ParamOrReturnType.VOID)},
{ typeof(bool), new TypeInfo(typeof(bool), ParamOrReturnType.I1_U1)},
{ typeof(byte), new TypeInfo(typeof(byte), ParamOrReturnType.I1_U1)},
{ typeof(sbyte), new TypeInfo(typeof(sbyte), ParamOrReturnType.I1_U1) },
{ typeof(short), new TypeInfo(typeof(short), ParamOrReturnType.I2_U2) },
{ typeof(ushort), new TypeInfo(typeof(ushort), ParamOrReturnType.I2_U2) },
{ typeof(char), new TypeInfo(typeof(char), ParamOrReturnType.I2_U2) },
{ typeof(int), new TypeInfo(typeof(int), ParamOrReturnType.I4_U4) },
{ typeof(uint), new TypeInfo(typeof(uint), ParamOrReturnType.I4_U4) },
{ typeof(long), new TypeInfo(typeof(long), ParamOrReturnType.I8_U8) },
{ typeof(ulong), new TypeInfo(typeof(ulong), ParamOrReturnType.I8_U8)},
{ typeof(float), new TypeInfo(typeof(float), ParamOrReturnType.R4)},
{ typeof(double), new TypeInfo(typeof(double), ParamOrReturnType.R8)},
{ typeof(IntPtr), new TypeInfo(null, ParamOrReturnType.I8_U8)},
{ typeof(UIntPtr), new TypeInfo(null, ParamOrReturnType.I8_U8)},
{ typeof(Vector2), new TypeInfo(typeof(Vector2), ParamOrReturnType.ARM64_HFA_FLOAT_2) },
{ typeof(Vector3), new TypeInfo(typeof(Vector3), ParamOrReturnType.ARM64_HFA_FLOAT_3) },
{ typeof(Vector4), new TypeInfo(typeof(Vector4), ParamOrReturnType.ARM64_HFA_FLOAT_4) },
{ typeof(System.Numerics.Vector2), new TypeInfo(typeof(System.Numerics.Vector2), ParamOrReturnType.ARM64_HFA_FLOAT_2) },
{ typeof(System.Numerics.Vector3), new TypeInfo(typeof(System.Numerics.Vector3), ParamOrReturnType.ARM64_HFA_FLOAT_3) },
{ typeof(System.Numerics.Vector4), new TypeInfo(typeof(System.Numerics.Vector4), ParamOrReturnType.ARM64_HFA_FLOAT_4) },
};
public PlatformABI CallConventionType { get; } = PlatformABI.Universal64;
public override bool IsArch32 => false;
public override TypeInfo PointerType => TypeInfo.s_i8u8;
protected override Dictionary<Type, TypeInfo> CacheTypes => s_typeInfoCaches;
public class HFATypeInfo
{
public Type Type { get; set; }
public int Count { get; set; }
}
private static bool IsNotHFAFastCheck(int typeSize)
{
return typeSize != 8 && typeSize != 12 && typeSize != 16 && typeSize != 24 && typeSize != 32;
}
private static bool ComputHFATypeInfo0(Type type, HFATypeInfo typeInfo)
{
var fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
foreach (var field in fields)
{
Type ftype = field.FieldType;
if (ftype != typeof(float) && ftype != typeof(double))
{
if (!ftype.IsPrimitive && ftype.IsValueType)
{
if (!ComputHFATypeInfo0(ftype, typeInfo))
{
return false;
}
}
else
{
return false;
}
}
else if (ftype == typeInfo.Type || typeInfo.Type == null)
{
typeInfo.Type = ftype;
++typeInfo.Count;
}
else
{
return false;
}
}
return typeInfo.Count <= 4;
}
public static bool ComputHFATypeInfo(Type type, int typeSize, out HFATypeInfo typeInfo)
{
typeInfo = new HFATypeInfo();
if (IsNotHFAFastCheck(typeSize))
{
return false;
}
bool ok = ComputHFATypeInfo0(type, typeInfo);
if (ok && typeInfo.Count >= 2 && typeInfo.Count <= 4)
{
int fieldSize = typeInfo.Type == typeof(float) ? 4 : 8;
return typeSize == fieldSize * typeInfo.Count;
}
return false;
}
protected override TypeInfo CreateValueType(Type type, bool returnValue)
{
(int typeSize, int typeAligment) = ComputeSizeAndAligmentOfArch64(type);
if (ComputHFATypeInfo(type, typeSize, out HFATypeInfo hfaTypeInfo))
{
if (hfaTypeInfo.Type == typeof(float))
{
switch (hfaTypeInfo.Count)
{
case 2: return new TypeInfo(type, ParamOrReturnType.ARM64_HFA_FLOAT_2);
case 3: return new TypeInfo(type, ParamOrReturnType.ARM64_HFA_FLOAT_3);
case 4: return new TypeInfo(type, ParamOrReturnType.ARM64_HFA_FLOAT_4);
default: throw new NotSupportedException();
}
}
else
{
Debug.Assert(hfaTypeInfo.Type == typeof(double));
switch (hfaTypeInfo.Count)
{
case 2: return new TypeInfo(type, ParamOrReturnType.ARM64_HFA_DOUBLE_2);
case 3: return new TypeInfo(type, ParamOrReturnType.ARM64_HFA_DOUBLE_3);
case 4: return new TypeInfo(type, ParamOrReturnType.ARM64_HFA_DOUBLE_4);
default: throw new NotSupportedException();
}
}
}
else
{
// 64位下结构体内存对齐规则是一样的
return CreateGeneralValueType(type, typeSize, 1 /*typeAligment*/);
}
}
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 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" }));
lines.Add($@"
static void __M2N_{method.CreateCallSigName()}(const MethodInfo* method, uint16_t* argVarIndexs, StackObject* localVarBase, void* ret)
{{
typedef {method.ReturnInfo.Type.GetTypeName()} (*NativeMethod)({paramListStr});
{(!method.ReturnInfo.IsVoid ? $"*({method.ReturnInfo.Type.GetTypeName()}*)ret = " : "")}((NativeMethod)(GetInterpreterDirectlyCallMethodPointer(method)))({paramNameListStr});
}}
");
}
public override void GenerateNative2ManagedMethod(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" }));
lines.Add($@"
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* ret = {(method.ReturnInfo.IsVoid ? "nullptr" : "args + " + method.ParamInfos.Count)};
Interpreter::Execute(method, args, ret);
{(!method.ReturnInfo.IsVoid ? $"return *({method.ReturnInfo.Type.GetTypeName()}*)ret;" : "")}
}}
");
}
public override void GenerateAdjustThunkMethod(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" }));
lines.Add($@"
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* ret = {(method.ReturnInfo.IsVoid ? "nullptr" : "args + " + method.ParamInfos.Count)};
Interpreter::Execute(method, args, ret);
{(!method.ReturnInfo.IsVoid ? $"return *({method.ReturnInfo.Type.GetTypeName()}*)ret;" : "")}
}}
");
}
}
}

View File

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

View File

@@ -1,19 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HybridCLR.Editor.Generators.MethodBridge
{
[AttributeUsage(AttributeTargets.Method)]
public class SignatureProviderAttribute : Attribute
{
public List<PlatformABI> Platforms { get; }
public SignatureProviderAttribute(params PlatformABI[] platforms)
{
Platforms = new List<PlatformABI>(platforms);
}
}
}

View File

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

View File

@@ -1,132 +0,0 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using UnityEngine;
namespace HybridCLR.Editor.Generators.MethodBridge
{
public class TypeInfo : IEquatable<TypeInfo>
{
public static readonly TypeInfo s_void = new TypeInfo(typeof(void), ParamOrReturnType.VOID);
public static readonly TypeInfo s_i4u4 = new TypeInfo(null, ParamOrReturnType.I4_U4);
public static readonly TypeInfo s_i8u8 = new TypeInfo(null, ParamOrReturnType.I8_U8);
public static readonly TypeInfo s_i16 = new TypeInfo(null, ParamOrReturnType.I16);
public static readonly TypeInfo s_ref = new TypeInfo(null, ParamOrReturnType.STRUCTURE_AS_REF_PARAM);
public TypeInfo(Type type, ParamOrReturnType portype)
{
this.Type = type;
PorType = portype;
Size = 0;
}
public TypeInfo(Type type, ParamOrReturnType portype, int size)
{
this.Type = type;
PorType = portype;
Size = size;
}
public Type Type { get; }
public ParamOrReturnType PorType { get; }
public int Size { get; }
public bool Equals(TypeInfo other)
{
return PorType == other.PorType && Size == other.Size;
}
public override bool Equals(object obj)
{
return Equals((TypeInfo)obj);
}
public override int GetHashCode()
{
return (int)PorType * 23 + Size;
}
public string CreateSigName()
{
switch (PorType)
{
case ParamOrReturnType.VOID: return "v";
case ParamOrReturnType.I1_U1: return "i1";
case ParamOrReturnType.I2_U2: return "i2";
case ParamOrReturnType.I4_U4: return "i4";
case ParamOrReturnType.I8_U8: return "i8";
case ParamOrReturnType.R4: return "r4";
case ParamOrReturnType.R8: return "r8";
case ParamOrReturnType.I16: return "i16";
case ParamOrReturnType.STRUCTURE_AS_REF_PARAM: return "sr";
case ParamOrReturnType.ARM64_HFA_FLOAT_2: return "vf2";
case ParamOrReturnType.ARM64_HFA_FLOAT_3: return "vf3";
case ParamOrReturnType.ARM64_HFA_FLOAT_4: return "vf4";
case ParamOrReturnType.ARM64_HFA_DOUBLE_2: return "vd2";
case ParamOrReturnType.ARM64_HFA_DOUBLE_3: return "vd3";
case ParamOrReturnType.ARM64_HFA_DOUBLE_4: return "vd4";
case ParamOrReturnType.STRUCTURE_ALIGN1: return "S" + Size;
case ParamOrReturnType.STRUCTURE_ALIGN2: return "A" + Size;
case ParamOrReturnType.STRUCTURE_ALIGN4: return "B" + Size;
case ParamOrReturnType.STRUCTURE_ALIGN8: return "C" + Size;
default: throw new NotSupportedException(PorType.ToString());
};
}
public string GetTypeName()
{
switch (PorType)
{
case ParamOrReturnType.VOID: return "void";
case ParamOrReturnType.I1_U1: return "int8_t";
case ParamOrReturnType.I2_U2: return "int16_t";
case ParamOrReturnType.I4_U4: return "int32_t";
case ParamOrReturnType.I8_U8: return "int64_t";
case ParamOrReturnType.R4: return "float";
case ParamOrReturnType.R8: return "double";
case ParamOrReturnType.I16: return "ValueTypeSize16";
case ParamOrReturnType.STRUCTURE_AS_REF_PARAM: return "uint64_t";
case ParamOrReturnType.ARM64_HFA_FLOAT_2: return "HtVector2f";
case ParamOrReturnType.ARM64_HFA_FLOAT_3: return "HtVector3f";
case ParamOrReturnType.ARM64_HFA_FLOAT_4: return "HtVector4f";
case ParamOrReturnType.ARM64_HFA_DOUBLE_2: return "HtVector2d";
case ParamOrReturnType.ARM64_HFA_DOUBLE_3: return "HtVector3d";
case ParamOrReturnType.ARM64_HFA_DOUBLE_4: return "HtVector4d";
case ParamOrReturnType.STRUCTURE_ALIGN1: return $"ValueTypeSize<{Size}>";
case ParamOrReturnType.STRUCTURE_ALIGN2: return $"ValueTypeSizeAlign2<{Size}>";
case ParamOrReturnType.STRUCTURE_ALIGN4: return $"ValueTypeSizeAlign4<{Size}>";
case ParamOrReturnType.STRUCTURE_ALIGN8: return $"ValueTypeSizeAlign8<{Size}>";
default: throw new NotImplementedException(PorType.ToString());
};
}
public int GetParamSlotNum()
{
switch (PorType)
{
case ParamOrReturnType.VOID: return 0;
case ParamOrReturnType.I16: return 2;
case ParamOrReturnType.STRUCTURE_AS_REF_PARAM: return 1;
case ParamOrReturnType.ARM64_HFA_FLOAT_3: return 2;
case ParamOrReturnType.ARM64_HFA_FLOAT_4: return 2;
case ParamOrReturnType.ARM64_HFA_DOUBLE_2: return 2;
case ParamOrReturnType.ARM64_HFA_DOUBLE_3: return 3;
case ParamOrReturnType.ARM64_HFA_DOUBLE_4: return 4;
case ParamOrReturnType.ARM64_HVA_8:
case ParamOrReturnType.ARM64_HVA_16: throw new NotSupportedException();
case ParamOrReturnType.STRUCTURE_ALIGN1:
case ParamOrReturnType.STRUCTURE_ALIGN2:
case ParamOrReturnType.STRUCTURE_ALIGN4:
case ParamOrReturnType.STRUCTURE_ALIGN8: return (Size + 7) / 8;
default:
{
Debug.Assert(PorType < ParamOrReturnType.STRUCT_NOT_PASS_AS_VALUE);
Debug.Assert(Size <= 8);
return 1;
}
}
}
}
}

View File

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

View File

@@ -1,148 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace HybridCLR.Editor.Generators.MethodBridge
{
public class ValueTypeSizeAligmentCalculator
{
private static Dictionary<string, int> s_primitives = new Dictionary<string, int>(14) {
{ "Byte", 1 },
{ "SByte", 1 },
{ "Boolean", 1 },
{ "Int16", 2 },
{ "UInt16", 2 },
{ "Char", 2 },
{ "Int32", 4 },
{ "UInt32", 4 },
{ "Single", 4 },
{ "Int64", 8 },
{ "UInt64", 8 },
{ "Double", 8 },
//{ "IntPtr", _referenceSize }, // so rule return the same results
//{ "UIntPtr", _referenceSize }, // on 32 and 64 bits architectures
};
public ValueTypeSizeAligmentCalculator(bool arch32)
{
_referenceSize = arch32 ? 4 : 8;
}
// actually we should use IntPtr.Size but that would make the rule
// return different results on 64 bits systems
private readonly int _referenceSize;
// Note: Needs to be public since this is being tested by our unit tests
private static bool IsIgnoreField(FieldInfo field)
{
var ignoreAttr = field.GetCustomAttributes().Where(a => a.GetType().Name == "IgnoreAttribute").FirstOrDefault();
if (ignoreAttr == null)
{
return false;
}
var p = ignoreAttr.GetType().GetProperty("DoesNotContributeToSize");
return (bool)p.GetValue(ignoreAttr);
}
private (int Size, int Aligment) SizeAndAligmentOfStruct(Type type)
{
int totalSize = 0;
int packAligment = 8;
int maxAligment = 1;
StructLayoutAttribute sa = type.StructLayoutAttribute;
if (sa != null && sa.Pack > 0)
{
packAligment = sa.Pack;
}
bool useSLSize = true;
foreach (FieldInfo field in type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
{
// add size of the type
var (fs, fa) = SizeAndAligmentOf(field.FieldType);
fa = Math.Min(fa, packAligment);
if (fa > maxAligment)
{
maxAligment = fa;
}
if (IsIgnoreField(field))
{
continue;
}
if (sa != null && sa.Value == LayoutKind.Explicit)
{
int offset = field.GetCustomAttribute<FieldOffsetAttribute>().Value;
totalSize = Math.Max(totalSize, offset + fs);
if (offset > sa.Size)
{
useSLSize = false;
}
}
else
{
if (totalSize % fa != 0)
{
totalSize = (totalSize + fa - 1) / fa * fa;
}
totalSize += fs;
if (sa != null && sa.Value == LayoutKind.Sequential && totalSize > sa.Size)
{
useSLSize = false;
}
}
}
if (totalSize == 0)
{
totalSize = maxAligment;
}
if (totalSize % maxAligment != 0)
{
totalSize = (totalSize + maxAligment - 1) / maxAligment * maxAligment;
}
if (sa != null && sa.Size > 0)
{
if (/*sa.Value == LayoutKind.Explicit &&*/ useSLSize)
{
totalSize = sa.Size;
while(totalSize % maxAligment != 0)
{
maxAligment /= 2;
}
}
}
return (totalSize, maxAligment);
}
public (int Size, int Aligment) SizeAndAligmentOf(Type type)
{
if (type.IsByRef || !type.IsValueType || type.IsArray)
return (_referenceSize, _referenceSize);
// list based on Type.IsPrimitive
if (type.Namespace == "System")
{
if (s_primitives.TryGetValue(type.Name, out var size))
{
return (size, size);
}
if (type.Name == "IntPtr" || type.Name == "UIntPtr")
{
return (_referenceSize, _referenceSize);
}
}
if (type.IsEnum)
return SizeAndAligmentOf(type.GetEnumUnderlyingType());
return SizeAndAligmentOfStruct(type);
}
}
}

View File

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

View File

@@ -1,38 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HybridCLR.Editor.Generators
{
public static class TemplateUtil
{
public static string EscapeIntegerName(int i)
{
return i >= 0 ? i.ToString() : "minus" + (-i);
}
public static string ReplaceRegion(string resultText, string region, string replaceContent)
{
int startIndex = resultText.IndexOf("//!!!{{" + region);
if (startIndex == -1)
{
throw new Exception($"region:{region} start not find");
}
int endIndex = resultText.IndexOf("//!!!}}" + region);
if (endIndex == -1)
{
throw new Exception($"region:{region} end not find");
}
int replaceStart = resultText.IndexOf('\n', startIndex);
int replaceEnd = resultText.LastIndexOf('\n', endIndex);
if (replaceStart == -1 || replaceEnd == -1)
{
throw new Exception($"region:{region} not find");
}
resultText = resultText.Substring(0, replaceStart) + "\n" + replaceContent + "\n" + resultText.Substring(replaceEnd);
return resultText;
}
}
}

View File

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

View File

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

View File

@@ -1,22 +0,0 @@
#include "MethodBridge.h"
#include <codegen/il2cpp-codegen-metadata.h>
#include "vm/ClassInlines.h"
#include "vm/Object.h"
#include "vm/Class.h"
#include "../metadata/MetadataModule.h"
#include "../metadata/MetadataUtil.h"
#include "Interpreter.h"
#include "MemoryUtil.h"
#include "InstrinctDef.h"
using namespace hybridclr::interpreter;
using hybridclr::GetInterpreterDirectlyCallMethodPointer;
#if HYBRIDCLR_ABI_ARM_64
//!!!{{INVOKE_STUB
//!!!}}INVOKE_STUB
#endif

View File

@@ -1,27 +0,0 @@
fileFormatVersion: 2
guid: 7e694feed8374f94380fe48bb70e9be1
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 0
isExplicitlyReferenced: 0
validateReferences: 1
platformData:
- first:
Any:
second:
enabled: 0
settings: {}
- first:
Editor: Editor
second:
enabled: 1
settings:
DefaultValueInitialized: true
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,22 +0,0 @@
#include "MethodBridge.h"
#include <codegen/il2cpp-codegen-metadata.h>
#include "vm/ClassInlines.h"
#include "vm/Object.h"
#include "vm/Class.h"
#include "../metadata/MetadataModule.h"
#include "../metadata/MetadataUtil.h"
#include "Interpreter.h"
#include "MemoryUtil.h"
#include "InstrinctDef.h"
using namespace hybridclr::interpreter;
using hybridclr::GetInterpreterDirectlyCallMethodPointer;
#if HYBRIDCLR_ABI_UNIVERSAL_32
//!!!{{INVOKE_STUB
//!!!}}INVOKE_STUB
#endif

View File

@@ -1,27 +0,0 @@
fileFormatVersion: 2
guid: 27135a158cd4b5049966f6f46d15ab10
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 0
isExplicitlyReferenced: 0
validateReferences: 1
platformData:
- first:
Any:
second:
enabled: 0
settings: {}
- first:
Editor: Editor
second:
enabled: 1
settings:
DefaultValueInitialized: true
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,22 +0,0 @@
#include "MethodBridge.h"
#include <codegen/il2cpp-codegen-metadata.h>
#include "vm/ClassInlines.h"
#include "vm/Object.h"
#include "vm/Class.h"
#include "../metadata/MetadataModule.h"
#include "../metadata/MetadataUtil.h"
#include "Interpreter.h"
#include "MemoryUtil.h"
#include "InstrinctDef.h"
using namespace hybridclr::interpreter;
using hybridclr::GetInterpreterDirectlyCallMethodPointer;
#if HYBRIDCLR_ABI_UNIVERSAL_64
//!!!{{INVOKE_STUB
//!!!}}INVOKE_STUB
#endif

View File

@@ -1,27 +0,0 @@
fileFormatVersion: 2
guid: ca76fdf59c873e441aa5043ad00d4537
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 0
isExplicitlyReferenced: 0
validateReferences: 1
platformData:
- first:
Any:
second:
enabled: 0
settings: {}
- first:
Editor: Editor
second:
enabled: 1
settings:
DefaultValueInitialized: true
userData:
assetBundleName:
assetBundleVariant:

View File

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

View File

@@ -1,224 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEditor;
using UnityEngine;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Diagnostics;
using Debug = UnityEngine.Debug;
namespace HybridCLR.Editor.Installer
{
public enum InstallErrorCode
{
Ok,
Il2CppInstallPathNotMatchIl2CppBranch,
Il2CppInstallPathNotExists,
NotIl2CppPath,
}
public partial class InstallerController
{
private string m_Il2CppInstallDirectory;
public string Il2CppInstallDirectory
{
get
{
return m_Il2CppInstallDirectory;
}
set
{
m_Il2CppInstallDirectory = value?.Replace('\\', '/');
if (!string.IsNullOrEmpty(m_Il2CppInstallDirectory))
{
EditorPrefs.SetString("UnityInstallDirectory", m_Il2CppInstallDirectory);
}
}
}
private string GetIl2CppPlusBranchByUnityVersion(string unityVersion)
{
if (unityVersion.Contains("2019."))
{
return "2019.4.40";
}
if (unityVersion.Contains("2020."))
{
return "2020.3.33";
}
if (unityVersion.Contains("2021."))
{
return "2021.3.1";
}
return "not support";
}
public string Il2CppBranch => GetIl2CppPlusBranchByUnityVersion(Application.unityVersion);
public string InitLocalIl2CppBatFile => Application.dataPath + "/../HybridCLRData/init_local_il2cpp_data.bat";
public string InitLocalIl2CppBashFile => Application.dataPath + "/../HybridCLRData/init_local_il2cpp_data.sh";
public InstallerController()
{
PrepareIl2CppInstallPath();
}
void PrepareIl2CppInstallPath()
{
#if UNITY_EDITOR_OSX
m_Il2CppInstallDirectory = EditorPrefs.GetString("Il2CppInstallDirectory");
if (CheckValidIl2CppInstallDirectory(Il2CppBranch, m_Il2CppInstallDirectory) == InstallErrorCode.Ok)
{
return;
}
var il2cppBranch = Il2CppBranch;
var curAppInstallPath = EditorApplication.applicationPath;
if (curAppInstallPath.Contains(il2cppBranch))
{
Il2CppInstallDirectory = $"{curAppInstallPath}/Contents/il2cpp";
return;
}
string unityHubRootDir = Directory.GetParent(curAppInstallPath).Parent.Parent.ToString();
foreach (var unityInstallDir in Directory.GetDirectories(unityHubRootDir, "*", SearchOption.TopDirectoryOnly))
{
Debug.Log("nity install dir:" + unityInstallDir);
if (unityInstallDir.Contains(il2cppBranch))
{
Il2CppInstallDirectory = $"{unityInstallDir}/Unity.app/Contents/il2cpp";
return;
}
}
Il2CppInstallDirectory = $"{curAppInstallPath}/Contents/il2cpp";
#else
m_Il2CppInstallDirectory = EditorPrefs.GetString("Il2CppInstallDirectory");
if (CheckValidIl2CppInstallDirectory(Il2CppBranch, m_Il2CppInstallDirectory) == InstallErrorCode.Ok)
{
return;
}
var il2cppBranch = Il2CppBranch;
var curAppInstallPath = EditorApplication.applicationPath;
if (curAppInstallPath.Contains(il2cppBranch))
{
Il2CppInstallDirectory = $"{Directory.GetParent(curAppInstallPath)}/Data/il2cpp";
return;
}
string unityHubRootDir = Directory.GetParent(curAppInstallPath).Parent.Parent.ToString();
Debug.Log("unity hub root dir:" + unityHubRootDir);
foreach (var unityInstallDir in Directory.GetDirectories(unityHubRootDir, "*", SearchOption.TopDirectoryOnly))
{
Debug.Log("nity install dir:" + unityInstallDir);
if (unityInstallDir.Contains(il2cppBranch))
{
Il2CppInstallDirectory = $"{unityInstallDir}/Editor/Data/il2cpp";
return;
}
}
Il2CppInstallDirectory = $"{Directory.GetParent(curAppInstallPath)}/Data/il2cpp";
#endif
}
public void InitHybridCLR(string il2cppBranch, string il2cppInstallPath)
{
if (CheckValidIl2CppInstallDirectory(il2cppBranch, il2cppInstallPath) != InstallErrorCode.Ok)
{
Debug.LogError($"请正确设置 il2cpp 安装目录");
return;
}
if (Application.platform == RuntimePlatform.WindowsEditor)
{
RunInitLocalIl2CppDataBat(il2cppBranch, il2cppInstallPath);
}
else
{
RunInitLocalIl2CppDataBash(il2cppBranch, il2cppInstallPath);
}
}
public bool HasInstalledHybridCLR()
{
return Directory.Exists($"{BuildConfig.LocalIl2CppDir}/libil2cpp/hybridclr");
}
public InstallErrorCode CheckValidIl2CppInstallDirectory(string il2cppBranch, string installDir)
{
installDir = installDir.Replace('\\', '/');
if (!Directory.Exists(installDir))
{
return InstallErrorCode.Il2CppInstallPathNotExists;
}
if (!installDir.Contains(il2cppBranch))
{
return InstallErrorCode.Il2CppInstallPathNotMatchIl2CppBranch;
}
if (!installDir.EndsWith("/il2cpp"))
{
return InstallErrorCode.NotIl2CppPath;
}
return InstallErrorCode.Ok;
}
public bool IsUnity2019(string branch)
{
return branch.Contains("2019.");
}
private void RunInitLocalIl2CppDataBat(string il2cppBranch, string il2cppInstallPath)
{
using (Process p = new Process())
{
p.StartInfo.WorkingDirectory = BuildConfig.HybridCLRDataDir;
p.StartInfo.FileName = InitLocalIl2CppBatFile;
p.StartInfo.UseShellExecute = true;
p.StartInfo.Arguments = $"{il2cppBranch} \"{il2cppInstallPath}\"";
p.Start();
p.WaitForExit();
if (IsUnity2019(il2cppBranch))
{
string srcIl2CppDll = $"{BuildConfig.HybridCLRDataDir}/ModifiedUnityAssemblies/2019.4.40/Unity.IL2CPP.dll";
string dstIl2CppDll = $"{BuildConfig.LocalIl2CppDir}/build/deploy/net471/Unity.IL2CPP.dll";
File.Copy(srcIl2CppDll, dstIl2CppDll, true);
Debug.Log($"copy {srcIl2CppDll} => {dstIl2CppDll}");
}
if (p.ExitCode == 0 && HasInstalledHybridCLR())
{
Debug.Log("HybirdCLR 安装成功");
}
}
}
private void RunInitLocalIl2CppDataBash(string il2cppBranch, string il2cppInstallPath)
{
using (Process p = new Process())
{
p.StartInfo.WorkingDirectory = Application.dataPath + "/../HybridCLRData";
p.StartInfo.FileName = "/bin/bash";
p.StartInfo.UseShellExecute = false;
p.StartInfo.CreateNoWindow = true;
p.StartInfo.Arguments = $"init_local_il2cpp_data.sh {il2cppBranch} '{il2cppInstallPath}'";
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.RedirectStandardError = true;
p.Start();
string output = p.StandardOutput.ReadToEnd();
Debug.Log(output);
p.WaitForExit();
if (HasInstalledHybridCLR())
{
Debug.Log("安装成功!!!");
}
}
}
}
}

View File

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

View File

@@ -1,117 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEditor ;
using UnityEngine;
namespace HybridCLR.Editor.Installer
{
public class InstallerWindow : EditorWindow
{
private InstallerController m_Controller;
[MenuItem("HybridCLR/Installer...", false, 0)]
private static void Open()
{
InstallerWindow window = GetWindow<InstallerWindow>("HybridCLR Installer", true);
window.minSize = new Vector2(800f, 500f);
}
private void OnEnable()
{
m_Controller = new InstallerController();
}
private void OnGUI()
{
GUI.enabled = true;
GUILayout.Space(10f);
EditorGUILayout.LabelField("=======================说明====================");
EditorGUILayout.LabelField(
$"你所在项目的Unity版本可以与il2cpp_plus版本:{m_Controller.Il2CppBranch} 不一样。\n"
+ $"由于安装HybridCLR时需要从il2cpp_plus对应版本而不是你项目版本拷贝il2cpp目录\n"
+ $"你必须同时也安装相应版本 {m_Controller.Il2CppBranch},否则无法安装", EditorStyles.wordWrappedLabel);
EditorGUILayout.LabelField("==============================================");
GUILayout.Space(10f);
EditorGUILayout.BeginVertical("box");
EditorGUILayout.LabelField($"安装状态:{(m_Controller.HasInstalledHybridCLR() ? "" : "")}", EditorStyles.boldLabel);
GUILayout.Space(5f);
EditorGUILayout.LabelField($"当前Unity版本: {Application.unityVersion}匹配的il2cpp_plus分支: {m_Controller.Il2CppBranch}");
GUISelectUnityDirectory($"il2cpp_plus分支对应Unity版本的il2cpp路径", "Select");
GUILayout.Space(10f);
GUIInstallButton("安装最新HybridCLR插件代码到本项目", "安装", InitHybridCLR);
EditorGUILayout.EndVertical();
}
private void GUIInstallButton(string content, string button, Action onClick)
{
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField(content);
GUI.enabled = m_Controller.CheckValidIl2CppInstallDirectory(m_Controller.Il2CppBranch, m_Controller.Il2CppInstallDirectory) == InstallErrorCode.Ok;
if (GUILayout.Button(button, GUILayout.Width(100)))
{
onClick?.Invoke();
GUIUtility.ExitGUI();
}
GUI.enabled = true;
EditorGUILayout.EndHorizontal();
}
private void GUISelectUnityDirectory(string content, string selectButton)
{
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField(content, GUILayout.MaxWidth(300));
string il2cppInstallDirectory = m_Controller.Il2CppInstallDirectory = EditorGUILayout.TextField(m_Controller.Il2CppInstallDirectory);
if (GUILayout.Button(selectButton, GUILayout.Width(100)))
{
string temp = EditorUtility.OpenFolderPanel(content, m_Controller.Il2CppInstallDirectory, string.Empty);
if (!string.IsNullOrEmpty(temp))
{
il2cppInstallDirectory = m_Controller.Il2CppInstallDirectory = temp;
}
}
EditorGUILayout.EndHorizontal();
InstallErrorCode err = m_Controller.CheckValidIl2CppInstallDirectory(m_Controller.Il2CppBranch, il2cppInstallDirectory);
switch (err)
{
case InstallErrorCode.Ok:
{
if (!il2cppInstallDirectory.Contains(m_Controller.Il2CppBranch))
{
EditorGUILayout.HelpBox($"li2cpp 路径未包含 '{m_Controller.Il2CppBranch}',请确保选择了 {m_Controller.Il2CppBranch} 版本的安装目录 ", MessageType.Warning);
}
break;
}
case InstallErrorCode.Il2CppInstallPathNotExists:
{
EditorGUILayout.HelpBox("li2cpp 路径不存在", MessageType.Error);
break;
}
case InstallErrorCode.Il2CppInstallPathNotMatchIl2CppBranch:
{
EditorGUILayout.HelpBox($"il2cpp 版本不匹配,必须为 {m_Controller.Il2CppBranch} 版本相应目录", MessageType.Error);
break;
}
case InstallErrorCode.NotIl2CppPath:
{
EditorGUILayout.HelpBox($"当前选择的路径不是il2cpp目录必须类似 xxx/il2cpp", MessageType.Error);
break;
}
default: throw new Exception($"not support {err}");
}
}
private void InitHybridCLR()
{
m_Controller.InitHybridCLR(m_Controller.Il2CppBranch, m_Controller.Il2CppInstallDirectory);
}
}
}

View File

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

View File

@@ -1,129 +0,0 @@
using HybridCLR.Editor.Generators;
using HybridCLR.Editor.Generators.MethodBridge;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using UnityEditor;
using UnityEngine;
namespace HybridCLR.Editor
{
internal class MethodBridgeHelper
{
private static void CleanIl2CppBuildCache()
{
string il2cppBuildCachePath = BuildConfig.Il2CppBuildCacheDir;
if (!Directory.Exists(il2cppBuildCachePath))
{
return;
}
Debug.Log($"clean il2cpp build cache:{il2cppBuildCachePath}");
Directory.Delete(il2cppBuildCachePath, true);
}
private static List<Assembly> CollectDependentAssemblies(Dictionary<string, Assembly> allAssByName, List<Assembly> dlls)
{
for(int i = 0; i < dlls.Count; i++)
{
Assembly ass = dlls[i];
foreach (var depAssName in ass.GetReferencedAssemblies())
{
if (!allAssByName.ContainsKey(depAssName.Name))
{
Debug.Log($"ignore ref assembly:{depAssName.Name}");
continue;
}
Assembly depAss = allAssByName[depAssName.Name];
if (!dlls.Contains(depAss))
{
dlls.Add(depAss);
}
}
}
return dlls;
}
private static List<Assembly> GetScanAssembiles()
{
var allAssByName = new Dictionary<string, Assembly>();
foreach(var ass in AppDomain.CurrentDomain.GetAssemblies())
{
allAssByName[ass.GetName().Name] = ass;
}
//CompileDllHelper.CompileDllActiveBuildTarget();
var rootAssemblies = BuildConfig.HotUpdateAssemblies
.Select(dll => Path.GetFileNameWithoutExtension(dll)).Concat(GeneratorConfig.GetExtraAssembiles())
.Where(name => allAssByName.ContainsKey(name)).Select(name => allAssByName[name]).ToList();
//var rootAssemblies = GeneratorConfig.GetExtraAssembiles()
// .Where(name => allAssByName.ContainsKey(name)).Select(name => allAssByName[name]).ToList();
CollectDependentAssemblies(allAssByName, rootAssemblies);
rootAssemblies.Sort((a, b) => a.GetName().Name.CompareTo(b.GetName().Name));
Debug.Log($"assembly count:{rootAssemblies.Count}");
foreach(var ass in rootAssemblies)
{
//Debug.Log($"scan assembly:{ass.GetName().Name}");
}
return rootAssemblies;
}
private static void GenerateMethodBridgeCppFile(PlatformABI platform, string fileName, bool optimized)
{
string outputFile = $"{BuildConfig.MethodBridgeCppDir}/{fileName}.cpp";
var g = new MethodBridgeGenerator(new MethodBridgeGeneratorOptions()
{
CallConvention = platform,
HotfixAssemblies = BuildConfig.HotUpdateAssemblies.Select(name =>
AppDomain.CurrentDomain.GetAssemblies().First(ass => ass.GetName().Name + ".dll" == name)).ToList(),
AllAssemblies = optimized ? GetScanAssembiles() : AppDomain.CurrentDomain.GetAssemblies().ToList(),
OutputFile = outputFile,
Optimized = optimized,
});
g.PrepareMethods();
g.Generate();
Debug.LogFormat("== output:{0} ==", outputFile);
CleanIl2CppBuildCache();
}
//[MenuItem("HybridCLR/MethodBridge/Arm64")]
//public static void MethodBridge_Arm64()
//{
// GenerateMethodBridgeCppFile(PlatformABI.Arm64, "MethodBridge_Arm64");
//}
//[MenuItem("HybridCLR/MethodBridge/Universal64")]
//public static void MethodBridge_Universal64()
//{
// GenerateMethodBridgeCppFile(PlatformABI.Universal64, "MethodBridge_Universal64");
//}
//[MenuItem("HybridCLR/MethodBridge/Universal32")]
//public static void MethodBridge_Universal32()
//{
// GenerateMethodBridgeCppFile(PlatformABI.Universal32, "MethodBridge_Universal32");
//}
public static void GenerateMethodBridgeAll(bool optimized)
{
GenerateMethodBridgeCppFile(PlatformABI.Arm64, "MethodBridge_Arm64", optimized);
GenerateMethodBridgeCppFile(PlatformABI.Universal64, "MethodBridge_Universal64", optimized);
GenerateMethodBridgeCppFile(PlatformABI.Universal32, "MethodBridge_Universal32", optimized);
}
[MenuItem("HybridCLR/MethodBridge/All_高度精简")]
public static void MethodBridge_All_Optimized()
{
GenerateMethodBridgeAll(true);
}
[MenuItem("HybridCLR/MethodBridge/All_完整(新手及开发期推荐)")]
public static void MethodBridge_All_Normal()
{
GenerateMethodBridgeAll(false);
}
}
}

View File

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