/// <summary> /// Defines a proxy method that is called from Objective-C runtime. This method retrieves the targeted managed instance and passes the parameters. /// </summary> private MethodBuilder DefineProxyMethod (TypeBuilder typeBuilder, MethodTuple methodTuple) { // Get info about the target method Type returnType = GetReturnType (methodTuple.MethodInfo); Type[] parameterTypes = TypeHelper.GetParameterTypes (methodTuple.MethodInfo); // The first argument of the extension method is the target type // TODO: Refactor Type targetType = parameterTypes [0]; // Remove first parameter of the extension method // TODO: Refactor parameterTypes = ArrayHelper.TrimLeft (parameterTypes, 1); Type nativeReturnType = TypeHelper.GetNativeType (returnType, this.Is64Bits); Type[] nativeParameterTypes = TypeHelper.GetNativeParameterTypes (parameterTypes, this.Is64Bits); // Create the array of parameters for the proxy method Type[] signatureNativeParameterTypes = ArrayHelper.Prepend (nativeParameterTypes, typeof(IntPtr), typeof(IntPtr)); // Create a unique proxy method name String name = GetUniqueName (methodTuple.MethodInfo); // Create a proxy method MethodBuilder methodBuilder = typeBuilder.DefineMethod (name, EmitConstants.PUBLIC_METHOD_STATIC, nativeReturnType, signatureNativeParameterTypes); // Give name to parameters methodBuilder.DefineParameter (1, ParameterAttributes.None, "receiver"); methodBuilder.DefineParameter (2, ParameterAttributes.None, "selector"); String[] parameterNames = TypeHelper.GetParameterNames (methodTuple.MethodInfo); // Remove first parameter of the extension method // TODO: Refactor parameterNames = ArrayHelper.TrimLeft (parameterNames, 1); for (int i = 0; i < parameterNames.Length; i++) { if (!String.IsNullOrEmpty (parameterNames [i])) { methodBuilder.DefineParameter (i + 3, ParameterAttributes.None, parameterNames [i]); } } // Generates body ILGenerator generator = methodBuilder.GetILGenerator (); // Emit the body this.EmitProxyMethodBodyForExtensionMethod (generator, methodTuple, targetType, returnType, nativeReturnType, parameterTypes, nativeParameterTypes); // Return generator.Emit (OpCodes.Ret); return methodBuilder; }
/// <summary> /// Defines a proxy method that is called from Objective-C runtime. This method retrieves the targeted managed instance and passes the parameters. /// </summary> private MethodBuilder DefineProxyMethod (TypeBuilder typeBuilder, MethodTuple methodTuple) { // Get info about the target method Type returnType = GetReturnType (methodTuple.MethodInfo); Type[] parameterTypes = TypeHelper.GetParameterTypes (methodTuple.MethodInfo); Type nativeReturnType = TypeHelper.GetNativeType (returnType, this.Is64Bits); Type[] nativeParameterTypes = TypeHelper.GetNativeParameterTypes (parameterTypes, this.Is64Bits); // Create the array of parameters for the proxy method Type[] signatureNativeParameterTypes = ArrayHelper.Prepend (nativeParameterTypes, typeof(IntPtr), typeof(IntPtr)); // Create a unique proxy method name String name = GetUniqueName (methodTuple.MethodInfo); // Create a proxy method MethodBuilder methodBuilder = typeBuilder.DefineMethod (name, EmitConstants.PUBLIC_METHOD_STATIC, nativeReturnType, signatureNativeParameterTypes); // Give name to parameters methodBuilder.DefineParameter (1, ParameterAttributes.None, "receiver"); methodBuilder.DefineParameter (2, ParameterAttributes.None, "selector"); String[] parameterNames = TypeHelper.GetParameterNames (methodTuple.MethodInfo); for (int i = 0; i < parameterNames.Length; i++) { if (!String.IsNullOrEmpty (parameterNames [i])) { methodBuilder.DefineParameter (i + 3, ParameterAttributes.None, parameterNames [i]); } } // Generates body ILGenerator generator = methodBuilder.GetILGenerator (); // We handle different behaviours: // - Static Method // - Instance Method if (methodTuple.MethodInfo.IsStatic) { this.EmitProxyMethodBodyForStaticMethod (generator, methodTuple, returnType, nativeReturnType, parameterTypes, nativeParameterTypes); } else { this.EmitProxyMethodBodyForInstanceMethod (generator, methodTuple, returnType, nativeReturnType, parameterTypes, nativeParameterTypes); } // Return generator.Emit (OpCodes.Ret); return methodBuilder; }
/// <summary> /// Collect every public static method with an attribute. /// </summary> internal static MethodTuple[] CollectStaticMethods (Type type) { List<MethodTuple> tuples = new List<MethodTuple> (); MethodInfo[] methodInfos = type.GetMethods (BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly); Array.ForEach (methodInfos, methodInfo => { ObjectiveCMessageAttribute attribute = (ObjectiveCMessageAttribute)Attribute.GetCustomAttribute (methodInfo, typeof(ObjectiveCMessageAttribute)); if (attribute == null) { return; } MethodTuple methodTuple = new MethodTuple (); methodTuple.MethodInfo = methodInfo; methodTuple.Selector = String.IsNullOrEmpty (attribute.Selector) ? ObjectiveCEncoding.GetSelector (methodInfo) : attribute.Selector; tuples.Add (methodTuple); }); return tuples.ToArray (); }
/// <summary> /// Defines the proxy delegate field info. /// </summary> /// <param name = "typeBuilder">The type builder.</param> /// <param name = "methodTuple">The method tuple.</param> internal static FieldInfo DefineProxyDelegateFieldInfo (TypeBuilder typeBuilder, MethodTuple methodTuple) { // Create a unique delegate name String name = GetUniqueName (methodTuple.MethodInfo) + "_Delegate"; // TODO: Const return EmitHelper.DefineField (typeBuilder, name, methodTuple.ProxyDelegate, true); }
private void EmitProxyMethodBodyForExtensionMethod (ILGenerator generator, MethodTuple methodTuple, Type targetType, Type returnType, Type nativeReturnType, Type[] parameterTypes, Type[] nativeParameterTypes) { bool isNotVoid = (returnType != typeof(void)); // Creates local variables for by-ref parameters ByRefParameter[] byRefLocalVariables = CreateLocalVariableForByRefParameters (generator, methodTuple.MethodInfo.GetParameters ()); bool hasByRef = byRefLocalVariables.Any (p => p.LocalBuilder != null && !p.IsOut); // To store result before return LocalBuilder result = (isNotVoid && hasByRef) ? CreateLocalBuilderForInvocationResult(generator, returnType, nativeReturnType) : null; // For by-ref parameters passed as reference (without [out] attribute), we first set the value of local variables this.EmitNativeToManagedMarshallingForByRefParameters (generator, nativeParameterTypes, byRefLocalVariables); // The target type is the type for which the extension method is declared generator.Emit (OpCodes.Ldarg_0); MethodInfo wrapInstance = EmitInfos.OBJECTIVECRUNTIME_GETINSTANCE.MakeGenericMethod (new[] {targetType}); generator.Emit (OpCodes.Call, wrapInstance); // Loads the parameters on the stack. // - For regular parameter, values are directly loaded on the stack // - For by-ref parameters, local variables are loaded instead. EmitParametersLoadingOnStack (generator, parameterTypes, nativeParameterTypes, byRefLocalVariables, 2); // Make the call on the receiver (direct call as the method is static) generator.Emit (OpCodes.Call, methodTuple.MethodInfo); // Unwrap result if needed if (isNotVoid) { UnwrapResultOfInvocation(generator, result, returnType, nativeReturnType, hasByRef); } // Marshal by-ref local variables to their corresponding parameters this.EmitManagedToNativeMarshallingForByRefParameters (generator, nativeParameterTypes, byRefLocalVariables); if (isNotVoid && hasByRef) { // Load the result on the stack generator.Emit (OpCodes.Ldloc, result); } }