public MethodSignature(Il2CppSystem.Reflection.MethodInfo methodInfo, bool hasThis)
 {
     HasThis               = hasThis;
     myReturnType          = methodInfo.ReturnType.IsValueType ? methodInfo.ReturnType._impl.value : IntPtr.Zero;
     myParameterTypes      = methodInfo.GetParameters().Select(it => it.ParameterType.IsValueType ? it.ParameterType._impl.value : IntPtr.Zero).ToArray();
     ConstructedFromNative = true;
 }
        private static Delegate GenerateNativeToManagedTrampoline(Il2CppSystem.Reflection.MethodInfo nativeMethod,
                                                                  MethodInfo managedMethod, MethodSignature signature)
        {
            var returnType = nativeMethod.ReturnType.IsValueType
                ? managedMethod.ReturnType
                : typeof(IntPtr);

            var managedParameters = managedMethod.GetParameters();
            var nativeParameters  = nativeMethod.GetParameters();
            var parameterTypes    = new Type[managedParameters.Length + 1 + 1]; // thisptr for target, methodInfo last arg

            parameterTypes[0] = typeof(IntPtr);
            parameterTypes[managedParameters.Length + 1] = typeof(Il2CppMethodInfo *);
            for (var i = 0; i < managedParameters.Length; i++)
            {
                parameterTypes[i + 1] = nativeParameters[i].ParameterType.IsValueType
                    ? managedParameters[i].ParameterType
                    : typeof(IntPtr);
            }

            var trampoline  = new DynamicMethod("(il2cpp delegate trampoline) " + ExtractSignature(managedMethod), MethodAttributes.Static, CallingConventions.Standard, returnType, parameterTypes, typeof(DelegateSupport), true);
            var bodyBuilder = trampoline.GetILGenerator();

            var tryLabel = bodyBuilder.BeginExceptionBlock();

            bodyBuilder.Emit(OpCodes.Ldarg_0);
            bodyBuilder.Emit(OpCodes.Call, typeof(ClassInjectorBase).GetMethod(nameof(ClassInjectorBase.GetMonoObjectFromIl2CppPointer)) !);
            bodyBuilder.Emit(OpCodes.Castclass, typeof(Il2CppToMonoDelegateReference));
            bodyBuilder.Emit(OpCodes.Ldfld, typeof(Il2CppToMonoDelegateReference).GetField(nameof(Il2CppToMonoDelegateReference.ReferencedDelegate)));

            for (var i = 0; i < managedParameters.Length; i++)
            {
                var parameterType = managedParameters[i].ParameterType;

                bodyBuilder.Emit(OpCodes.Ldarg, i + 1);
                if (parameterType == typeof(string))
                {
                    bodyBuilder.Emit(OpCodes.Call, typeof(IL2CPP).GetMethod(nameof(IL2CPP.Il2CppStringToManaged)) !);
                }
                else if (!parameterType.IsValueType)
                {
                    var labelNull = bodyBuilder.DefineLabel();
                    var labelDone = bodyBuilder.DefineLabel();
                    bodyBuilder.Emit(OpCodes.Brfalse, labelNull);
                    bodyBuilder.Emit(OpCodes.Ldarg, i + 1);
                    bodyBuilder.Emit(OpCodes.Newobj, parameterType.GetConstructor(new[] { typeof(IntPtr) }) !);
                    bodyBuilder.Emit(OpCodes.Br, labelDone);
                    bodyBuilder.MarkLabel(labelNull);
                    bodyBuilder.Emit(OpCodes.Ldnull);
                    bodyBuilder.MarkLabel(labelDone);
                }
            }

            bodyBuilder.Emit(OpCodes.Call, managedMethod);

            if (returnType == typeof(string))
            {
                bodyBuilder.Emit(OpCodes.Call, typeof(IL2CPP).GetMethod(nameof(IL2CPP.ManagedStringToIl2Cpp)) !);
            }
            else if (!returnType.IsValueType)
            {
                var labelNull = bodyBuilder.DefineLabel();
                var labelDone = bodyBuilder.DefineLabel();
                bodyBuilder.Emit(OpCodes.Dup);
                bodyBuilder.Emit(OpCodes.Brfalse, labelNull);
                bodyBuilder.Emit(OpCodes.Call, typeof(Il2CppObjectBase).GetProperty(nameof(Il2CppObjectBase.Pointer)) !.GetMethod);
                bodyBuilder.Emit(OpCodes.Br, labelDone);
                bodyBuilder.MarkLabel(labelNull);
                bodyBuilder.Emit(OpCodes.Pop);
                bodyBuilder.Emit(OpCodes.Ldc_I4_0);
                bodyBuilder.Emit(OpCodes.Conv_I);
                bodyBuilder.MarkLabel(labelDone);
            }

            var exceptionLocal = bodyBuilder.DeclareLocal(typeof(Exception));

            bodyBuilder.BeginCatchBlock(typeof(Exception));
            bodyBuilder.Emit(OpCodes.Stloc, exceptionLocal);
            bodyBuilder.Emit(OpCodes.Ldstr, "Exception in IL2CPP-to-Managed trampoline, not passing it to il2cpp: ");
            bodyBuilder.Emit(OpCodes.Ldloc, exceptionLocal);
            bodyBuilder.Emit(OpCodes.Callvirt, typeof(object).GetMethod(nameof(ToString)) !);
            bodyBuilder.Emit(OpCodes.Call, typeof(string).GetMethod(nameof(string.Concat), new [] { typeof(string), typeof(string) }) !);
            bodyBuilder.Emit(OpCodes.Call, typeof(LogSupport).GetMethod(nameof(LogSupport.Error)) !);

            bodyBuilder.EndExceptionBlock();

            bodyBuilder.Emit(OpCodes.Ret);

            return(trampoline.CreateDelegate(GetOrCreateDelegateType(signature, managedMethod)));
        }
 private static Delegate GetOrCreateNativeToManagedTrampoline(MethodSignature signature, Il2CppSystem.Reflection.MethodInfo nativeMethod, MethodInfo managedMethod)
 {
     return(NativeToManagedTrampolines.GetOrAdd(managedMethod,
                                                (_, tuple) => GenerateNativeToManagedTrampoline(tuple.nativeMethod, tuple.managedMethod, tuple.signature), (nativeMethod, managedMethod, signature)));
 }