Esempio n. 1
0
        /// <summary>
        /// Saves the return value from a given method call.
        /// </summary>
        /// <param name="IL">The <see cref="CilWorker"/> pointing to the target method body.</param>
        public void Emit(CilWorker IL)
        {
            var module = IL.GetModule();
            var voidType = module.ImportType(typeof (void));
            var returnTypeIsValueType = _returnType != voidType && _returnType.IsValueType;

            if (_returnType is GenericParameter || returnTypeIsValueType)
                IL.Create(OpCodes.Box, _returnType);

            if (_returnType != voidType)
                IL.Create(OpCodes.Stloc, _returnValue);
        }
        /// <summary>
        /// Saves the return value from a given method call.
        /// </summary>
        /// <param name="IL">The <see cref="CilWorker"/> pointing to the target method body.</param>
        public void Emit(CilWorker IL)
        {
            ModuleDefinition module = IL.GetModule();
            TypeReference voidType = module.ImportType(typeof (void));
            bool returnTypeIsValueType = _returnType != voidType && _returnType.IsValueType;

            if (_returnType is GenericParameter || returnTypeIsValueType)
                IL.Create(OpCodes.Box, _returnType);

            if (_returnType != voidType)
                IL.Create(OpCodes.Stloc, _returnValue);
        }
        public void Emit(CilWorker IL)
        {
            var module = IL.GetModule();
            var modifiableType = module.ImportType<IModifiableType>();
            var getInterceptionDisabledMethod = module.ImportMethod<IModifiableType>("get_IsInterceptionDisabled");
            if (!_hostMethod.HasThis)
            {
                IL.Emit(OpCodes.Ldc_I4_0);
                IL.Emit(OpCodes.Stloc, _interceptionDisabled);
                return;
            }

            var skipLabel = IL.Create(OpCodes.Nop);

            // var interceptionDisabled = this.IsInterceptionDisabled;
            IL.Emit(OpCodes.Ldarg_0);
            IL.Emit(OpCodes.Isinst, modifiableType);
            IL.Emit(OpCodes.Brfalse, skipLabel);

            IL.Emit(OpCodes.Ldarg_0);
            IL.Emit(OpCodes.Isinst, modifiableType);
            IL.Emit(OpCodes.Callvirt, getInterceptionDisabledMethod);
            IL.Emit(OpCodes.Stloc, _interceptionDisabled);

            IL.Append(skipLabel);
        }
        /// <summary>
        /// Adds method body interception to the target method.
        /// </summary>
        /// <param name="IL">The <see cref="CilWorker"/> pointing to the target method body.</param>
        public void Emit(CilWorker IL)
        {
            MethodDefinition method = IL.GetMethod();
            TypeReference returnType = method.ReturnType.ReturnType;

            Instruction endLabel = IL.Create(OpCodes.Nop);
            Instruction executeOriginalInstructions = IL.Create(OpCodes.Nop);

            // Execute the method body replacement if and only if
            // interception is enabled
            IL.Emit(OpCodes.Ldloc, _interceptionDisabled);
            IL.Emit(OpCodes.Brtrue, executeOriginalInstructions);

            Instruction invokeReplacement = IL.Create(OpCodes.Nop);

            IL.Emit(OpCodes.Ldloc, _methodReplacementProvider);
            IL.Emit(OpCodes.Brtrue, invokeReplacement);

            IL.Emit(OpCodes.Ldloc, _classMethodReplacementProvider);
            IL.Emit(OpCodes.Brtrue, invokeReplacement);

            IL.Emit(OpCodes.Br, executeOriginalInstructions);
            IL.Append(invokeReplacement);

            // This is equivalent to the following code:
            // var replacement = provider.GetMethodReplacement(info);
            var invokeMethodReplacement = new InvokeMethodReplacement(executeOriginalInstructions,
                                                                      _methodReplacementProvider,
                                                                      _classMethodReplacementProvider, _invocationInfo);
            invokeMethodReplacement.Emit(IL);

            IL.Emit(OpCodes.Br, endLabel);

            #region The original instruction block

            IL.Append(executeOriginalInstructions);
            var addOriginalInstructions = new AddOriginalInstructions(_oldInstructions, endLabel);
            addOriginalInstructions.Emit(IL);

            #endregion

            // Mark the end of the method body
            IL.Append(endLabel);

            var saveReturnValue = new SaveReturnValue(returnType, _returnValue);
            saveReturnValue.Emit(IL);
        }
