Holds the definition of a method (Mix of .NET/Objective-C).
		/// <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;
		}
Exemple #3
0
		/// <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);
			}
		}