예제 #1
0
        private static void UnwindArguments(MethodInfo targetMethod,
                                            MethodDebugging generator, LocalBuilder argumentValues, bool isBeforeCall)
        {
            if (targetMethod.GetParameters().Length > 0)
            {
                for (var argLoad = 0; argLoad < targetMethod.GetParameters().Length; argLoad++)
                {
                    var parameter     = targetMethod.GetParameters()[argLoad];
                    var parameterType = parameter.ParameterType;

                    if (isBeforeCall || parameterType.IsByRef)
                    {
                        if (parameterType.IsByRef)
                        {
                            generator.Emit(OpCodes.Ldarg, argLoad + 1);
                        }

                        generator.Emit(OpCodes.Ldloc, argumentValues);
                        generator.Emit(OpCodes.Ldc_I4, argLoad);
                        generator.Emit(OpCodes.Ldelem_Ref);

                        // This code is odd. By-ref generic parameters are not reported as generic,
                        // so that's why the FullName null check is done.
                        // Also, the Unbox_Any won't work with by-ref generic arguments,
                        // so the generic type has to be found within the generic arguments array
                        // off of the target method.
                        if (parameterType.IsGenericParameter || parameterType.FullName == null)
                        {
                            if (parameterType.IsByRef)
                            {
                                parameterType = parameterType.GetElementType();
                                generator.Emit(OpCodes.Unbox_Any, parameterType);
                                generator.Emit(OpCodes.Stobj, parameterType);
                            }
                            else
                            {
                                generator.Emit(OpCodes.Unbox_Any, parameterType);
                                generator.Emit(OpCodes.Starg, argLoad + 1);
                            }
                        }
                        else
                        {
                            if (parameterType.IsValueType ||
                                (parameterType.HasElementType && parameterType.GetElementType().IsValueType))
                            {
                                if (parameterType.IsByRef)
                                {
                                    parameterType = parameterType.GetElementType();
                                    generator.Emit(OpCodes.Unbox_Any, parameterType);

                                    var indirectCode = ProxyMethodBuilder.GetIndCode(parameterType, false);

                                    if (indirectCode == OpCodes.Stobj)
                                    {
                                        generator.Emit(indirectCode, parameterType);
                                    }
                                    else
                                    {
                                        generator.Emit(indirectCode);
                                    }
                                }
                                else
                                {
                                    generator.Emit(OpCodes.Unbox_Any, parameterType);
                                    generator.Emit(OpCodes.Starg, argLoad + 1);
                                }
                            }
                            else
                            {
                                if (parameterType.IsByRef)
                                {
                                    parameterType = parameterType.GetElementType();
                                    generator.Emit(OpCodes.Castclass, parameterType);
                                    generator.Emit(OpCodes.Stind_Ref);
                                }
                                else
                                {
                                    generator.Emit(OpCodes.Castclass, parameterType);
                                    generator.Emit(OpCodes.Starg, argLoad + 1);
                                }
                            }
                        }
                    }
                }
            }
        }
예제 #2
0
        private static void WindArguments(MethodInfo targetMethod,
                                          MethodDebugging generator, LocalBuilder argumentValues, bool isBeforeCall)
        {
            //  Set up the arg array
            if (targetMethod.GetParameters().Length > 0)
            {
                for (int argLoad = 0; argLoad < targetMethod.GetParameters().Length; argLoad++)
                {
                    var parameter     = targetMethod.GetParameters()[argLoad];
                    var parameterType = parameter.ParameterType;

                    if (isBeforeCall || parameterType.IsByRef)
                    {
                        generator.Emit(OpCodes.Ldloc, argumentValues);
                        generator.Emit(OpCodes.Ldc_I4, argLoad);
                        generator.Emit(OpCodes.Ldarg, argLoad + 1);

                        if (parameterType.IsGenericParameter || parameterType.FullName == null)
                        {
                            if (parameterType.IsByRef)
                            {
                                parameterType = parameterType.GetElementType();
                                generator.Emit(OpCodes.Ldobj, parameterType);
                                generator.Emit(OpCodes.Box, parameterType);
                            }
                            else
                            {
                                generator.Emit(OpCodes.Box, parameterType);
                            }
                        }
                        else if (parameterType.IsValueType ||
                                 (parameterType.HasElementType && parameterType.GetElementType().IsValueType))
                        {
                            if (parameterType.IsByRef)
                            {
                                parameterType = parameterType.GetElementType();

                                var indirectCode = ProxyMethodBuilder.GetIndCode(parameterType, true);

                                if (indirectCode == OpCodes.Ldobj)
                                {
                                    generator.Emit(indirectCode, parameterType);
                                }
                                else
                                {
                                    generator.Emit(indirectCode);
                                }
                            }

                            generator.Emit(OpCodes.Box, parameterType);
                        }
                        else
                        {
                            if (parameterType.IsByRef)
                            {
                                generator.Emit(OpCodes.Ldind_Ref);
                            }
                        }

                        generator.Emit(OpCodes.Stelem_Ref);
                    }
                }
            }
        }