Esempio n. 5
0
        public void Emit(CilWorker IL)
        {
            var targetMethod = IL.GetMethod();
            var declaringType = targetMethod.DeclaringType;
            var module = declaringType.Module;

            var getSurroundingClassImplementation = new GetSurroundingClassImplementation(_invocationInfo,
                                                                                          _surroundingClassImplementation, _registryType.GetMethod("GetSurroundingImplementation"));

            // var classAroundInvoke = AroundInvokeRegistry.GetSurroundingImplementation(info);
            getSurroundingClassImplementation.Emit(IL);

            // classAroundInvoke.BeforeInvoke(info);
            var skipInvoke = IL.Create(OpCodes.Nop);

            IL.Emit(OpCodes.Ldloc, _surroundingClassImplementation);
            IL.Emit(OpCodes.Brfalse, skipInvoke);

            var beforeInvoke = module.ImportMethod<IBeforeInvoke>("BeforeInvoke");

            // surroundingImplementation.BeforeInvoke(invocationInfo);
            IL.Emit(OpCodes.Ldloc, _surroundingClassImplementation);
            IL.Emit(OpCodes.Ldloc, _invocationInfo);
            IL.Emit(OpCodes.Callvirt, beforeInvoke);

            IL.Append(skipInvoke);

            // if (surroundingImplementation != null) {
            if (!targetMethod.HasThis)
                return;

            var skipInvoke1 = IL.Create(OpCodes.Nop);
            IL.Emit(OpCodes.Ldloc, _surroundingImplementation);
            IL.Emit(OpCodes.Brfalse, skipInvoke1);

            var beforeInvoke1 = module.ImportMethod<IBeforeInvoke>("BeforeInvoke");

            // surroundingImplementation.BeforeInvoke(invocationInfo);
            IL.Emit(OpCodes.Ldloc, _surroundingImplementation);
            IL.Emit(OpCodes.Ldloc, _invocationInfo);
            IL.Emit(OpCodes.Callvirt, beforeInvoke1);

            IL.Append(skipInvoke1);
            // }
        }
        public void EmitNewObject(MethodDefinition hostMethod, CilWorker IL, MethodReference targetConstructor,
                                  TypeReference concreteType)
        {
            ParameterDefinitionCollection parameters = targetConstructor.Parameters;
            Instruction skipInterception = IL.Create(OpCodes.Nop);

            SaveConstructorArguments(IL, parameters);
            EmitCreateMethodActivationContext(hostMethod, IL, concreteType);

            // Skip the interception if an activator cannot be found
            EmitGetActivator(hostMethod, IL, skipInterception);

            IL.Emit(OpCodes.Stloc, _currentActivator);

            IL.Emit(OpCodes.Ldloc, _currentActivator);
            IL.Emit(OpCodes.Brfalse, skipInterception);

            // Determine if the activator can instantiate the method from the
            // current context
            IL.Emit(OpCodes.Ldloc, _currentActivator);
            IL.Emit(OpCodes.Ldloc, _methodContext);
            IL.Emit(OpCodes.Callvirt, _canActivate);
            IL.Emit(OpCodes.Brfalse, skipInterception);

            // Use the activator to create the object instance
            EmitCreateInstance(IL);

            // }
            Instruction endCreate = IL.Create(OpCodes.Nop);
            IL.Emit(OpCodes.Br, endCreate);
            // else {
            IL.Append(skipInterception);

            // Restore the arguments that were popped off the stack
            // by the list of constructor arguments
            int parameterCount = parameters.Count;
            for (int index = 0; index < parameterCount; index++)
            {
                ParameterDefinition currentParameter = parameters[index];

                IL.Emit(OpCodes.Ldloc, _constructorArguments);
                IL.Emit(OpCodes.Ldc_I4, index);
                IL.Emit(OpCodes.Callvirt, _getItem);
                IL.Emit(OpCodes.Unbox_Any, currentParameter.ParameterType);
            }

            IL.Emit(OpCodes.Newobj, targetConstructor);
            // }

            IL.Append(endCreate);
        }
        private static void Emit(CilWorker IL, ModuleDefinition module,
                                 VariableDefinition surroundingImplementation,
                                 VariableDefinition invocationInfo,
                                 VariableDefinition returnValue)
        {
            Instruction skipInvoke = IL.Create(OpCodes.Nop);

            Instruction skipPrint = IL.Create(OpCodes.Nop);
            IL.Emit(OpCodes.Ldloc, surroundingImplementation);
            IL.Emit(OpCodes.Brtrue, skipPrint);

            IL.Append(skipPrint);
            IL.Emit(OpCodes.Ldloc, surroundingImplementation);
            IL.Emit(OpCodes.Brfalse, skipInvoke);

            MethodReference aroundInvoke = module.ImportMethod<IAfterInvoke>("AfterInvoke");
            IL.Emit(OpCodes.Ldloc, surroundingImplementation);
            IL.Emit(OpCodes.Ldloc, invocationInfo);
            IL.Emit(OpCodes.Ldloc, returnValue);
            IL.Emit(OpCodes.Callvirt, aroundInvoke);

            IL.Append(skipInvoke);
        }
        private static void GetMethodReplacementInstance(MethodDefinition method,
            CilWorker IL,
            VariableDefinition methodReplacement,
            VariableDefinition methodReplacementProvider, VariableDefinition invocationInfo)
        {
            var declaringType = method.DeclaringType;
            var module = declaringType.Module;
            var pushInstance = method.HasThis ? IL.Create(OpCodes.Ldarg_0) : IL.Create(OpCodes.Ldnull);

            var getReplacement = module.ImportMethod<IMethodReplacementProvider>("GetMethodReplacement");
            IL.Emit(OpCodes.Ldloc, methodReplacementProvider);

            var skipGetMethodReplacement = IL.Create(OpCodes.Nop);
            IL.Emit(OpCodes.Brfalse, skipGetMethodReplacement);
            IL.Emit(OpCodes.Ldloc, methodReplacementProvider);

            IL.Append(pushInstance);
            IL.Emit(OpCodes.Ldloc, invocationInfo);
            IL.Emit(OpCodes.Callvirt, getReplacement);
            IL.Emit(OpCodes.Stloc, methodReplacement);

            IL.Append(skipGetMethodReplacement);
        }
