mirror of
https://github.com/Alex-Rachel/TEngine.git
synced 2025-08-07 16:45:10 +00:00
更新HybirdCLR
更新HybirdCLR
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5441af6e690e22643970bc4bafba0eb9
|
||||
guid: f775bd6af30f702448064119d19be43f
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b0d3fa47cdbec26468b426ee8e23e245
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0cca09dc9d27f314da15fa746a01d51c
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -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}";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bf7714fc37515834382cd5836b503a9f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -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",
|
||||
};
|
||||
}
|
||||
}
|
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 33c09b498146d144a947ed6d8ff104f3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 91aca02079207d746b74aeea1b595127
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f85b93bff3478c045ae862a7cc216b18
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -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*";
|
||||
}
|
||||
}
|
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e1465458aaad6884d95af7c4fc2de7a1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e5aa6559bd1b1e4488aa6746eda8202b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -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",
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d1d14f8f858560948ae1dfa0fa572e51
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4aa66b41c89ed7742ad067898725f7ff
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -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);
|
||||
}
|
||||
}
|
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 983dbdeb1fb7d0b43a863c6b22160ace
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3171ed79d43e06c4b8c889b0a3f38969
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cbe63fb39b5bdcc448f3589b475fb5d8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c04e163336b93af44b4b565d0ab195e2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -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,
|
||||
}
|
||||
}
|
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7886905937fafb64999dc4e358565982
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -1,9 +0,0 @@
|
||||
namespace HybridCLR.Editor.Generators.MethodBridge
|
||||
{
|
||||
public enum PlatformABI
|
||||
{
|
||||
Universal32,
|
||||
Universal64,
|
||||
Arm64,
|
||||
}
|
||||
}
|
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: deee8d06a7f05bf4d9ab4b78f0a8a47c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -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("};");
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ebf14107fd82b364cb7d61276d444829
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -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;" : "")}
|
||||
}}
|
||||
");
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bff17a6e8ee060c4eb9ac97fcf30bf78
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -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;" : "")}
|
||||
}}
|
||||
");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fb741900113b22443a2054ddba6b131b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -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;" : "")}
|
||||
}}
|
||||
");
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 26324be9505c9f54996bcbb62ba49132
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 50c5ec2d43d3fda4a8b8cfa75cb37a74
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5afd7344483678a4abcb56158fd1442d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 49b3dbcebadb1b543a42e01afec07ed1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 32ec2cc1cf5c468468308fa6308fba19
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3a1563e7820e5b648a6a6691677f564c
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -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
|
@@ -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:
|
@@ -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
|
@@ -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:
|
@@ -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
|
@@ -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:
|
@@ -1,8 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a4a3d499c10d66f43af10a859e276a8f
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -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("安装成功!!!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 44c8627d126b30d4e9560b1f738264ca
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 959fbf0bb06629542969354505189240
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 18beea79433bdce44af834574cd9c212
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Reference in New Issue
Block a user