예제 #3
0
        private static void BuildTargetMethods(TypeBuilder proxyBuilder, MethodBuilder onBeforeMethodInvocation,
                                               MethodBuilder onAfterMethodInvocation, Type targetType,
                                               FieldBuilder wrappedObject, Dictionary <MethodInfo, MethodMappings> targets, TypeDebugging debug)
        {
            var methodAttribs = MethodAttributes.HideBySig |
                                MethodAttributes.Virtual | MethodAttributes.Private;

            foreach (var target in targets)
            {
                var targetMethod = target.Key;
                var arguments    = new Type[targetMethod.GetParameters().Length];

                for (int i = 0; i < targetMethod.GetParameters().Length; i++)
                {
                    arguments[i] = targetMethod.GetParameters()[i].ParameterType;
                }

                var method = proxyBuilder.DefineMethod(
                    targetMethod.Name + Proxy.ProxyExtension, methodAttribs, targetMethod.ReturnType, arguments);

                ProxyMethodBuilder.HandleGenericMethodArguments(targetMethod, method);

                //  Determine if this method should override
                //  the mapped method (OverridesInterfaceMethods == false)
                //  or a number of itf. methods (OverridesInterfaceMethods == true)
                var mappings = target.Value;

                if (!mappings.OverridesInterfaceMethods)
                {
                    proxyBuilder.DefineMethodOverride(method, targetMethod);
                }
                else
                {
                    for (int itfs = 0; itfs < mappings.MappedMethods.Count; itfs++)
                    {
                        proxyBuilder.DefineMethodOverride(method, mappings.MappedMethods[itfs]);
                    }
                }

                using (var generator = debug.GetMethodDebugging(method))
                {
                    var argumentValues = generator.DeclareLocal(typeof(object[]));
                    var callMethod     = generator.DeclareLocal(typeof(bool));
                    generator.DeclareLocal(typeof(Type));
                    var          generatedException = generator.DeclareLocal(typeof(Exception));
                    LocalBuilder returnValue        = null;
                    var          wrappedReturnValue = generator.DeclareLocal(typeof(object));
                    var          baseMethod         = generator.DeclareLocal(typeof(MethodBase));

                    var endCall = generator.DefineLabel();

                    //  Check for a return value.
                    if (targetMethod.ReturnType != typeof(void))
                    {
                        returnValue = generator.DeclareLocal(targetMethod.ReturnType);
                    }

                    generator.Emit(OpCodes.Ldnull);
                    generator.Emit(OpCodes.Stloc, generatedException);

                    generator.Emit(OpCodes.Ldc_I4, targetMethod.GetParameters().Length);
                    generator.Emit(OpCodes.Newarr, typeof(object));
                    generator.Emit(OpCodes.Stloc, argumentValues);

                    // Get the target method.
                    generator.Emit(OpCodes.Ldtoken, targetMethod);

                    if (targetType.IsGenericType)
                    {
                        generator.Emit(OpCodes.Ldtoken, targetType);
                        generator.Emit(OpCodes.Call,
                                       typeof(MethodBase).GetMethod(GetMethodFromHandleMethod,
                                                                    new Type[] { typeof(RuntimeMethodHandle), typeof(RuntimeTypeHandle) }));
                    }
                    else
                    {
                        generator.Emit(OpCodes.Call,
                                       typeof(MethodBase).GetMethod(GetMethodFromHandleMethod,
                                                                    new Type[] { typeof(RuntimeMethodHandle) }));
                    }

                    generator.Emit(OpCodes.Stloc, baseMethod);

                    // call OnBeforeMethodInvocation.
                    ProxyMethodBuilder.WindArguments(targetMethod, generator, argumentValues, true);
                    generator.Emit(OpCodes.Ldarg_0);
                    generator.Emit(OpCodes.Ldloc, baseMethod);
                    generator.Emit(OpCodes.Ldloc, argumentValues);
                    generator.Emit(OpCodes.Call, onBeforeMethodInvocation);
                    generator.Emit(OpCodes.Stloc, callMethod);
                    ProxyMethodBuilder.UnwindArguments(targetMethod, generator, argumentValues, true);

                    // If the call should be cancelled, break to the end.
                    generator.Emit(OpCodes.Ldloc, callMethod);
                    generator.Emit(OpCodes.Brfalse, endCall);

                    // Call the real method.
                    generator.BeginExceptionBlock();
                    generator.Emit(OpCodes.Ldarg_0);
                    generator.Emit(OpCodes.Ldfld, wrappedObject);

                    for (var argLoad = 0; argLoad < targetMethod.GetParameters().Length; argLoad++)
                    {
                        generator.Emit(OpCodes.Ldarg, argLoad + 1);
                    }

                    generator.Emit(OpCodes.Callvirt, targetMethod);

                    if (targetMethod.ReturnType != typeof(void))
                    {
                        generator.Emit(OpCodes.Stloc, returnValue);
                    }

                    // call OnAfterInvocation
                    ProxyMethodBuilder.WindArguments(targetMethod, generator, argumentValues, false);
                    generator.Emit(OpCodes.Ldarg_0);
                    generator.Emit(OpCodes.Ldloc, baseMethod);
                    generator.Emit(OpCodes.Ldloc, argumentValues);
                    ProxyMethodBuilder.WrapReturnValue(targetMethod, generator, returnValue, wrappedReturnValue);
                    generator.Emit(OpCodes.Ldloc, generatedException);
                    generator.Emit(OpCodes.Call, onAfterMethodInvocation);
                    ProxyMethodBuilder.UnwrapReturnValue(targetMethod, generator, returnValue, wrappedReturnValue);
                    ProxyMethodBuilder.UnwindArguments(targetMethod, generator, argumentValues, false);

                    generator.BeginCatchBlock(typeof(Exception));
                    // call OnAfterInvocationWithException
                    generator.Emit(OpCodes.Stloc, generatedException);
                    ProxyMethodBuilder.WindArguments(targetMethod, generator, argumentValues, false);
                    generator.Emit(OpCodes.Ldarg_0);
                    generator.Emit(OpCodes.Ldloc, baseMethod);
                    generator.Emit(OpCodes.Ldloc, argumentValues);
                    ProxyMethodBuilder.WrapReturnValue(targetMethod, generator, returnValue, wrappedReturnValue);
                    generator.Emit(OpCodes.Ldloc, generatedException);
                    generator.Emit(OpCodes.Call, onAfterMethodInvocation);
                    ProxyMethodBuilder.UnwrapReturnValue(targetMethod, generator, returnValue, wrappedReturnValue);
                    ProxyMethodBuilder.UnwindArguments(targetMethod, generator, argumentValues, false);
                    generator.EndExceptionBlock();
                    generator.MarkLabel(endCall);

                    //  Finally...return.
                    if (targetMethod.ReturnType != typeof(void))
                    {
                        generator.Emit(OpCodes.Ldloc, returnValue);
                    }

                    generator.Emit(OpCodes.Ret);
                }
            }
        }