Esempio n. 9
0
        public void AddEpilog(CilWorker IL)
        {
            var skipEpilog = IL.Create(OpCodes.Nop);

            // if (!IsInterceptionDisabled && surroundingImplementation != null) {
            IL.Emit(OpCodes.Ldloc, _interceptionDisabled);
            IL.Emit(OpCodes.Brtrue, skipEpilog);

            // surroundingImplementation.AfterInvoke(invocationInfo, returnValue);
            var emitAfterInvoke = new EmitAfterInvoke(_surroundingImplementation, _surroundingClassImplementation, _invocationInfo, _returnValue);
            emitAfterInvoke.Emit(IL);

            // }
            IL.Append(skipEpilog);
        }
        public void Rewrite(MethodDefinition method, CilWorker IL,
            IEnumerable<Instruction> oldInstructions)
        {
            var targetMethod = _parameters.TargetMethod;
            var worker = targetMethod.GetILGenerator();
            var module = worker.GetModule();
            _getInterceptionDisabled.Emit(worker);

            // Construct the InvocationInfo instance
            var skipInvocationInfo = worker.Create(OpCodes.Nop);
            worker.Emit(OpCodes.Ldloc, _parameters.InterceptionDisabled);
            worker.Emit(OpCodes.Brtrue, skipInvocationInfo);

            var interceptedMethod = targetMethod;
            _emitter.Emit(targetMethod, interceptedMethod, _parameters.InvocationInfo);

            var skipGetReplacementProvider = IL.Create(OpCodes.Nop);
            // var provider = this.MethodReplacementProvider;
            //IL.Emit(OpCodes.Ldloc, _interceptionDisabled);
            //IL.Emit(OpCodes.Brtrue, skipGetReplacementProvider);
            _getInstanceMethodReplacementProvider.Emit(IL);
            _surroundMethodBody.AddProlog(worker);
            IL.Append(skipGetReplacementProvider);

            worker.Append(skipInvocationInfo);

            _getClassMethodReplacementProvider.Emit(worker);

            var returnType = targetMethod.ReturnType.ReturnType;

            _addMethodReplacement.Emit(worker);

            // Save the return value
            TypeReference voidType = module.Import(typeof(void));
            _surroundMethodBody.AddEpilog(worker);

            if (returnType != voidType)
                worker.Emit(OpCodes.Ldloc, _parameters.ReturnValue);

            worker.Emit(OpCodes.Ret);
        }
        public void Emit(CilWorker IL)
        {
            var module = IL.GetModule();
            var method = IL.GetMethod();
            var returnType = method.ReturnType.ReturnType;
            var methodReplacement = MethodDefinitionExtensions.AddLocal(method, typeof(IInterceptor));

            GetMethodReplacementInstance(method, IL, methodReplacement, _methodReplacementProvider, _invocationInfo);

            var skipGetClassMethodReplacement = IL.Create(OpCodes.Nop);
            IL.Emit(OpCodes.Ldloc, methodReplacement);
            IL.Emit(OpCodes.Brtrue, skipGetClassMethodReplacement);

            GetMethodReplacementInstance(method, IL, methodReplacement, _classMethodReplacementProvider, _invocationInfo);

            IL.Append(skipGetClassMethodReplacement);
            IL.Emit(OpCodes.Ldloc, methodReplacement);
            IL.Emit(OpCodes.Brfalse, _executeOriginalInstructions);

            // var returnValue = replacement.Intercept(info);
            InvokeInterceptor(module, IL, methodReplacement, returnType, _invocationInfo);
        }
 private void EnteringMethodInstruction(MethodDefinition method, CilWorker worker)
 {
     MethodReference enteringMethod =
         method.DeclaringType.Module.Import(typeof (Profiler).GetMethod("EnteringMethod"));
     worker.InsertBefore(method.Body.Instructions[0], worker.Create(OpCodes.Call, enteringMethod));
     worker.InsertBefore(method.Body.Instructions[0],
                         worker.Create(OpCodes.Ldstr, MethodName(method)));
 }
 private void InstrumentMethodAtThrow(CilWorker worker, Instruction throwInstruction,
                                                   MethodReference profilerMethod)
 {
     Instruction newThrowInstruction = worker.Create(throwInstruction.OpCode);
     throwInstruction.OpCode = OpCodes.Call;
     throwInstruction.Operand = profilerMethod;
     worker.InsertAfter(throwInstruction, newThrowInstruction);
 }
