2025-03-31 14:55:24 +08:00
using dnlib.DotNet ;
using HybridCLR.Editor.ABI ;
using HybridCLR.Editor.Meta ;
using HybridCLR.Editor.Template ;
using System ;
using System.Collections.Generic ;
using System.ComponentModel.DataAnnotations ;
using System.IO ;
using System.Linq ;
using System.Reflection ;
using System.Text ;
using System.Threading.Tasks ;
using UnityEditor ;
using UnityEngine ;
using TypeInfo = HybridCLR . Editor . ABI . TypeInfo ;
2025-06-12 18:00:06 +08:00
using CallingConvention = System . Runtime . InteropServices . CallingConvention ;
using TypeAttributes = dnlib . DotNet . TypeAttributes ;
using System.Runtime.InteropServices ;
2025-03-31 14:55:24 +08:00
namespace HybridCLR.Editor.MethodBridge
{
public class Generator
{
public class Options
{
public string TemplateCode { get ; set ; }
public string OutputFile { get ; set ; }
public IReadOnlyCollection < GenericMethod > GenericMethods { get ; set ; }
2025-06-12 18:00:06 +08:00
public List < RawMonoPInvokeCallbackMethodInfo > ReversePInvokeMethods { get ; set ; }
public IReadOnlyCollection < CallNativeMethodSignatureInfo > CalliMethodSignatures { get ; set ; }
public bool Development { get ; set ; }
}
private class ABIReversePInvokeMethodInfo
{
public MethodDesc Method { get ; set ; }
public CallingConvention Callvention { get ; set ; }
public int Count { get ; set ; }
public string Signature { get ; set ; }
}
private class CalliMethodInfo
{
public MethodDesc Method { get ; set ; }
public CallingConvention Callvention { get ; set ; }
public string Signature { get ; set ; }
2025-03-31 14:55:24 +08:00
}
private readonly List < GenericMethod > _genericMethods ;
2025-06-12 18:00:06 +08:00
private readonly List < RawMonoPInvokeCallbackMethodInfo > _originalReversePInvokeMethods ;
private readonly List < CallNativeMethodSignatureInfo > _originalCalliMethodSignatures ;
2025-03-31 14:55:24 +08:00
private readonly string _templateCode ;
private readonly string _outputFile ;
2025-06-12 18:00:06 +08:00
private readonly bool _development ;
2025-03-31 14:55:24 +08:00
private readonly TypeCreator _typeCreator ;
private readonly HashSet < MethodDesc > _managed2nativeMethodSet = new HashSet < MethodDesc >();
private readonly HashSet < MethodDesc > _native2managedMethodSet = new HashSet < MethodDesc >();
private readonly HashSet < MethodDesc > _adjustThunkMethodSet = new HashSet < MethodDesc >();
2025-06-12 18:00:06 +08:00
private List < ABIReversePInvokeMethodInfo > _reversePInvokeMethods ;
private List < CalliMethodInfo > _callidMethods ;
2025-03-31 14:55:24 +08:00
public Generator ( Options options )
{
List <( GenericMethod , string )> genericMethodInfo = options . GenericMethods . Select ( m => ( m , m . ToString ())). ToList ();
genericMethodInfo . Sort (( a , b ) => string . CompareOrdinal ( a . Item2 , b . Item2 ));
_genericMethods = genericMethodInfo . Select ( m => m . Item1 ). ToList ();
2025-06-12 18:00:06 +08:00
_originalReversePInvokeMethods = options . ReversePInvokeMethods ;
_originalCalliMethodSignatures = options . CalliMethodSignatures . ToList ();
2025-03-31 14:55:24 +08:00
_templateCode = options . TemplateCode ;
_outputFile = options . OutputFile ;
_typeCreator = new TypeCreator ();
2025-06-12 18:00:06 +08:00
_development = options . Development ;
2025-03-31 14:55:24 +08:00
}
private readonly Dictionary < string , TypeInfo > _sig2Types = new Dictionary < string , TypeInfo >();
private TypeInfo GetSharedTypeInfo ( TypeSig type )
{
var typeInfo = _typeCreator . CreateTypeInfo ( type );
if (! typeInfo . IsStruct )
{
return typeInfo ;
}
string sigName = ToFullName ( typeInfo . Klass );
if (! _sig2Types . TryGetValue ( sigName , out var sharedTypeInfo ))
{
sharedTypeInfo = typeInfo ;
_sig2Types . Add ( sigName , sharedTypeInfo );
}
return sharedTypeInfo ;
}
private MethodDesc CreateMethodDesc ( MethodDef methodDef , bool forceRemoveThis , TypeSig returnType , List < TypeSig > parameters )
{
var paramInfos = new List < ParamInfo >();
if ( forceRemoveThis && ! methodDef . IsStatic )
{
parameters . RemoveAt ( 0 );
}
if ( returnType . ContainsGenericParameter )
{
throw new Exception ( $"[PreservedMethod] method:{methodDef} has generic parameters" );
}
foreach ( var paramInfo in parameters )
{
if ( paramInfo . ContainsGenericParameter )
{
throw new Exception ( $"[PreservedMethod] method:{methodDef} has generic parameters" );
}
paramInfos . Add ( new ParamInfo () { Type = GetSharedTypeInfo ( paramInfo ) });
}
var mbs = new MethodDesc ()
{
MethodDef = methodDef ,
ReturnInfo = new ReturnInfo () { Type = returnType != null ? GetSharedTypeInfo ( returnType ) : TypeInfo . s_void },
ParamInfos = paramInfos ,
};
return mbs ;
}
2025-06-12 18:00:06 +08:00
private MethodDesc CreateMethodDesc ( TypeSig returnType , List < TypeSig > parameters )
{
var paramInfos = new List < ParamInfo >();
if ( returnType . ContainsGenericParameter )
{
throw new Exception ( $"[PreservedMethod] method has generic parameters" );
}
foreach ( var paramInfo in parameters )
{
if ( paramInfo . ContainsGenericParameter )
{
throw new Exception ( $"[PreservedMethod] method has generic parameters" );
}
paramInfos . Add ( new ParamInfo () { Type = GetSharedTypeInfo ( paramInfo ) });
}
var mbs = new MethodDesc ()
{
MethodDef = null ,
ReturnInfo = new ReturnInfo () { Type = returnType != null ? GetSharedTypeInfo ( returnType ) : TypeInfo . s_void },
ParamInfos = paramInfos ,
};
return mbs ;
}
2025-03-31 14:55:24 +08:00
private void AddManaged2NativeMethod ( MethodDesc method )
{
method . Init ();
_managed2nativeMethodSet . Add ( method );
}
private void AddNative2ManagedMethod ( MethodDesc method )
{
method . Init ();
_native2managedMethodSet . Add ( method );
}
private void AddAdjustThunkMethod ( MethodDesc method )
{
method . Init ();
_adjustThunkMethodSet . Add ( method );
}
private void ProcessMethod ( MethodDef method , List < TypeSig > klassInst , List < TypeSig > methodInst )
{
if ( method . IsPrivate || ( method . IsAssembly && ! method . IsPublic && ! method . IsFamily ))
{
if ( klassInst == null && methodInst == null )
{
return ;
}
else
{
//Debug.Log($"[PreservedMethod] method:{method}");
}
}
ICorLibTypes corLibTypes = method . Module . CorLibTypes ;
TypeSig returnType ;
List < TypeSig > parameters ;
if ( klassInst == null && methodInst == null )
{
if ( method . HasGenericParameters )
{
throw new Exception ( $"[PreservedMethod] method:{method} has generic parameters" );
}
returnType = MetaUtil . ToShareTypeSig ( corLibTypes , method . ReturnType );
parameters = method . Parameters . Select ( p => MetaUtil . ToShareTypeSig ( corLibTypes , p . Type )). ToList ();
}
else
{
var gc = new GenericArgumentContext ( klassInst , methodInst );
returnType = MetaUtil . ToShareTypeSig ( corLibTypes , MetaUtil . Inflate ( method . ReturnType , gc ));
parameters = method . Parameters . Select ( p => MetaUtil . ToShareTypeSig ( corLibTypes , MetaUtil . Inflate ( p . Type , gc ))). ToList ();
}
var m2nMethod = CreateMethodDesc ( method , false , returnType , parameters );
AddManaged2NativeMethod ( m2nMethod );
if ( method . IsVirtual )
{
if ( method . DeclaringType . IsInterface )
{
AddAdjustThunkMethod ( m2nMethod );
}
//var adjustThunkMethod = CreateMethodDesc(method, true, returnType, parameters);
AddNative2ManagedMethod ( m2nMethod );
}
if ( method . Name == "Invoke" && method . DeclaringType . IsDelegate )
{
var openMethod = CreateMethodDesc ( method , true , returnType , parameters );
AddNative2ManagedMethod ( openMethod );
}
}
2025-06-12 18:00:06 +08:00
private void PrepareMethodBridges ()
2025-03-31 14:55:24 +08:00
{
2025-06-12 18:00:06 +08:00
foreach ( var method in _genericMethods )
2025-03-31 14:55:24 +08:00
{
ProcessMethod ( method . Method , method . KlassInst , method . MethodInst );
}
2025-06-12 18:00:06 +08:00
foreach ( var reversePInvokeMethod in _originalReversePInvokeMethods )
{
MethodDef method = reversePInvokeMethod . Method ;
ICorLibTypes corLibTypes = method . Module . CorLibTypes ;
var returnType = MetaUtil . ToShareTypeSig ( corLibTypes , method . ReturnType );
var parameters = method . Parameters . Select ( p => MetaUtil . ToShareTypeSig ( corLibTypes , p . Type )). ToList ();
var sharedMethod = CreateMethodDesc ( method , true , returnType , parameters );
sharedMethod . Init ();
AddNative2ManagedMethod ( sharedMethod );
}
2025-03-31 14:55:24 +08:00
}
static void CheckUnique ( IEnumerable < string > names )
{
var set = new HashSet < string >();
foreach ( var name in names )
{
if (! set . Add ( name ))
{
throw new Exception ( $"[CheckUnique] duplicate name:{name}" );
}
}
}
private List < MethodDesc > _managed2NativeMethodList0 ;
private List < MethodDesc > _native2ManagedMethodList0 ;
private List < MethodDesc > _adjustThunkMethodList0 ;
private List < TypeInfo > _structTypes0 ;
private void CollectTypesAndMethods ()
{
_managed2NativeMethodList0 = _managed2nativeMethodSet . ToList ();
_managed2NativeMethodList0 . Sort (( a , b ) => string . CompareOrdinal ( a . Sig , b . Sig ));
_native2ManagedMethodList0 = _native2managedMethodSet . ToList ();
_native2ManagedMethodList0 . Sort (( a , b ) => string . CompareOrdinal ( a . Sig , b . Sig ));
_adjustThunkMethodList0 = _adjustThunkMethodSet . ToList ();
_adjustThunkMethodList0 . Sort (( a , b ) => string . CompareOrdinal ( a . Sig , b . Sig ));
var structTypeSet = new HashSet < TypeInfo >();
CollectStructDefs ( _managed2NativeMethodList0 , structTypeSet );
CollectStructDefs ( _native2ManagedMethodList0 , structTypeSet );
CollectStructDefs ( _adjustThunkMethodList0 , structTypeSet );
_structTypes0 = structTypeSet . ToList ();
_structTypes0 . Sort (( a , b ) => a . TypeId - b . TypeId );
CheckUnique ( _structTypes0 . Select ( t => ToFullName ( t . Klass )));
CheckUnique ( _structTypes0 . Select ( t => t . CreateSigName ()));
Debug . LogFormat ( "== before optimization struct:{3} managed2native:{0} native2managed:{1} adjustThunk:{2}" ,
_managed2NativeMethodList0 . Count , _native2ManagedMethodList0 . Count , _adjustThunkMethodList0 . Count , _structTypes0 . Count );
}
2025-06-12 18:00:06 +08:00
private class AnalyzeFieldInfo
{
public FieldDef field ;
public TypeInfo type ;
}
2025-03-31 14:55:24 +08:00
private class AnalyzeTypeInfo
{
2025-06-12 18:00:06 +08:00
public TypeInfo isoType ;
public List < AnalyzeFieldInfo > fields ;
2025-03-31 14:55:24 +08:00
public string signature ;
2025-06-12 18:00:06 +08:00
public uint originalPackingSize ;
public uint packingSize ;
public uint classSize ;
public LayoutKind layout ;
public bool blittable ;
2025-03-31 14:55:24 +08:00
}
private readonly Dictionary < TypeInfo , AnalyzeTypeInfo > _analyzeTypeInfos = new Dictionary < TypeInfo , AnalyzeTypeInfo >();
private readonly Dictionary < string , TypeInfo > _signature2Type = new Dictionary < string , TypeInfo >();
2025-06-12 18:00:06 +08:00
private bool IsBlittable ( TypeSig typeSig )
{
typeSig = typeSig . RemovePinnedAndModifiers ();
if ( typeSig . IsByRef )
{
return true ;
}
switch ( typeSig . ElementType )
{
case ElementType . Void : return false ;
case ElementType . Boolean :
case ElementType . I1 :
case ElementType . U1 :
case ElementType . I2 :
case ElementType . Char :
case ElementType . U2 :
case ElementType . I4 :
case ElementType . U4 :
case ElementType . I8 :
case ElementType . U8 :
case ElementType . R4 :
case ElementType . R8 :
case ElementType . I :
case ElementType . U :
case ElementType . Ptr :
case ElementType . ByRef :
case ElementType . FnPtr :
case ElementType . TypedByRef : return true ;
case ElementType . String :
case ElementType . Class :
case ElementType . Array :
case ElementType . SZArray :
case ElementType . Object :
case ElementType . Module :
case ElementType . Var :
case ElementType . MVar : return false ;
case ElementType . ValueType :
{
TypeDef typeDef = typeSig . ToTypeDefOrRef (). ResolveTypeDef ();
if ( typeDef == null )
{
throw new Exception ( $"type:{typeSig} definition could not be found. Please try `HybridCLR/Genergate/LinkXml`, then Build once to generate the AOT dll, and then regenerate the bridge function" );
}
if ( typeDef . IsEnum )
{
return true ;
}
return CalculateAnalyzeTypeInfoBasic ( GetSharedTypeInfo ( typeSig )). blittable ;
}
case ElementType . GenericInst :
{
GenericInstSig gis = ( GenericInstSig ) typeSig ;
if (! gis . GenericType . IsValueType )
{
return false ;
}
TypeDef typeDef = gis . GenericType . ToTypeDefOrRef (). ResolveTypeDef ();
if ( typeDef . IsEnum )
{
return true ;
}
return CalculateAnalyzeTypeInfoBasic ( GetSharedTypeInfo ( typeSig )). blittable ;
}
default : throw new NotSupportedException ( $"{typeSig.ElementType}" );
}
}
2025-03-31 14:55:24 +08:00
private AnalyzeTypeInfo CalculateAnalyzeTypeInfoBasic ( TypeInfo typeInfo )
{
2025-06-12 18:00:06 +08:00
Debug . Assert ( typeInfo . IsStruct );
if ( _analyzeTypeInfos . TryGetValue ( typeInfo , out var ati ))
{
return ati ;
}
2025-03-31 14:55:24 +08:00
TypeSig type = typeInfo . Klass ;
TypeDef typeDef = type . ToTypeDefOrRef (). ResolveTypeDefThrow ();
List < TypeSig > klassInst = type . ToGenericInstSig ()?. GenericArguments ?. ToList ();
GenericArgumentContext ctx = klassInst != null ? new GenericArgumentContext ( klassInst , null ) : null ;
2025-06-12 18:00:06 +08:00
var fields = new List < AnalyzeFieldInfo >();
2025-03-31 14:55:24 +08:00
2025-06-12 18:00:06 +08:00
bool blittable = true ;
2025-03-31 14:55:24 +08:00
foreach ( FieldDef field in typeDef . Fields )
{
if ( field . IsStatic )
{
continue ;
}
TypeSig fieldType = ctx != null ? MetaUtil . Inflate ( field . FieldType , ctx ) : field . FieldType ;
2025-06-12 18:00:06 +08:00
blittable &= IsBlittable ( fieldType );
TypeInfo sharedFieldTypeInfo = GetSharedTypeInfo ( fieldType );
TypeInfo isoType = ToIsomorphicType ( sharedFieldTypeInfo );
fields . Add ( new AnalyzeFieldInfo { field = field , type = isoType });
}
//analyzeTypeInfo.blittable = blittable;
//analyzeTypeInfo.packingSize = blittable ? analyzeTypeInfo.originalPackingSize : 0;
ClassLayout sa = typeDef . ClassLayout ;
uint originalPackingSize = sa ?. PackingSize ?? 0 ;
var analyzeTypeInfo = new AnalyzeTypeInfo ()
{
originalPackingSize = originalPackingSize ,
packingSize = blittable && ! typeDef . IsAutoLayout ? originalPackingSize : 0 ,
classSize = sa ?. ClassSize ?? 0 ,
layout = typeDef . IsAutoLayout ? LayoutKind . Auto : ( typeDef . IsExplicitLayout ? LayoutKind . Explicit : LayoutKind . Sequential ),
fields = fields ,
blittable = blittable ,
};
_analyzeTypeInfos . Add ( typeInfo , analyzeTypeInfo );
analyzeTypeInfo . signature = GetOrCalculateTypeInfoSignature ( typeInfo );
if ( _signature2Type . TryGetValue ( analyzeTypeInfo . signature , out var sharedType ))
{
// Debug.Log($"[ToIsomorphicType] type:{type.Klass} ==> sharedType:{sharedType.Klass} signature:{signature} ");
analyzeTypeInfo . isoType = sharedType ;
}
else
{
analyzeTypeInfo . isoType = typeInfo ;
_signature2Type . Add ( analyzeTypeInfo . signature , typeInfo );
2025-03-31 14:55:24 +08:00
}
2025-06-12 18:00:06 +08:00
2025-03-31 14:55:24 +08:00
return analyzeTypeInfo ;
}
private string GetOrCalculateTypeInfoSignature ( TypeInfo typeInfo )
{
if (! typeInfo . IsStruct )
{
return typeInfo . CreateSigName ();
}
var ati = _analyzeTypeInfos [ typeInfo ];
//if (_analyzeTypeInfos.TryGetValue(typeInfo, out var ati))
//{
// return ati.signature;
//}
//ati = CalculateAnalyzeTypeInfoBasic(typeInfo);
//_analyzeTypeInfos.Add(typeInfo, ati);
if ( ati . signature != null )
{
return ati . signature ;
}
2025-06-12 18:00:06 +08:00
2025-03-31 14:55:24 +08:00
var sigBuf = new StringBuilder ();
2025-06-12 18:00:06 +08:00
if ( ati . packingSize != 0 || ati . classSize != 0 || ati . layout != LayoutKind . Sequential || ! ati . blittable )
{
sigBuf . Append ( $"[{ati.classSize}|{ati.packingSize}|{ati.layout}|{(ati.blittable ? 0 : 1)}]" );
}
2025-03-31 14:55:24 +08:00
foreach ( var field in ati . fields )
{
2025-06-12 18:00:06 +08:00
string fieldOffset = field . field . FieldOffset != null ? field . field . FieldOffset . ToString () + "|" : "" ;
sigBuf . Append ( "{" + fieldOffset + GetOrCalculateTypeInfoSignature ( ToIsomorphicType ( field . type )) + "}" );
2025-03-31 14:55:24 +08:00
}
return ati . signature = sigBuf . ToString ();
}
private TypeInfo ToIsomorphicType ( TypeInfo type )
{
if (! type . IsStruct )
{
return type ;
}
2025-06-12 18:00:06 +08:00
return CalculateAnalyzeTypeInfoBasic ( type ). isoType ;
2025-03-31 14:55:24 +08:00
}
private MethodDesc ToIsomorphicMethod ( MethodDesc method )
{
var paramInfos = new List < ParamInfo >();
foreach ( var paramInfo in method . ParamInfos )
{
paramInfos . Add ( new ParamInfo () { Type = ToIsomorphicType ( paramInfo . Type ) });
}
var mbs = new MethodDesc ()
{
MethodDef = method . MethodDef ,
ReturnInfo = new ReturnInfo () { Type = ToIsomorphicType ( method . ReturnInfo . Type ) },
ParamInfos = paramInfos ,
};
mbs . Init ();
return mbs ;
}
private List < MethodDesc > _managed2NativeMethodList ;
private List < MethodDesc > _native2ManagedMethodList ;
private List < MethodDesc > _adjustThunkMethodList ;
private List < TypeInfo > structTypes ;
private void BuildAnalyzeTypeInfos ()
{
foreach ( var type in _structTypes0 )
{
ToIsomorphicType ( type );
}
structTypes = _signature2Type . Values . ToList ();
structTypes . Sort (( a , b ) => a . TypeId - b . TypeId );
}
private List < MethodDesc > ToUniqueOrderedList ( List < MethodDesc > methods )
{
var methodMap = new SortedDictionary < string , MethodDesc >();
foreach ( var method in methods )
{
var sharedMethod = ToIsomorphicMethod ( method );
var sig = sharedMethod . Sig ;
if (! methodMap . TryGetValue ( sig , out var _ ))
{
methodMap . Add ( sig , sharedMethod );
}
}
return methodMap . Values . ToList ();
}
2025-06-12 18:00:06 +08:00
private static string MakeReversePInvokeSignature ( MethodDesc desc , CallingConvention CallingConventionention )
{
string convStr = (( char )( 'A' + ( int ) CallingConventionention - 1 )). ToString ();
return $"{convStr}{desc.Sig}" ;
}
private static string MakeCalliSignature ( MethodDesc desc , CallingConvention CallingConventionention )
{
string convStr = (( char )( 'A' + Math . Max (( int ) CallingConventionention - 1 , 0 ))). ToString ();
return $"{convStr}{desc.Sig}" ;
}
private static CallingConvention GetCallingConvention ( MethodDef method )
{
var monoPInvokeCallbackAttr = method . CustomAttributes . FirstOrDefault ( ca => ca . AttributeType . Name == "MonoPInvokeCallbackAttribute" );
if ( monoPInvokeCallbackAttr == null )
{
return CallingConvention . Winapi ;
}
object delegateTypeSig = monoPInvokeCallbackAttr . ConstructorArguments [ 0 ]. Value ;
TypeDef delegateTypeDef ;
if ( delegateTypeSig is ClassSig classSig )
{
delegateTypeDef = classSig . TypeDefOrRef . ResolveTypeDefThrow ();
}
else if ( delegateTypeSig is GenericInstSig genericInstSig )
{
delegateTypeDef = genericInstSig . GenericType . TypeDefOrRef . ResolveTypeDefThrow ();
}
else
{
delegateTypeDef = null ;
}
if ( delegateTypeDef == null )
{
throw new NotSupportedException ( $"Unsupported delegate type: {delegateTypeSig}" );
}
var attr = delegateTypeDef . CustomAttributes . FirstOrDefault ( ca => ca . AttributeType . FullName == "System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute" );
if ( attr == null )
{
return CallingConvention . Winapi ;
}
var conv = attr . ConstructorArguments [ 0 ]. Value ;
return ( CallingConvention ) conv ;
}
private List < ABIReversePInvokeMethodInfo > BuildABIMethods ( List < RawMonoPInvokeCallbackMethodInfo > rawMethods )
{
var methodsBySig = new Dictionary < string , ABIReversePInvokeMethodInfo >();
foreach ( var method in rawMethods )
{
var sharedMethod = new MethodDesc
{
MethodDef = method . Method ,
ReturnInfo = new ReturnInfo { Type = GetSharedTypeInfo ( method . Method . ReturnType ) },
ParamInfos = method . Method . Parameters . Select ( p => new ParamInfo { Type = GetSharedTypeInfo ( p . Type ) }). ToList (),
};
sharedMethod . Init ();
sharedMethod = ToIsomorphicMethod ( sharedMethod );
CallingConvention callingConv = GetCallingConvention ( method . Method );
string signature = MakeReversePInvokeSignature ( sharedMethod , callingConv );
if (! methodsBySig . TryGetValue ( signature , out var arm ))
{
arm = new ABIReversePInvokeMethodInfo ()
{
Method = sharedMethod ,
Signature = signature ,
Count = 0 ,
Callvention = callingConv ,
};
methodsBySig . Add ( signature , arm );
}
int preserveCount = method . GenerationAttribute != null ? ( int ) method . GenerationAttribute . ConstructorArguments [ 0 ]. Value : 1 ;
arm . Count += preserveCount ;
}
var newMethods = methodsBySig . Values . ToList ();
newMethods . Sort (( a , b ) => string . CompareOrdinal ( a . Signature , b . Signature ));
return newMethods ;
}
private List < CalliMethodInfo > BuildCalliMethods ( List < CallNativeMethodSignatureInfo > rawMethods )
{
var methodsBySig = new Dictionary < string , CalliMethodInfo >();
foreach ( var method in rawMethods )
{
var sharedMethod = new MethodDesc
{
MethodDef = null ,
ReturnInfo = new ReturnInfo { Type = GetSharedTypeInfo ( method . MethodSig . RetType ) },
ParamInfos = method . MethodSig . Params . Select ( p => new ParamInfo { Type = GetSharedTypeInfo ( p ) }). ToList (),
};
sharedMethod . Init ();
sharedMethod = ToIsomorphicMethod ( sharedMethod );
CallingConvention callingConv = ( CallingConvention )(( int )( method . MethodSig . CallingConvention & dnlib . DotNet . CallingConvention . Mask ) + 1 );
string signature = MakeCalliSignature ( sharedMethod , callingConv );
if (! methodsBySig . TryGetValue ( signature , out var arm ))
{
arm = new CalliMethodInfo ()
{
Method = sharedMethod ,
Signature = signature ,
Callvention = callingConv ,
};
methodsBySig . Add ( signature , arm );
}
}
var newMethods = methodsBySig . Values . ToList ();
newMethods . Sort (( a , b ) => string . CompareOrdinal ( a . Signature , b . Signature ));
return newMethods ;
}
2025-03-31 14:55:24 +08:00
private void BuildOptimizedMethods ()
{
_managed2NativeMethodList = ToUniqueOrderedList ( _managed2NativeMethodList0 );
_native2ManagedMethodList = ToUniqueOrderedList ( _native2ManagedMethodList0 );
_adjustThunkMethodList = ToUniqueOrderedList ( _adjustThunkMethodList0 );
2025-06-12 18:00:06 +08:00
_reversePInvokeMethods = BuildABIMethods ( _originalReversePInvokeMethods );
_callidMethods = BuildCalliMethods ( _originalCalliMethodSignatures );
2025-03-31 14:55:24 +08:00
}
private void OptimizationTypesAndMethods ()
{
BuildAnalyzeTypeInfos ();
BuildOptimizedMethods ();
Debug . LogFormat ( "== after optimization struct:{3} managed2native:{0} native2managed:{1} adjustThunk:{2}" ,
_managed2NativeMethodList . Count , _native2ManagedMethodList . Count , _adjustThunkMethodList . Count , structTypes . Count );
}
private void GenerateCode ()
{
var frr = new FileRegionReplace ( _templateCode );
2025-06-12 18:00:06 +08:00
List < string > lines = new List < string >( 20_0000 )
{
"\n" ,
$"// DEVELOPMENT={(_development ? 1 : 0)}" ,
"\n"
};
2025-03-31 14:55:24 +08:00
var classInfos = new List < ClassInfo >();
2025-06-12 18:00:06 +08:00
var classTypeSet = new Dictionary < TypeInfo , ClassInfo >();
2025-03-31 14:55:24 +08:00
foreach ( var type in structTypes )
{
GenerateClassInfo ( type , classTypeSet , classInfos );
}
GenerateStructDefines ( classInfos , lines );
// use structTypes0 to generate signature
GenerateStructureSignatureStub ( _structTypes0 , lines );
foreach ( var method in _managed2NativeMethodList )
{
GenerateManaged2NativeMethod ( method , lines );
}
GenerateManaged2NativeStub ( _managed2NativeMethodList , lines );
foreach ( var method in _native2ManagedMethodList )
{
GenerateNative2ManagedMethod ( method , lines );
}
GenerateNative2ManagedStub ( _native2ManagedMethodList , lines );
foreach ( var method in _adjustThunkMethodList )
{
GenerateAdjustThunkMethod ( method , lines );
}
GenerateAdjustThunkStub ( _adjustThunkMethodList , lines );
2025-06-12 18:00:06 +08:00
GenerateReversePInvokeWrappers ( _reversePInvokeMethods , lines );
foreach ( var method in _callidMethods )
{
GenerateManaged2NativeFunctionPointerMethod ( method , lines );
}
GenerateManaged2NativeFunctionPointerMethodStub ( _callidMethods , lines );
2025-03-31 14:55:24 +08:00
frr . Replace ( "CODE" , string . Join ( "\n" , lines ));
Directory . CreateDirectory ( Path . GetDirectoryName ( _outputFile ));
frr . Commit ( _outputFile );
}
2025-06-12 18:00:06 +08:00
private static string GetIl2cppCallConventionName ( CallingConvention conv )
{
switch ( conv )
{
case 0 :
case CallingConvention . Winapi :
return "DEFAULT_CALL" ;
case CallingConvention . Cdecl :
return "CDECL" ;
case CallingConvention . StdCall :
return "STDCALL" ;
case CallingConvention . ThisCall :
return "THISCALL" ;
case CallingConvention . FastCall :
return "FASTCALL" ;
default :
throw new NotSupportedException ( $"Unsupported CallingConvention {conv}" );
}
}
private void GenerateReversePInvokeWrappers ( List < ABIReversePInvokeMethodInfo > methods , List < string > lines )
{
int methodIndex = 0 ;
var stubCodes = new List < string >();
foreach ( var methodInfo in methods )
{
MethodDesc method = methodInfo . Method ;
string il2cppCallConventionName = GetIl2cppCallConventionName ( methodInfo . Callvention );
string paramDeclaringListWithoutMethodInfoStr = string . Join ( ", " , method . ParamInfos . Select ( p => $"{p.Type.GetTypeName()} __arg{p.Index}" ));
string paramNameListWithoutMethodInfoStr = string . Join ( ", " , method . ParamInfos . Select ( p => $"__arg{p.Index}" ). Concat ( new string [] { "method" }));
string paramTypeListWithMethodInfoStr = string . Join ( ", " , method . ParamInfos . Select ( p => $"{p.Type.GetTypeName()}" ). Concat ( new string [] { "const MethodInfo*" }));
string methodTypeDef = $"typedef {method.ReturnInfo.Type.GetTypeName()} (*Callback)({paramTypeListWithMethodInfoStr})" ;
for ( int i = 0 ; i < methodInfo . Count ; i ++, methodIndex ++)
{
lines . Add ( $@"
{method.ReturnInfo.Type.GetTypeName()} {il2cppCallConventionName} __ReversePInvokeMethod_{methodIndex}({paramDeclaringListWithoutMethodInfoStr})
{{
il2cpp::vm::ScopedThreadAttacher _vmThreadHelper;
const MethodInfo* method = InterpreterModule::GetMethodInfoByReversePInvokeWrapperIndex({methodIndex});
{methodTypeDef};
{(method.ReturnInfo.IsVoid ? "" : " return ")}((Callback)(method->methodPointerCallByInterp))({paramNameListWithoutMethodInfoStr});
}}
");
stubCodes . Add ( $"\t{{\" { methodInfo . Signature } \ ", (Il2CppMethodPointer)__ReversePInvokeMethod_{methodIndex}}}," );
}
Debug . Log ( $"[ReversePInvokeWrap.Generator] method:{method.MethodDef} wrapperCount:{methodInfo.Count}" );
}
lines . Add ( @"
const ReversePInvokeMethodData hybridclr::interpreter::g_reversePInvokeMethodStub[]
{
" );
lines . AddRange ( stubCodes );
lines . Add ( @"
{nullptr, nullptr},
};
" );
}
2025-03-31 14:55:24 +08:00
public void Generate ()
{
2025-06-12 18:00:06 +08:00
PrepareMethodBridges ();
2025-03-31 14:55:24 +08:00
CollectTypesAndMethods ();
OptimizationTypesAndMethods ();
GenerateCode ();
}
private void CollectStructDefs ( List < MethodDesc > methods , HashSet < TypeInfo > structTypes )
{
foreach ( var method in methods )
{
foreach ( var paramInfo in method . ParamInfos )
{
if ( paramInfo . Type . IsStruct )
{
structTypes . Add ( paramInfo . Type );
if ( paramInfo . Type . Klass . ContainsGenericParameter )
{
throw new Exception ( $"[CollectStructDefs] method:{method.MethodDef} type:{paramInfo.Type.Klass} contains generic parameter" );
}
}
}
if ( method . ReturnInfo . Type . IsStruct )
{
structTypes . Add ( method . ReturnInfo . Type );
if ( method . ReturnInfo . Type . Klass . ContainsGenericParameter )
{
throw new Exception ( $"[CollectStructDefs] method:{method.MethodDef} type:{method.ReturnInfo.Type.Klass} contains generic parameter" );
}
}
}
}
class FieldInfo
{
public FieldDef field ;
public TypeInfo type ;
}
class ClassInfo
{
public TypeInfo type ;
2025-06-12 18:00:06 +08:00
public List < AnalyzeFieldInfo > fields ;
public uint packingSize ;
public uint classSize ;
public LayoutKind layout ;
public bool blittable ;
2025-03-31 14:55:24 +08:00
}
2025-06-12 18:00:06 +08:00
private void GenerateClassInfo ( TypeInfo type , Dictionary < TypeInfo , ClassInfo > typeSet , List < ClassInfo > classInfos )
2025-03-31 14:55:24 +08:00
{
2025-06-12 18:00:06 +08:00
if ( typeSet . ContainsKey ( type ))
2025-03-31 14:55:24 +08:00
{
return ;
}
2025-06-12 18:00:06 +08:00
AnalyzeTypeInfo ati = CalculateAnalyzeTypeInfoBasic ( type );
//TypeSig typeSig = type.Klass;
//var fields = new List<FieldInfo>();
2025-03-31 14:55:24 +08:00
2025-06-12 18:00:06 +08:00
//TypeDef typeDef = typeSig.ToTypeDefOrRef().ResolveTypeDefThrow();
2025-03-31 14:55:24 +08:00
2025-06-12 18:00:06 +08:00
//List<TypeSig> klassInst = typeSig.ToGenericInstSig()?.GenericArguments?.ToList();
//GenericArgumentContext ctx = klassInst != null ? new GenericArgumentContext(klassInst, null) : null;
//ClassLayout sa = typeDef.ClassLayout;
//ICorLibTypes corLibTypes = typeDef.Module.CorLibTypes;
//bool blittable = true;
//foreach (FieldDef field in typeDef.Fields)
//{
// if (field.IsStatic)
// {
// continue;
// }
// TypeSig fieldType = ctx != null ? MetaUtil.Inflate(field.FieldType, ctx) : field.FieldType;
// fieldType = MetaUtil.ToShareTypeSig(corLibTypes, fieldType);
// var fieldTypeInfo = ToIsomorphicType(GetSharedTypeInfo(fieldType));
// if (fieldTypeInfo.IsStruct)
// {
// GenerateClassInfo(fieldTypeInfo, typeSet, classInfos);
// }
// blittable &= IsBlittable(fieldType, fieldTypeInfo, typeSet);
// fields.Add(new FieldInfo { field = field, type = fieldTypeInfo });
//}
foreach ( var field in ati . fields )
2025-03-31 14:55:24 +08:00
{
2025-06-12 18:00:06 +08:00
if ( field . type . IsStruct )
2025-03-31 14:55:24 +08:00
{
2025-06-12 18:00:06 +08:00
GenerateClassInfo ( field . type , typeSet , classInfos );
2025-03-31 14:55:24 +08:00
}
}
2025-06-12 18:00:06 +08:00
var classInfo = new ClassInfo ()
{
type = type ,
fields = ati . fields ,
packingSize = ati . packingSize ,
classSize = ati . classSize ,
layout = ati . layout ,
blittable = ati . blittable ,
};
typeSet . Add ( type , classInfo );
classInfos . Add ( classInfo );
2025-03-31 14:55:24 +08:00
}
private void GenerateStructDefines ( List < ClassInfo > classInfos , List < string > lines )
{
foreach ( var ci in classInfos )
{
lines . Add ( $"// {ci.type.Klass}" );
2025-06-12 18:00:06 +08:00
uint packingSize = ci . packingSize ;
uint classSize = ci . classSize ;
2025-03-31 14:55:24 +08:00
2025-06-12 18:00:06 +08:00
if ( ci . layout == LayoutKind . Explicit )
2025-03-31 14:55:24 +08:00
{
2025-06-12 18:00:06 +08:00
lines . Add ( $"struct {ci.type.GetTypeName()} {{" );
lines . Add ( "\tunion {" );
2025-03-31 14:55:24 +08:00
if ( classSize > 0 )
{
lines . Add ( $"\tstruct {{ char __fieldSize_offsetPadding[{classSize}];}};" );
}
int index = 0 ;
foreach ( var field in ci . fields )
{
uint offset = field . field . FieldOffset . Value ;
string fieldName = $"__{index}" ;
string commentFieldName = $"{field.field.Name}" ;
lines . Add ( "\t#pragma pack(push, 1)" );
2025-06-12 18:00:06 +08:00
lines . Add ( $"\tstruct {{ {(offset > 0 ? $" char { fieldName } _offsetPadding [{ offset }]; " : "")}{field.type.GetTypeName()} {fieldName};}}; // {commentFieldName}" );
2025-03-31 14:55:24 +08:00
lines . Add ( $"\t#pragma pack(pop)" );
2025-06-12 18:00:06 +08:00
if ( packingSize > 0 )
{
lines . Add ( $"\t#pragma pack(push, {packingSize})" );
}
lines . Add ( $"\tstruct {{ {(offset > 0 ? $" char { fieldName } _offsetPadding_forAlignmentOnly [{ offset }]; " : "")}{field.type.GetTypeName()} {fieldName}_forAlignmentOnly;}}; // {commentFieldName}" );
if ( packingSize > 0 )
{
lines . Add ( $"\t#pragma pack(pop)" );
}
2025-03-31 14:55:24 +08:00
++ index ;
}
2025-06-12 18:00:06 +08:00
lines . Add ( "\t};" );
lines . Add ( "};" );
2025-03-31 14:55:24 +08:00
}
else
{
2025-06-12 18:00:06 +08:00
if ( packingSize != 0 )
{
lines . Add ( $"#pragma pack(push, {packingSize})" );
}
2025-03-31 14:55:24 +08:00
lines . Add ( $"{(classSize > 0 ? " union " : " struct ")} {ci.type.GetTypeName()} {{" );
if ( classSize > 0 )
{
lines . Add ( $"\tstruct {{ char __fieldSize_offsetPadding[{classSize}];}};" );
lines . Add ( "\tstruct {" );
}
int index = 0 ;
foreach ( var field in ci . fields )
{
string fieldName = $"__{index}" ;
string commentFieldName = $"{field.field.Name}" ;
lines . Add ( $"\t{field.type.GetTypeName()} {fieldName}; // {commentFieldName}" );
++ index ;
}
if ( classSize > 0 )
{
lines . Add ( "\t};" );
}
2025-06-12 18:00:06 +08:00
lines . Add ( "};" );
if ( packingSize != 0 )
{
lines . Add ( $"#pragma pack(pop)" );
}
2025-03-31 14:55:24 +08:00
}
}
}
2025-06-12 18:00:06 +08:00
private const string SigOfObj = "u" ;
2025-03-31 14:55:24 +08:00
2025-06-12 18:00:06 +08:00
private static string ToFullName ( TypeSig type )
2025-03-31 14:55:24 +08:00
{
type = type . RemovePinnedAndModifiers ();
switch ( type . ElementType )
{
case ElementType . Void : return "v" ;
case ElementType . Boolean : return "u1" ;
case ElementType . I1 : return "i1" ;
case ElementType . U1 : return "u1" ;
case ElementType . I2 : return "i2" ;
case ElementType . Char :
case ElementType . U2 : return "u2" ;
case ElementType . I4 : return "i4" ;
case ElementType . U4 : return "u4" ;
case ElementType . I8 : return "i8" ;
case ElementType . U8 : return "u8" ;
case ElementType . R4 : return "r4" ;
case ElementType . R8 : return "r8" ;
case ElementType . I : return "i" ;
case ElementType . U :
case ElementType . String :
case ElementType . Ptr :
case ElementType . ByRef :
case ElementType . Class :
case ElementType . Array :
case ElementType . SZArray :
case ElementType . FnPtr :
case ElementType . Object :
return SigOfObj ;
case ElementType . Module :
case ElementType . Var :
case ElementType . MVar :
throw new NotSupportedException ( $"ToFullName type:{type}" );
case ElementType . TypedByRef : return TypeInfo . strTypedByRef ;
case ElementType . ValueType :
{
TypeDef typeDef = type . ToTypeDefOrRef (). ResolveTypeDef ();
if ( typeDef == null )
{
throw new Exception ( $"type:{type} definition could not be found. Please try `HybridCLR/Genergate/LinkXml`, then Build once to generate the AOT dll, and then regenerate the bridge function" );
}
if ( typeDef . IsEnum )
{
return ToFullName ( typeDef . GetEnumUnderlyingType ());
}
return ToValueTypeFullName (( ClassOrValueTypeSig ) type );
}
case ElementType . GenericInst :
{
GenericInstSig gis = ( GenericInstSig ) type ;
if (! gis . GenericType . IsValueType )
{
return SigOfObj ;
}
TypeDef typeDef = gis . GenericType . ToTypeDefOrRef (). ResolveTypeDef ();
if ( typeDef . IsEnum )
{
return ToFullName ( typeDef . GetEnumUnderlyingType ());
}
return $"{ToValueTypeFullName(gis.GenericType)}<{string.Join(" , ", gis.GenericArguments.Select(a => ToFullName(a)))}>" ;
}
default : throw new NotSupportedException ( $"{type.ElementType}" );
}
}
private static bool IsSystemOrUnityAssembly ( ModuleDef module )
{
if ( module . IsCoreLibraryModule == true )
{
return true ;
}
string assName = module . Assembly . Name . String ;
return assName . StartsWith ( "System." ) || assName . StartsWith ( "UnityEngine." );
}
private static string ToValueTypeFullName ( ClassOrValueTypeSig type )
{
TypeDef typeDef = type . ToTypeDefOrRef (). ResolveTypeDef ();
if ( typeDef == null )
{
throw new Exception ( $"type:{type} resolve fail" );
}
if ( typeDef . DeclaringType != null )
{
return $"{ToValueTypeFullName((ClassOrValueTypeSig)typeDef.DeclaringType.ToTypeSig())}/{typeDef.Name}" ;
}
if ( IsSystemOrUnityAssembly ( typeDef . Module ))
{
return type . FullName ;
}
return $"{Path.GetFileNameWithoutExtension(typeDef.Module.Name)}:{typeDef.FullName}" ;
}
2025-06-12 18:00:06 +08:00
private void GenerateStructureSignatureStub ( List < TypeInfo > types , List < string > lines )
2025-03-31 14:55:24 +08:00
{
2025-06-12 18:00:06 +08:00
lines . Add ( "const FullName2Signature hybridclr::interpreter::g_fullName2SignatureStub[] = {" );
2025-03-31 14:55:24 +08:00
foreach ( var type in types )
{
TypeInfo isoType = ToIsomorphicType ( type );
lines . Add ( $"\t{{\" { ToFullName ( type . Klass )} \ ", \"{isoType.CreateSigName()}\"}}," );
}
lines . Add ( "\t{ nullptr, nullptr}," );
lines . Add ( "};" );
}
2025-06-12 18:00:06 +08:00
private void GenerateManaged2NativeStub ( List < MethodDesc > methods , List < string > lines )
2025-03-31 14:55:24 +08:00
{
lines . Add ( $@"
2025-06-12 18:00:06 +08:00
const Managed2NativeMethodInfo hybridclr::interpreter::g_managed2nativeStub[] =
2025-03-31 14:55:24 +08:00
{{
" );
foreach ( var method in methods )
{
lines . Add ( $"\t{{\" { method . CreateInvokeSigName ()} \ ", __M2N_{method.CreateInvokeSigName()}}}," );
}
lines . Add ( $"\t{{nullptr, nullptr}}," );
lines . Add ( "};" );
}
2025-06-12 18:00:06 +08:00
private void GenerateNative2ManagedStub ( List < MethodDesc > methods , List < string > lines )
2025-03-31 14:55:24 +08:00
{
lines . Add ( $@"
2025-06-12 18:00:06 +08:00
const Native2ManagedMethodInfo hybridclr::interpreter::g_native2managedStub[] =
2025-03-31 14:55:24 +08:00
{{
" );
foreach ( var method in methods )
{
lines . Add ( $"\t{{\" { method . CreateInvokeSigName ()} \ ", (Il2CppMethodPointer)__N2M_{method.CreateInvokeSigName()}}}," );
}
lines . Add ( $"\t{{nullptr, nullptr}}," );
lines . Add ( "};" );
}
2025-06-12 18:00:06 +08:00
private void GenerateAdjustThunkStub ( List < MethodDesc > methods , List < string > lines )
2025-03-31 14:55:24 +08:00
{
lines . Add ( $@"
2025-06-12 18:00:06 +08:00
const NativeAdjustThunkMethodInfo hybridclr::interpreter::g_adjustThunkStub[] =
2025-03-31 14:55:24 +08:00
{{
" );
foreach ( var method in methods )
{
lines . Add ( $"\t{{\" { method . CreateInvokeSigName ()} \ ", (Il2CppMethodPointer)__N2M_AdjustorThunk_{method.CreateCallSigName()}}}," );
}
lines . Add ( $"\t{{nullptr, nullptr}}," );
lines . Add ( "};" );
}
private string GetManaged2NativePassParam ( TypeInfo type , string varName )
{
return $"M2NFromValueOrAddress<{type.GetTypeName()}>({varName})" ;
}
private string GetNative2ManagedPassParam ( TypeInfo type , string varName )
{
return type . NeedExpandValue () ? $"(uint64_t)({varName})" : $"N2MAsUint64ValueOrAddress<{type.GetTypeName()}>({varName})" ;
}
2025-06-12 18:00:06 +08:00
private void GenerateManaged2NativeMethod ( MethodDesc method , List < string > lines )
2025-03-31 14:55:24 +08:00
{
string paramListStr = string . Join ( ", " , method . ParamInfos . Select ( p => $"{p.Type.GetTypeName()} __arg{p.Index}" ). Concat ( new string [] { "const MethodInfo* method" }));
string paramNameListStr = string . Join ( ", " , method . ParamInfos . Select ( p => GetManaged2NativePassParam ( p . Type , $"localVarBase+argVarIndexs[{p.Index}]" )). Concat ( new string [] { "method" }));
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)(method->methodPointerCallByInterp))({paramNameListStr});
}}
");
}
2025-06-12 18:00:06 +08:00
private string GenerateArgumentSizeAndOffset ( List < ParamInfo > paramInfos )
2025-03-31 14:55:24 +08:00
{
StringBuilder s = new StringBuilder ();
int index = 0 ;
foreach ( var param in paramInfos )
{
s . AppendLine ( $"\tconstexpr int __ARG_OFFSET_{index}__ = {(index > 0 ? $" __ARG_OFFSET_ { index - 1 } __ + __ARG_SIZE_ { index - 1 } __ " : " 0 ")};" );
s . AppendLine ( $"\tconstexpr int __ARG_SIZE_{index}__ = (sizeof(__arg{index}) + 7)/8;" );
index ++;
}
s . AppendLine ( $"\tconstexpr int __TOTAL_ARG_SIZE__ = {(paramInfos.Count > 0 ? $" __ARG_OFFSET_ { index - 1 } __ + __ARG_SIZE_ { index - 1 } __ " : " 1 ")};" );
return s . ToString ();
}
2025-06-12 18:00:06 +08:00
private string GenerateCopyArgumentToInterpreterStack ( List < ParamInfo > paramInfos )
2025-03-31 14:55:24 +08:00
{
StringBuilder s = new StringBuilder ();
int index = 0 ;
foreach ( var param in paramInfos )
{
if ( param . Type . IsPrimitiveType )
{
if ( param . Type . NeedExpandValue ())
{
s . AppendLine ( $"\targs[__ARG_OFFSET_{index}__].u64 = __arg{index};" );
}
else
{
s . AppendLine ( $"\t*({param.Type.GetTypeName()}*)(args + __ARG_OFFSET_{index}__) = __arg{index};" );
}
}
else
{
s . AppendLine ( $"\t*({param.Type.GetTypeName()}*)(args + __ARG_OFFSET_{index}__) = __arg{index};" );
}
index ++;
}
return s . ToString ();
}
private void GenerateNative2ManagedMethod0 ( MethodDesc method , bool adjustorThunk , List < string > lines )
{
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 ? " AdjustorThunk_ " : "")}{method.CreateCallSigName()}({paramListStr})
{{
{( adjustorThunk ? "__arg0 += sizeof(Il2CppObject);" : "" )}
{ GenerateArgumentSizeAndOffset ( method . ParamInfos )}
StackObject args [ __TOTAL_ARG_SIZE__ ];
{ GenerateCopyArgumentToInterpreterStack ( method . ParamInfos )}
{( method . ReturnInfo . IsVoid ? "Interpreter::Execute(method, args, nullptr);" : $"{method.ReturnInfo.Type.GetTypeName()} ret; Interpreter::Execute(method, args, &ret); return ret;" )}
}}
");
}
2025-06-12 18:00:06 +08:00
private void GenerateNative2ManagedMethod ( MethodDesc method , List < string > lines )
2025-03-31 14:55:24 +08:00
{
GenerateNative2ManagedMethod0 ( method , false , lines );
}
2025-06-12 18:00:06 +08:00
private void GenerateAdjustThunkMethod ( MethodDesc method , List < string > lines )
2025-03-31 14:55:24 +08:00
{
GenerateNative2ManagedMethod0 ( method , true , lines );
}
2025-06-12 18:00:06 +08:00
private void GenerateManaged2NativeFunctionPointerMethod ( CalliMethodInfo methodInfo , List < string > lines )
{
MethodDesc method = methodInfo . Method ;
string paramListStr = string . Join ( ", " , method . ParamInfos . Select ( p => $"{p.Type.GetTypeName()} __arg{p.Index}" ));
string paramNameListStr = string . Join ( ", " , method . ParamInfos . Select ( p => GetManaged2NativePassParam ( p . Type , $"localVarBase+argVarIndexs[{p.Index}]" )));
string il2cppCallConventionName = GetIl2cppCallConventionName ( methodInfo . Callvention );
lines . Add ( $@"
static void __M2NF_{methodInfo.Signature}(Il2CppMethodPointer methodPointer, uint16_t* argVarIndexs, StackObject* localVarBase, void* ret)
{{
typedef {method.ReturnInfo.Type.GetTypeName()} ({il2cppCallConventionName} *NativeMethod)({paramListStr});
{(!method.ReturnInfo.IsVoid ? $" *({ method . ReturnInfo . Type . GetTypeName ()}*) ret = " : "")}((NativeMethod)(methodPointer))({paramNameListStr});
}}
");
}
private void GenerateManaged2NativeFunctionPointerMethodStub ( List < CalliMethodInfo > calliMethodSignatures , List < string > lines )
{
lines . Add ( @"
const Managed2NativeFunctionPointerCallData hybridclr::interpreter::g_managed2NativeFunctionPointerCallStub[]
{
" );
foreach ( var method in calliMethodSignatures )
{
lines . Add ( $"\t{{\" { method . Signature } \ ", __M2NF_{method.Signature}}}," );
}
lines . Add ( @"
{nullptr, nullptr},
};
" );
}
2025-03-31 14:55:24 +08:00
}
}