/// <inheritdoc />
        public bool RemoveInterceptor(MethodInfo method, IInterceptor interceptor)
        {
            if (method == null)
            {
                throw new ArgumentNullException(@"method");
            }
            if (interceptor == null)
            {
                throw new ArgumentNullException(@"interceptor");
            }

            return(StaticInterceptorStub.RemoveInterceptor(method, interceptor));
        }
        /// <inheritdoc />
        public void AddInterceptor(MethodInfo method, IInterceptor interceptor)
        {
            if (method == null)
            {
                throw new ArgumentNullException(@"method");
            }
            if (interceptor == null)
            {
                throw new ArgumentNullException(@"interceptor");
            }

            StaticInterceptorStub.AddInterceptor(method, interceptor);
        }
Beispiel #3
0
        /// <summary>
        /// Removes an interceptor.
        /// </summary>
        /// <param name="method">The method to intercept</param>
        /// <param name="interceptor">The interceptor to remove</param>
        /// <returns>True if an interceptor was removed</returns>
        internal static bool RemoveInterceptor(MethodInfo method, IInterceptor interceptor)
        {
            lock (syncRoot)
            {
                FieldInfo             stubField = GetStubField(method);
                StaticInterceptorStub stub      = (StaticInterceptorStub)stubField.GetValue(null);

                if (stub == null)
                {
                    return(false);
                }

                IInterceptor[] oldInterceptors = stub.interceptors;
                int            index           = Array.IndexOf(oldInterceptors, interceptor);
                if (index < 0)
                {
                    return(false);
                }

                if (oldInterceptors.Length == 1)
                {
                    stub = null;
                }
                else
                {
                    IInterceptor[] newInterceptors = new IInterceptor[oldInterceptors.Length - 1];

                    int remainder = newInterceptors.Length - index;
                    if (index != 0)
                    {
                        Array.Copy(oldInterceptors, newInterceptors, index);
                    }
                    if (remainder != 0)
                    {
                        Array.Copy(oldInterceptors, index + 1, newInterceptors, index, remainder);
                    }

                    stub = new StaticInterceptorStub(method, newInterceptors, stub.methodInvocationTarget);
                }

                stubField.SetValue(null, stub);
                return(true);
            }
        }
Beispiel #4
0
        /// <summary>
        /// Adds an interceptor.
        /// </summary>
        /// <param name="method">The method to intercept</param>
        /// <param name="interceptor">The interceptor to add</param>
        internal static void AddInterceptor(MethodInfo method, IInterceptor interceptor)
        {
            lock (syncRoot)
            {
                FieldInfo             stubField = GetStubField(method);
                StaticInterceptorStub stub      = (StaticInterceptorStub)stubField.GetValue(null);

                IInterceptor[] newInterceptors;
                if (stub == null)
                {
                    newInterceptors = new IInterceptor[] { interceptor };
                    stub            = new StaticInterceptorStub(method, newInterceptors);
                }
                else
                {
                    newInterceptors = stub.interceptors;
                    Array.Resize(ref newInterceptors, newInterceptors.Length + 1);
                    newInterceptors[newInterceptors.Length - 1] = interceptor;
                    stub = new StaticInterceptorStub(method, newInterceptors, stub.methodInvocationTarget);
                }

                stubField.SetValue(null, stub);
            }
        }