Esempio n. 14
0
        private void Replace(CilWorker IL, Instruction oldInstruction, MethodReference targetMethod, MethodDefinition hostMethod, Instruction endLabel, Instruction callOriginalMethod)
        {
            var returnType = targetMethod.ReturnType.ReturnType;
            var module = hostMethod.DeclaringType.Module;
            if (!hostMethod.IsStatic)
                GetInstanceProvider(IL);

            var pushInstance = hostMethod.HasThis ? IL.Create(OpCodes.Ldarg_0) : IL.Create(OpCodes.Ldnull);

            // If all else fails, use the static method replacement provider
            IL.Append(pushInstance);
            IL.Emit(OpCodes.Ldloc, _invocationInfo);
            IL.Emit(OpCodes.Call, _getStaticProvider);
            IL.Emit(OpCodes.Stloc, _staticProvider);

            var restoreArgumentStack = IL.Create(OpCodes.Nop);

            var callReplacement = IL.Create(OpCodes.Nop);
            var useStaticProvider = IL.Create(OpCodes.Nop);

            #region Use the instance method replacement provider

            IL.Emit(OpCodes.Ldloc, _instanceProvider);
            IL.Emit(OpCodes.Brfalse, useStaticProvider);

            EmitCanReplace(IL, hostMethod, _instanceProvider);
            IL.Emit(OpCodes.Ldloc, _canReplaceFlag);
            IL.Emit(OpCodes.Brfalse, useStaticProvider);

            EmitGetMethodReplacement(IL, hostMethod, _instanceProvider);

            IL.Emit(OpCodes.Ldloc, _replacement);
            IL.Emit(OpCodes.Brtrue, callReplacement);

            #endregion

            IL.Append(useStaticProvider);
            // if (!MethodReplacementProvider.CanReplace(info))
            //      CallOriginalMethod();
            EmitCanReplace(IL, hostMethod, _staticProvider);

            IL.Emit(OpCodes.Ldloc, _canReplaceFlag);
            IL.Emit(OpCodes.Brfalse, restoreArgumentStack);

            EmitGetMethodReplacement(IL, hostMethod, _staticProvider);

            IL.Append(callReplacement);

            // if (replacement == null)
            //      CallOriginalMethod();
            IL.Emit(OpCodes.Ldloc, _replacement);
            IL.Emit(OpCodes.Brfalse, restoreArgumentStack);

            EmitInterceptorCall(IL);

            IL.PackageReturnValue(module, returnType);

            IL.Emit(OpCodes.Br, endLabel);

            IL.Append(restoreArgumentStack);

            // Reconstruct the method arguments if the interceptor
            // cannot be found

            // Push the target instance
            ReconstructMethodArguments(IL, targetMethod);

            // Mark the CallOriginalMethod instruction label
            IL.Append(callOriginalMethod);

            // Call the original method
            IL.Append(oldInstruction);
        }
Esempio n. 15
0
        private void EmitGetMethodReplacement(CilWorker IL, IMethodSignature hostMethod, VariableDefinition provider)
        {
            // var replacement = MethodReplacementProvider.GetReplacement(info);
            IL.Emit(OpCodes.Ldloc, provider);

            // Push the host instance
            var pushInstance = hostMethod.HasThis ? IL.Create(OpCodes.Ldarg_0) : IL.Create(OpCodes.Ldnull);
            IL.Append(pushInstance);
            IL.Emit(OpCodes.Ldloc, _invocationInfo);
            IL.Emit(OpCodes.Callvirt, _getReplacement);
            IL.Emit(OpCodes.Stloc, _replacement);
        }
