hybridclr_unity/Editor/MethodBridge/Generator.cs

251 lines
8.8 KiB
C#
Raw Normal View History

2022-09-22 08:56:07 +08:00
using dnlib.DotNet;
2022-10-17 12:16:18 +08:00
using HybridCLR.Editor.ABI;
2022-09-22 08:56:07 +08:00
using HybridCLR.Editor.Meta;
using HybridCLR.Editor.Template;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
2022-09-22 08:56:07 +08:00
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using UnityEditor;
using UnityEngine;
2022-10-17 12:16:18 +08:00
using TypeInfo = HybridCLR.Editor.ABI.TypeInfo;
2022-09-22 08:56:07 +08:00
namespace HybridCLR.Editor.MethodBridge
2022-09-22 08:56:07 +08:00
{
public class Generator
{
public class Options
{
2022-10-17 12:16:18 +08:00
public PlatformABI PlatformABI { get; set; }
2022-09-22 08:56:07 +08:00
public string TemplateCode { get; set; }
public string OutputFile { get; set; }
public IReadOnlyList<MethodDef> NotGenericMethods { get; set; }
public IReadOnlyCollection<GenericMethod> GenericMethods { get; set; }
public HashSet<GenericMethod> SpeicalPreserveMethods { get; set; }
2022-09-22 08:56:07 +08:00
}
private PlatformABI _platformABI;
2022-09-22 08:56:07 +08:00
private readonly IReadOnlyList<MethodDef> _notGenericMethods;
private readonly IReadOnlyCollection<GenericMethod> _genericMethods;
private readonly HashSet<GenericMethod> _preservedMethods;
2022-09-22 08:56:07 +08:00
private readonly string _templateCode;
private readonly string _outputFile;
2022-10-17 12:16:18 +08:00
private readonly PlatformGeneratorBase _platformAdaptor;
2022-09-22 08:56:07 +08:00
2022-10-17 12:16:18 +08:00
private readonly TypeCreatorBase _typeCreator;
2022-09-22 08:56:07 +08:00
2022-10-17 12:16:18 +08:00
private readonly HashSet<MethodDesc> _managed2nativeMethodSet = new HashSet<MethodDesc>();
2022-09-22 08:56:07 +08:00
2022-10-17 12:16:18 +08:00
private List<MethodDesc> _managed2nativeMethodList;
2022-09-22 08:56:07 +08:00
2022-10-17 12:16:18 +08:00
private readonly HashSet<MethodDesc> _native2managedMethodSet = new HashSet<MethodDesc>();
2022-09-22 08:56:07 +08:00
2022-10-17 12:16:18 +08:00
private List<MethodDesc> _native2managedMethodList;
2022-09-22 08:56:07 +08:00
2022-10-17 12:16:18 +08:00
private readonly HashSet<MethodDesc> _adjustThunkMethodSet = new HashSet<MethodDesc>();
private List<MethodDesc> _adjustThunkMethodList;
2022-09-22 08:56:07 +08:00
public Generator(Options options)
{
_platformABI = options.PlatformABI;
2022-09-22 08:56:07 +08:00
_notGenericMethods = options.NotGenericMethods;
_genericMethods = options.GenericMethods;
_preservedMethods = options.SpeicalPreserveMethods;
2022-09-22 08:56:07 +08:00
_templateCode = options.TemplateCode;
_outputFile = options.OutputFile;
2022-10-17 12:16:18 +08:00
_platformAdaptor = CreatePlatformAdaptor(options.PlatformABI);
_typeCreator = TypeCreatorFactory.CreateTypeCreator(options.PlatformABI);
2022-09-22 08:56:07 +08:00
}
2022-10-17 12:16:18 +08:00
private static PlatformGeneratorBase CreatePlatformAdaptor(PlatformABI type)
2022-09-22 08:56:07 +08:00
{
switch (type)
{
2022-10-17 12:16:18 +08:00
case PlatformABI.Universal32: return new PlatformGeneratorUniversal32();
case PlatformABI.Universal64: return new PlatformGeneratorUniversal64();
case PlatformABI.Arm64: return new PlatformGeneratorArm64();
2022-10-19 09:54:33 +08:00
case PlatformABI.WebGL32: return new PlatformGeneratorWebGL32();
2022-09-22 08:56:07 +08:00
default: throw new NotSupportedException();
}
}
2022-10-17 12:16:18 +08:00
private MethodDesc CreateMethodDesc(MethodDef methodDef, bool forceRemoveThis, TypeSig returnType, List<TypeSig> parameters)
2022-09-22 08:56:07 +08:00
{
var paramInfos = new List<ParamInfo>();
if (forceRemoveThis && !methodDef.IsStatic)
{
parameters.RemoveAt(0);
}
foreach (var paramInfo in parameters)
{
2022-10-17 12:16:18 +08:00
paramInfos.Add(new ParamInfo() { Type = _typeCreator.CreateTypeInfo(paramInfo) });
2022-09-22 08:56:07 +08:00
}
2022-10-17 12:16:18 +08:00
var mbs = new MethodDesc()
2022-09-22 08:56:07 +08:00
{
MethodDef = methodDef,
2022-10-17 12:16:18 +08:00
ReturnInfo = new ReturnInfo() { Type = returnType != null ? _typeCreator.CreateTypeInfo(returnType) : TypeInfo.s_void },
2022-09-22 08:56:07 +08:00
ParamInfos = paramInfos,
};
2022-10-17 12:16:18 +08:00
_typeCreator.OptimizeMethod(mbs);
2022-09-22 08:56:07 +08:00
return mbs;
}
2022-10-17 12:16:18 +08:00
private void AddManaged2NativeMethod(MethodDesc method)
2022-09-22 08:56:07 +08:00
{
method.Init();
_managed2nativeMethodSet.Add(method);
2022-09-22 08:56:07 +08:00
}
2022-10-17 12:16:18 +08:00
private void AddNative2ManagedMethod(MethodDesc method)
2022-09-22 08:56:07 +08:00
{
method.Init();
_native2managedMethodSet.Add(method);
2022-09-22 08:56:07 +08:00
}
2022-10-17 12:16:18 +08:00
private void AddAdjustThunkMethod(MethodDesc method)
2022-09-22 08:56:07 +08:00
{
method.Init();
_adjustThunkMethodSet.Add(method);
2022-09-22 08:56:07 +08:00
}
private void ProcessMethod(MethodDef method, List<TypeSig> klassInst, List<TypeSig> methodInst)
{
if (method.IsPrivate || (method.IsAssembly && !method.IsPublic && !method.IsFamily))
{
if (!_preservedMethods.Contains(new GenericMethod(method, klassInst, methodInst)))
{
return;
}
else
{
//Debug.Log($"[PreservedMethod] method:{method}");
}
2022-09-22 08:56:07 +08:00
}
TypeSig returnType;
List<TypeSig> parameters;
if (klassInst == null && methodInst == null)
{
returnType = method.ReturnType;
parameters = method.Parameters.Select(p => p.Type).ToList();
}
else
{
var gc = new GenericArgumentContext(klassInst, methodInst);
returnType = MetaUtil.Inflate(method.ReturnType, gc);
parameters = method.Parameters.Select(p => MetaUtil.Inflate(p.Type, gc)).ToList();
}
2022-10-17 12:16:18 +08:00
var m2nMethod = CreateMethodDesc(method, false, returnType, parameters);
2022-09-22 08:56:07 +08:00
AddManaged2NativeMethod(m2nMethod);
if (method.IsVirtual)
{
if (method.DeclaringType.IsInterface)
{
AddAdjustThunkMethod(m2nMethod);
}
2022-10-17 12:16:18 +08:00
//var adjustThunkMethod = CreateMethodDesc(method, true, returnType, parameters);
2022-09-22 08:56:07 +08:00
AddNative2ManagedMethod(m2nMethod);
}
if (method.Name == "Invoke" && method.DeclaringType.IsDelegate)
{
2022-10-17 12:16:18 +08:00
var openMethod = CreateMethodDesc(method, true, returnType, parameters);
2022-09-22 08:56:07 +08:00
AddNative2ManagedMethod(openMethod);
}
}
public void PrepareMethods()
{
foreach(var method in _notGenericMethods)
{
ProcessMethod(method, null, null);
}
foreach(var method in _genericMethods)
{
ProcessMethod(method.Method, method.KlassInst, method.MethodInst);
}
{
2022-10-17 12:16:18 +08:00
var sortedMethods = new SortedDictionary<string, MethodDesc>();
2022-09-22 08:56:07 +08:00
foreach (var method in _managed2nativeMethodSet)
{
sortedMethods.Add(method.CreateCallSigName(), method);
}
_managed2nativeMethodList = sortedMethods.Values.ToList();
}
{
2022-10-17 12:16:18 +08:00
var sortedMethods = new SortedDictionary<string, MethodDesc>();
2022-09-22 08:56:07 +08:00
foreach (var method in _native2managedMethodSet)
{
sortedMethods.Add(method.CreateCallSigName(), method);
}
_native2managedMethodList = sortedMethods.Values.ToList();
}
{
2022-10-17 12:16:18 +08:00
var sortedMethods = new SortedDictionary<string, MethodDesc>();
2022-09-22 08:56:07 +08:00
foreach (var method in _adjustThunkMethodSet)
{
sortedMethods.Add(method.CreateCallSigName(), method);
}
_adjustThunkMethodList = sortedMethods.Values.ToList();
}
}
public void Generate()
{
var frr = new FileRegionReplace(_templateCode.Replace("{PLATFORM_ABI}", ABIUtil.GetHybridCLRPlatformMacro(_platformABI)));
2022-09-22 08:56:07 +08:00
List<string> lines = new List<string>(20_0000);
Debug.LogFormat("== managed2native:{0} native2managed:{1} adjustThunk:{2}",
_managed2nativeMethodList.Count, _native2managedMethodList.Count, _adjustThunkMethodList.Count);
foreach(var method in _managed2nativeMethodList)
{
_platformAdaptor.GenerateManaged2NativeMethod(method, lines);
}
_platformAdaptor.GenerateManaged2NativeStub(_managed2nativeMethodList, lines);
foreach (var method in _native2managedMethodList)
{
_platformAdaptor.GenerateNative2ManagedMethod(method, lines);
}
_platformAdaptor.GenerateNative2ManagedStub(_native2managedMethodList, lines);
foreach (var method in _adjustThunkMethodList)
{
_platformAdaptor.GenerateAdjustThunkMethod(method, lines);
}
_platformAdaptor.GenerateAdjustThunkStub(_adjustThunkMethodList, lines);
frr.Replace("CODE", string.Join("\n", lines));
2022-09-22 08:56:07 +08:00
Directory.CreateDirectory(Path.GetDirectoryName(_outputFile));
frr.Commit(_outputFile);
}
}
}