Beispiel #5
0
 /// <summary>
 /// Creates an invocation.
 /// </summary>
 /// <param name="interceptorStub">The stub</param>
 /// <param name="invocationTarget">The invocation target or null if intercepting a static method</param>
 /// <param name="arguments">The arguments</param>
 public StaticInvocation(StaticInterceptorStub interceptorStub, object invocationTarget, object[] arguments)
 {
     this.interceptorStub  = interceptorStub;
     this.invocationTarget = invocationTarget;
     this.arguments        = arguments;
 }
 /// <summary>
 /// Creates an invocation.
 /// </summary>
 /// <param name="interceptorStub">The stub</param>
 /// <param name="invocationTarget">The invocation target or null if intercepting a static method</param>
 /// <param name="arguments">The arguments</param>
 public StaticInvocation(StaticInterceptorStub interceptorStub, object invocationTarget, object[] arguments)
 {
     this.interceptorStub = interceptorStub;
     this.invocationTarget = invocationTarget;
     this.arguments = arguments;
 }
        /// <summary>
        /// Adds an interceptor.
        /// </summary>
        /// <param name="method">The method to intercept</param>
        /// <param name="interceptor">The interceptor to add</param>
        internal static void AddInterceptor(MethodInfo method, IInterceptor interceptor)
        {
            lock (syncRoot)
            {
                FieldInfo stubField = GetStubField(method);
                StaticInterceptorStub stub = (StaticInterceptorStub)stubField.GetValue(null);

                IInterceptor[] newInterceptors;
                if (stub == null)
                {
                    newInterceptors = new IInterceptor[] { interceptor };
                    stub = new StaticInterceptorStub(method, newInterceptors);
                }
                else
                {
                    newInterceptors = stub.interceptors;
                    Array.Resize(ref newInterceptors, newInterceptors.Length + 1);
                    newInterceptors[newInterceptors.Length - 1] = interceptor;
                    stub = new StaticInterceptorStub(method, newInterceptors, stub.methodInvocationTarget);
                }

                stubField.SetValue(null, stub);
            }
        }
        /// <summary>
        /// Removes an interceptor.
        /// </summary>
        /// <param name="method">The method to intercept</param>
        /// <param name="interceptor">The interceptor to remove</param>
        /// <returns>True if an interceptor was removed</returns>
        internal static bool RemoveInterceptor(MethodInfo method, IInterceptor interceptor)
        {
            lock (syncRoot)
            {
                FieldInfo stubField = GetStubField(method);
                StaticInterceptorStub stub = (StaticInterceptorStub)stubField.GetValue(null);

                if (stub == null)
                    return false;

                IInterceptor[] oldInterceptors = stub.interceptors;
                int index = Array.IndexOf(oldInterceptors, interceptor);
                if (index < 0)
                    return false;

                if (oldInterceptors.Length == 1)
                {
                    stub = null;
                }
                else
                {
                    IInterceptor[] newInterceptors = new IInterceptor[oldInterceptors.Length - 1];

                    int remainder = newInterceptors.Length - index;
                    if (index != 0)
                        Array.Copy(oldInterceptors, newInterceptors, index);
                    if (remainder != 0)
                        Array.Copy(oldInterceptors, index + 1, newInterceptors, index, remainder);

                    stub = new StaticInterceptorStub(method, newInterceptors, stub.methodInvocationTarget);
                }

                stubField.SetValue(null, stub);
                return true;
            }
        }
        private void Rewrite(TypeDefinition typeDefinition, MethodDefinition methodDefinition, List <MethodDefinition> addedMethods)
        {
            if (!methodDefinition.HasBody)
            {
                return;
            }

            ImportReferences();

            // Create an interceptor stub for the method.
            string          stubFieldName       = StaticInterceptorStub.GetStubFieldName(methodDefinition.Name);
            FieldDefinition stubFieldDefinition = new FieldDefinition(stubFieldName, staticInterceptorStubReference,
                                                                      FieldAttributes.Private | FieldAttributes.Static | FieldAttributes.NotSerialized);

            typeDefinition.Fields.Add(stubFieldDefinition);

            // Clone the original method and give it a new name.
            MethodDefinition targetMethodDefinition = methodDefinition.Clone();

            targetMethodDefinition.Overrides.Clear();
            targetMethodDefinition.Attributes = (methodDefinition.Attributes & MethodAttributes.Static)
                                                | MethodAttributes.Private | MethodAttributes.HideBySig;
            targetMethodDefinition.CallingConvention = MethodCallingConvention.Default;
            targetMethodDefinition.Name = StaticInterceptorStub.GetTargetMethodName(methodDefinition.Name);

            addedMethods.Add(targetMethodDefinition);

            // Replace the original method with a stub that calls the callback.
            MethodBody body = new MethodBody(methodDefinition);

            body.InitLocals       = true;
            methodDefinition.Body = body;
            CilWorker worker = body.CilWorker;

            /*** Obtain the invocation, if needed ***/
            // Load the stub if it has been initialized.
            VariableDefinition stubVariableDefinition = new VariableDefinition(staticInterceptorStubReference);

            body.Variables.Add(stubVariableDefinition);

            worker.Emit(OpCodes.Ldsfld, stubFieldDefinition);
            worker.Emit(OpCodes.Dup);
            worker.Emit(OpCodes.Stloc, stubVariableDefinition);
            Instruction fastPathEntryBranch = worker.Emit(OpCodes.Brfalse, body.Instructions.Outside);

            /*** Slow path ***/
            // Copy arguments to an array.
            VariableDefinition argumentsVariableDefinition = null;

            if (methodDefinition.Parameters.Count != 0)
            {
                argumentsVariableDefinition = new VariableDefinition(objectArrayReference);
                body.Variables.Add(argumentsVariableDefinition);

                worker.Emit(OpCodes.Ldc_I4, methodDefinition.Parameters.Count);
                worker.Emit(OpCodes.Newarr, objectReference);
                worker.Emit(OpCodes.Stloc, argumentsVariableDefinition);

                foreach (ParameterDefinition param in methodDefinition.Parameters)
                {
                    if ((param.Attributes & ParameterAttributes.In) != 0)
                    {
                        worker.Emit(OpCodes.Ldloc, argumentsVariableDefinition);
                        worker.Emit(OpCodes.Ldc_I4, param.Sequence);
                        worker.Emit(OpCodes.Ldarg, param);
                        worker.Emit(OpCodes.Box, objectReference);
                        worker.Emit(OpCodes.Stelem_Ref);
                    }
                }
            }

            // Create the invocation.
            worker.Emit(OpCodes.Ldloc, stubVariableDefinition);
            if (methodDefinition.HasThis)
            {
                worker.Emit(OpCodes.Ldarg_0);
            }
            else
            {
                worker.Emit(OpCodes.Ldnull);
            }
            if (argumentsVariableDefinition == null)
            {
                worker.Emit(OpCodes.Ldsfld, noArgumentsReference);
            }
            else
            {
                worker.Emit(OpCodes.Ldloc, argumentsVariableDefinition);
            }
            worker.Emit(OpCodes.Newobj, staticInvocationConstructorReference);

            // Execute it (leaves the result on the stack).
            worker.Emit(OpCodes.Call, executeReference);

            // Copy any ref and out arguments back out of the invocation's array.
            if (argumentsVariableDefinition != null)
            {
                foreach (ParameterDefinition param in methodDefinition.Parameters)
                {
                    if ((param.Attributes & ParameterAttributes.Out) != 0)
                    {
                        worker.Emit(OpCodes.Ldloc, argumentsVariableDefinition);
                        worker.Emit(OpCodes.Ldc_I4, param.Sequence);
                        worker.Emit(OpCodes.Ldelem_Ref);
                        worker.Emit(OpCodes.Unbox_Any, param.ParameterType);
                        worker.Emit(OpCodes.Starg, param);
                    }
                }
            }

            // Unbox the result if needed and return.
            if (CecilUtils.IsVoid(methodDefinition.ReturnType.ReturnType))
            {
                worker.Emit(OpCodes.Pop);
            }
            else
            {
                worker.Emit(OpCodes.Unbox_Any, methodDefinition.ReturnType.ReturnType);
            }

            Instruction slowPathReturnBranch = worker.Emit(OpCodes.Br, body.Instructions.Outside);

            /*** Fast path ***/
            // Load up all arguments.
            Instruction fastPathEntryInstr = null;

            if (methodDefinition.HasThis)
            {
                fastPathEntryInstr = worker.Emit(OpCodes.Ldarg, methodDefinition.This);
            }
            foreach (ParameterDefinition param in methodDefinition.Parameters)
            {
                Instruction instr = worker.Emit(OpCodes.Ldarg, param);
                if (fastPathEntryInstr == null)
                {
                    fastPathEntryInstr = instr;
                }
            }

            // Emit a tail call back to the original method for the fast-path without an invocation.
            worker.Emit(OpCodes.Tail);
            worker.Emit(OpCodes.Call, targetMethodDefinition);

            /*** Common return ***/
            Instruction returnInstr = worker.Emit(OpCodes.Ret);

            // Patch branches.
            fastPathEntryBranch.Operand  = fastPathEntryInstr;
            slowPathReturnBranch.Operand = returnInstr;
        }