Esempio n. 16
0
        protected override void Replace(Instruction oldInstruction, MethodDefinition hostMethod,
            CilWorker IL)
        {
            var targetMethod = (MethodReference)oldInstruction.Operand;

            var callOriginalMethod = IL.Create(OpCodes.Nop);
            var returnType = targetMethod.ReturnType.ReturnType;
            var endLabel = IL.Create(OpCodes.Nop);
            var module = hostMethod.DeclaringType.Module;

            // Create the stack that will hold the method arguments
            IL.Emit(OpCodes.Newobj, _stackCtor);
            IL.Emit(OpCodes.Stloc, _currentArguments);

            SaveInvocationInfo(IL, targetMethod, module, returnType);

            var getInterceptionDisabled = new GetInterceptionDisabled(hostMethod, _interceptionDisabled);
            getInterceptionDisabled.Emit(IL);

            var surroundMethodBody = new SurroundMethodBody(_methodReplacementProvider, _aroundInvokeProvider,
                                                            _invocationInfo, _interceptionDisabled, _returnValue, typeof(AroundInvokeMethodCallRegistry));

            surroundMethodBody.AddProlog(IL);
            // Use the MethodReplacementProvider attached to the
            // current host instance
            Replace(IL, oldInstruction, targetMethod, hostMethod, endLabel, callOriginalMethod);

            IL.Append(endLabel);

            surroundMethodBody.AddEpilog(IL);
        }
        private void EmitCreateMethodActivationContext(MethodDefinition method, CilWorker IL, TypeReference concreteType)
        {
            // TODO: Add static method support
            var pushThis = method.IsStatic ? IL.Create(OpCodes.Ldnull) : IL.Create(OpCodes.Ldarg_0);

            // Push the 'this' pointer onto the stack
            IL.Append(pushThis);

            var module = method.DeclaringType.Module;

            // Push the current method onto the stack
            IL.PushMethod(method, module);

            // Push the concrete type onto the stack
            IL.Emit(OpCodes.Ldtoken, concreteType);
            IL.Emit(OpCodes.Call, _getTypeFromHandle);

            IL.Emit(OpCodes.Ldloc, _constructorArguments);
            IL.Emit(OpCodes.Callvirt, _toArrayMethod);
            IL.Emit(OpCodes.Newobj, _methodActivationContextCtor);

            // var context = new MethodActivationContext(this, currentMethod, concreteType, args);
            IL.Emit(OpCodes.Stloc, _methodContext);
        }
Esempio n. 18
0
        private static void InsertCustomCodeCall(
            MethodDefinition method, 
            MethodReference generatedTypeCtorRef, 
            MethodReference generatedMethodRef, 
            CilWorker cilWorker, 
            Instruction instructionToInsertBefore,
            bool replaceMethod
            )
        {
            bool hasReturnValue = (method.ReturnType.ReturnType.FullName != typeof(void).FullName);

            Instruction nop = cilWorker.Create(OpCodes.Nop);
            cilWorker.InsertBefore(instructionToInsertBefore, nop);

            // call ctor
            Instruction newGeneratedType = cilWorker.Create(OpCodes.Newobj, generatedTypeCtorRef);
            cilWorker.InsertBefore(instructionToInsertBefore, newGeneratedType);

            // load arguments on stack if any
            for (int i = 0; i < method.Parameters.Count; i++)
            {
                Instruction loadArg = cilWorker.Create(OpCodes.Ldarga_S, method.Parameters[i]);
                cilWorker.InsertBefore(instructionToInsertBefore, loadArg);
            }

            // call replacing method
            Instruction callGeneratedMethod = cilWorker.Create(OpCodes.Call, generatedMethodRef);
            cilWorker.InsertBefore(instructionToInsertBefore, callGeneratedMethod);

            if (hasReturnValue)
            {
                if (replaceMethod)
                {
                    // add variable to list
                    var generatedValueVar = new VariableDefinition(method.ReturnType.ReturnType);
                    method.Body.Variables.Add(generatedValueVar);
                    // assign to variable
                    Instruction assignNewGeneratedValue = cilWorker.Create(OpCodes.Stloc, generatedValueVar);
                    cilWorker.InsertBefore(instructionToInsertBefore, assignNewGeneratedValue);
                    Instruction ldLoc = cilWorker.Create(OpCodes.Ldloc_0);
                    Instruction brs = cilWorker.Create(OpCodes.Br_S, ldLoc);
                    cilWorker.InsertBefore(instructionToInsertBefore, brs);
                    cilWorker.InsertBefore(instructionToInsertBefore, ldLoc);
                }
                else
                {
                    // remove value from stack
                    Instruction pop = cilWorker.Create(OpCodes.Pop);
                    cilWorker.InsertBefore(instructionToInsertBefore, pop);
                }
            }
        }
Esempio n. 19
0
 private static void DebugLine(AssemblyDefinition assembly, CilWorker il, string text, params Instruction[] appendInstructions)
 {
     il.Append(il.Create(OpCodes.Ldstr, text));
     //Append any instructions we need to
     if (appendInstructions.Length > 0)
     {
         var concat =
             assembly.Import(typeof (String).GetMethod("Concat", new[] {typeof (string), typeof (string)}));
         foreach (Instruction i in appendInstructions)
         {
             il.Append(il.Create(OpCodes.Ldstr, ","));
             il.Append(il.Create(OpCodes.Call, concat));
             il.Append(i);
             il.Append(il.Create(OpCodes.Call, concat));
         }
     }
     var writeLine = assembly.Import(typeof (Console).GetMethod("WriteLine", new[] {typeof (string)}));
     il.Append(il.Create(OpCodes.Call, writeLine));
 }
Esempio n. 20
0
        private void EmitCanReplace(CilWorker IL, IMethodSignature hostMethod, VariableDefinition provider)
        {
            var skipGetProvider = IL.Create(OpCodes.Nop);

            IL.Emit(OpCodes.Ldloc, provider);
            IL.Emit(OpCodes.Brfalse, skipGetProvider);

            IL.Emit(OpCodes.Ldloc, provider);

            // Push the host instance
            var pushInstance = hostMethod.HasThis ? IL.Create(OpCodes.Ldarg_0) : IL.Create(OpCodes.Ldnull);
            IL.Append(pushInstance);
            IL.Emit(OpCodes.Ldloc, _invocationInfo);
            IL.Emit(OpCodes.Callvirt, _canReplace);

            IL.Emit(OpCodes.Stloc, _canReplaceFlag);
            IL.Append(skipGetProvider);
        }
Esempio n. 21
0
        /// <summary>
        /// Adds a prolog to the given method body.
        /// </summary>
        /// <param name="IL">The <see cref="CilWorker"/> that points to the given method body.</param>
        public void AddProlog(CilWorker IL)
        {
            var method = IL.GetMethod();
            _surroundingImplementation = method.AddLocal<IAroundInvoke>();
            _surroundingClassImplementation = method.AddLocal<IAroundInvoke>();

            var skipProlog = IL.Create(OpCodes.Nop);
            var declaringType = method.DeclaringType;
            var module = declaringType.Module;
            var modifiableType = module.ImportType<IModifiableType>();

            if (method.HasThis)
            {
                IL.Emit(OpCodes.Ldarg_0);
                IL.Emit(OpCodes.Isinst, modifiableType);
                IL.Emit(OpCodes.Brfalse, skipProlog);
            }

            IL.Emit(OpCodes.Ldloc, _interceptionDisabled);
            IL.Emit(OpCodes.Brtrue, skipProlog);

            // var provider = this.MethodReplacementProvider;

            if (_getMethodReplacementProvider != null)
                _getMethodReplacementProvider.Emit(IL);

            var getAroundInvokeProvider = new GetAroundInvokeProvider(_aroundInvokeProvider, _providerName);
            getAroundInvokeProvider.Emit(IL);

            // if (aroundInvokeProvider != null ) {
            var skipGetSurroundingImplementation = IL.Create(OpCodes.Nop);
            var getSurroundingImplementationInstance = new GetSurroundingImplementationInstance(_aroundInvokeProvider,
                _invocationInfo,
                _surroundingImplementation,
                skipGetSurroundingImplementation);

            getSurroundingImplementationInstance.Emit(IL);

            // }

            IL.Append(skipGetSurroundingImplementation);
            var emitBeforeInvoke = new EmitBeforeInvoke(_invocationInfo, _surroundingClassImplementation,
                _surroundingImplementation, _registryType);
            emitBeforeInvoke.Emit(IL);

            IL.Append(skipProlog);
        }
Esempio n. 22
0
        private void GetInstanceProvider(CilWorker IL)
        {
            var skipInstanceProvider = IL.Create(OpCodes.Nop);

            IL.Emit(OpCodes.Ldarg_0);
            IL.Emit(OpCodes.Isinst, _hostInterfaceType);
            IL.Emit(OpCodes.Brfalse, skipInstanceProvider);
            IL.Emit(OpCodes.Ldarg_0);
            IL.Emit(OpCodes.Isinst, _hostInterfaceType);
            IL.Emit(OpCodes.Callvirt, _getProvider);
            IL.Emit(OpCodes.Stloc, _instanceProvider);

            IL.Emit(OpCodes.Ldloc, _instanceProvider);
            IL.Emit(OpCodes.Brtrue, skipInstanceProvider);

            IL.Append(skipInstanceProvider);
        }
Esempio n. 23
0
        /// <summary>
        /// Replaces the <paramref name="oldInstruction"/> with a set of new instructions.
        /// </summary>
        /// <param name="oldInstruction">The instruction currently being evaluated.</param>
        /// <param name="hostMethod">The method that contains the target instruction.</param>
        /// <param name="IL">The CilWorker that will be used to emit the method body instructions.</param>
        protected override void Replace(Instruction oldInstruction, MethodDefinition hostMethod, CilWorker IL)
        {
            var targetField = (FieldReference) oldInstruction.Operand;
            var fieldType = targetField.FieldType;
            var isSetter = oldInstruction.OpCode == OpCodes.Stsfld || oldInstruction.OpCode == OpCodes.Stfld;

            if (isSetter)
            {
                hostMethod.Body.InitLocals = true;
                // Save the setter argument and box it if necessary
                if (fieldType.IsValueType || fieldType is GenericParameter)
                    IL.Emit(OpCodes.Box, fieldType);

                IL.Emit(OpCodes.Stloc, _currentArgument);
            }

            // There's no need to push the current object instance
            // since the this pointer is pushed prior to the field call
            if (hostMethod.IsStatic)
                IL.Emit((OpCodes.Ldnull));

            // Push the current method
            var module = hostMethod.DeclaringType.Module;

            // Push the current method onto the stack
            IL.PushMethod(hostMethod, module);

            // Push the current field onto the stack
            IL.PushField(targetField, module);

            // Push the host type onto the stack
            IL.PushType(hostMethod.DeclaringType, module);

            // Create the IFieldInterceptionContext instance
            IL.Emit(OpCodes.Newobj, _fieldContextCtor);
            IL.Emit(OpCodes.Stloc, _fieldContext);

            var skipInterception = IL.Create(OpCodes.Nop);
            // Obtain an interceptor instance
            if (hostMethod.IsStatic)
            {
                IL.Emit(OpCodes.Ldloc, _fieldContext);
                IL.Emit(OpCodes.Call, _getInterceptor);
            }
            else
            {
                IL.Emit(OpCodes.Ldarg_0);
                IL.Emit(OpCodes.Isinst, _fieldInterceptionHostType);
                IL.Emit(OpCodes.Brfalse, skipInterception);

                IL.Emit(OpCodes.Ldarg_0);
                IL.Emit(OpCodes.Isinst, _fieldInterceptionHostType);
                IL.Emit(OpCodes.Callvirt, _getInstanceInterceptor);
            }

            // The field interceptor cannot be null
            IL.Emit(OpCodes.Stloc, _fieldInterceptor);
            IL.Emit(OpCodes.Ldloc, _fieldInterceptor);
            IL.Emit(OpCodes.Brfalse, skipInterception);

            // if (FieldInterceptor.CanIntercept(context) {
            IL.Emit(OpCodes.Ldloc, _fieldInterceptor);
            IL.Emit(OpCodes.Ldloc, _fieldContext);
            IL.Emit(OpCodes.Callvirt, _canIntercept);
            IL.Emit(OpCodes.Brfalse, skipInterception);

            var isGetter = oldInstruction.OpCode == OpCodes.Ldsfld || oldInstruction.OpCode == OpCodes.Ldfld;

            var endLabel = IL.Create(OpCodes.Nop);

            //Call the interceptor instead of the getter or setter
            if (isGetter)
            {
                IL.Emit(OpCodes.Ldloc, _fieldInterceptor);
                IL.Emit(OpCodes.Ldloc, _fieldContext);
                IL.Emit(OpCodes.Callvirt, _getValue);
                IL.Emit(OpCodes.Unbox_Any, fieldType);
            }

            if (isSetter)
            {
                // Push the 'this' pointer for instance field setters
                if (!hostMethod.IsStatic)
                    IL.Emit(OpCodes.Ldarg_0);

                IL.Emit(OpCodes.Ldloc, _fieldInterceptor);
                IL.Emit(OpCodes.Ldloc, _fieldContext);
                IL.Emit(OpCodes.Ldloc, _currentArgument);

                // Unbox the setter value
                IL.Emit(OpCodes.Unbox_Any, fieldType);

                IL.Emit(OpCodes.Callvirt, _setValue);

                // Set the actual field value
                IL.Emit(OpCodes.Unbox_Any, fieldType);
                IL.Emit(oldInstruction.OpCode, targetField);
            }

            IL.Emit(OpCodes.Br, endLabel);

            // }
            IL.Append(skipInterception);

            // else {

            // Load the original field
            if (!hostMethod.IsStatic)
                IL.Emit(OpCodes.Ldarg_0);

            if (isSetter)
            {
                IL.Emit(OpCodes.Ldloc, _currentArgument);

                // Unbox the setter value
                IL.Emit(OpCodes.Unbox_Any, fieldType);
            }

            IL.Emit(oldInstruction.OpCode, targetField);

            // }

            IL.Append(endLabel);
        }
        /// <summary>
        /// Rewrites the instructions in the target method body to support dynamic exception handling.
        /// </summary>
        /// <param name="targetMethod">The target method.</param>
        /// <param name="IL">The <see cref="CilWorker"/> instance that represents the method body.</param>
        /// <param name="oldInstructions">The IL instructions of the original method body.</param>
        protected override void RewriteMethodBody(MethodDefinition targetMethod, CilWorker IL,
            IEnumerable<Instruction> oldInstructions)
        {
            var endOfOriginalInstructionBlock = IL.Create(OpCodes.Nop);
            var addOriginalInstructions = new AddOriginalInstructions(oldInstructions, endOfOriginalInstructionBlock);

            var endLabel = IL.Create(OpCodes.Nop);
            var tryStart = IL.Emit(OpCodes.Nop);
            var tryEnd = IL.Emit(OpCodes.Nop);
            var catchStart = IL.Emit(OpCodes.Nop);
            var catchEnd = IL.Emit(OpCodes.Nop);

            var module = IL.GetModule();
            var handler = new ExceptionHandler(ExceptionHandlerType.Catch);
            var body = targetMethod.Body;
            body.ExceptionHandlers.Add(handler);

            handler.CatchType = module.ImportType<Exception>();

            handler.TryStart = tryStart;
            handler.TryEnd = tryEnd;

            handler.HandlerStart = catchStart;
            handler.HandlerEnd = catchEnd;

            var emitter = new InvocationInfoEmitter(true);

            var returnType = targetMethod.ReturnType.ReturnType;

            // try {
            IL.Append(tryStart);
            addOriginalInstructions.Emit(IL);

            IL.Append(endOfOriginalInstructionBlock);
            if (returnType != _voidType && _returnValue != null)
            {
                IL.Emit(OpCodes.Stloc, _returnValue);
            }

            IL.Emit(OpCodes.Leave, endLabel);

            // }
            IL.Append(tryEnd);
            // catch (Exception ex) {
            IL.Append(catchStart);
            IL.Emit(OpCodes.Stloc, _exception);

            SaveExceptionInfo(targetMethod, emitter);
            IL.Emit(OpCodes.Ldloc, _exceptionInfo);

            var getHandlerMethodInfo = typeof (ExceptionHandlerRegistry).GetMethod("GetHandler");
            var getHandlerMethod = module.Import(getHandlerMethodInfo);
            IL.Emit(OpCodes.Call, getHandlerMethod);
            IL.Emit(OpCodes.Stloc, _exceptionHandler);

            // if (exceptionHandler == null)
            //      throw;
            var doRethrow = IL.Create(OpCodes.Nop);
            IL.Emit(OpCodes.Ldloc, _exceptionHandler);
            IL.Emit(OpCodes.Brfalse, doRethrow);

            // if (handler.CanCatch(exceptionInfo)) {
            var leaveBlock = IL.Create(OpCodes.Nop);
            var canCatch = module.ImportMethod<IExceptionHandler>("CanCatch");
            IL.Emit(OpCodes.Ldloc, _exceptionHandler);
            IL.Emit(OpCodes.Ldloc, _exceptionInfo);
            IL.Emit(OpCodes.Callvirt, canCatch);
            IL.Emit(OpCodes.Brfalse, doRethrow);

            var catchMethod = module.ImportMethod<IExceptionHandler>("Catch");
            IL.Emit(OpCodes.Ldloc, _exceptionHandler);
            IL.Emit(OpCodes.Ldloc, _exceptionInfo);
            IL.Emit(OpCodes.Callvirt, catchMethod);
            // }

            var getShouldSkipRethrow = module.ImportMethod<IExceptionHandlerInfo>("get_ShouldSkipRethrow");
            IL.Emit(OpCodes.Ldloc, _exceptionInfo);
            IL.Emit(OpCodes.Callvirt, getShouldSkipRethrow);
            IL.Emit(OpCodes.Brfalse, doRethrow);

            IL.Emit(OpCodes.Br, leaveBlock);

            IL.Append(doRethrow);
            IL.Emit(OpCodes.Rethrow);

            IL.Append(leaveBlock);

            IL.Emit(OpCodes.Leave, endLabel);
            IL.Append(catchEnd);
            // }
            IL.Append(endLabel);

            if (returnType != _voidType && _returnValue != null)
            {
                var returnOriginalValue = IL.Create(OpCodes.Nop);
                var getReturnValue = module.ImportMethod<IExceptionHandlerInfo>("get_ReturnValue");

                IL.Emit(OpCodes.Ldloc, _exceptionInfo);
                IL.Emit(OpCodes.Brfalse, returnOriginalValue);

                IL.Emit(OpCodes.Ldloc, _exceptionInfo);
                IL.Emit(OpCodes.Callvirt, getReturnValue);
                IL.Emit(OpCodes.Stloc, _returnValue);
                IL.Append(returnOriginalValue);

                IL.Emit(OpCodes.Ldloc, _returnValue);
            }

            IL.Emit(OpCodes.Ret);
        }
 private void InstrumentMethodAtReturn(CilWorker worker,
                                                                                Instruction exitInstruction,
                                                                                MethodReference exitingMethod,
                                                                                MethodDefinition
                                                                                    methodToInstrument)
 {
     exitInstruction.OpCode = OpCodes.Ldstr;
     exitInstruction.Operand = MethodName(methodToInstrument);
     Instruction callToProfiler = worker.Create(OpCodes.Call, exitingMethod);
     worker.InsertAfter(exitInstruction, callToProfiler);
     worker.InsertAfter(callToProfiler, worker.Create(OpCodes.Ret));
 }