/// <summary>
        /// Adds the original instructions to a given method body.
        /// </summary>
        /// <param name="IL">The <see cref="CilWorker"/> responsible for the target method body.</param>
        public void Emit(CilWorker IL)
        {
            var originalInstructions = new List<Instruction>(_oldInstructions);
            Instruction lastInstruction = originalInstructions.LastOrDefault();

            if (lastInstruction != null && lastInstruction.OpCode == OpCodes.Ret)
            {
                // HACK: Convert the Ret instruction into a Nop
                // instruction so that the code will
                // fall through to the epilog
                lastInstruction.OpCode = OpCodes.Br;
                lastInstruction.Operand = _endLabel;
            }

            foreach (Instruction instruction in (IEnumerable<Instruction>) originalInstructions)
            {
                if (instruction.OpCode != OpCodes.Ret || instruction == lastInstruction)
                    continue;

                if (lastInstruction == null)
                    continue;

                // HACK: Modify all ret instructions to call
                // the epilog after execution
                instruction.OpCode = OpCodes.Br;
                instruction.Operand = lastInstruction;
            }

            // Emit the original instructions
            foreach (Instruction instruction in originalInstructions)
            {
                IL.Append(instruction);
            }
        }
        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);
        }
Esempio n. 3
0
        /// <summary>
        /// Rewrites a target method using the given CilWorker.
        /// </summary>
        /// <param name="method">The target method.</param>
        /// <param name="IL">The CilWorker that will be used to rewrite the target method.</param>
        /// <param name="oldInstructions">The original instructions from the target method body.</param>
        public void Rewrite(MethodDefinition method, CilWorker IL, IEnumerable<Instruction> oldInstructions)
        {
            var declaringType = method.DeclaringType;
            var module = declaringType.Module;

            // Interfaces and Enums cannot be modified
            if (declaringType.IsInterface || declaringType.IsEnum)
                return;

            ImportReferences(module);

            AddLocals(method);

            if (!_modifiedTypes.Contains(declaringType))
            {
                AddAdditionalMembers(declaringType);
                _modifiedTypes.Add(declaringType);
            }

            var newInstructions = new Queue<Instruction>();
            foreach (var instruction in oldInstructions)
            {
                // Intercept only the load field and the load static field instruction
                if (!ShouldReplace(instruction, method))
                {
                    IL.Append(instruction);
                    continue;
                }

                Replace(instruction, method, IL);
            }
        }
        /// <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);
            // }
        }
Esempio n. 6
0
        protected override void RewriteMethodBody(MethodDefinition method, CilWorker IL, IEnumerable<Instruction> oldInstructions)
        {
            var newInstructions = new Queue<Instruction>();
            foreach (var instruction in oldInstructions)
            {
                if (!ShouldReplace(instruction, method))
                {
                    IL.Append(instruction);
                    continue;
                }

                Replace(instruction, method, IL);
            }
        }
        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);
        }
        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);
        }
        protected override void Replace(Instruction currentInstruction, MethodDefinition method, CilWorker IL)
        {
            var constructor = (MethodReference) currentInstruction.Operand;
            TypeReference concreteType = constructor.DeclaringType;
            ParameterDefinitionCollection parameters = constructor.Parameters;

            if (!_emitter.ShouldIntercept(constructor, concreteType, method))
            {
                // Reuse the old instruction instead of emitting a new one
                IL.Append(currentInstruction);
                return;
            }

            _emitter.EmitNewObject(method, IL, constructor, concreteType);
        }
Esempio n. 10
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);
        }
Esempio n. 13
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. 14
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. 15
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. 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);
        }
Esempio n. 17
0
 private void AddOriginalInstructions(CilWorker IL, IEnumerable<Instruction> oldInstructions)
 {
     foreach (var instruction in oldInstructions)
     {
         IL.Append(instruction);
     }
 }
Esempio n. 18
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);
        }
        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);
        }
        internal static MethodBody Clone(MethodBody body, MethodDefinition parent, ImportContext context)
        {
            MethodBody nb = new MethodBody(parent);

            nb.MaxStack   = body.MaxStack;
            nb.InitLocals = body.InitLocals;
            nb.CodeSize   = body.CodeSize;

            CilWorker worker = nb.CilWorker;

            if (body.HasVariables)
            {
                foreach (VariableDefinition var in body.Variables)
                {
                    nb.Variables.Add(new VariableDefinition(
                                         var.Name, var.Index, parent,
                                         context.Import(var.VariableType)));
                }
            }

            foreach (Instruction instr in body.Instructions)
            {
                Instruction ni = new Instruction(instr.OpCode);

                switch (instr.OpCode.OperandType)
                {
                case OperandType.InlineParam:
                case OperandType.ShortInlineParam:
                    if (instr.Operand == body.Method.This)
                    {
                        ni.Operand = nb.Method.This;
                    }
                    else
                    {
                        int param = body.Method.Parameters.IndexOf((ParameterDefinition)instr.Operand);
                        ni.Operand = parent.Parameters [param];
                    }
                    break;

                case OperandType.InlineVar:
                case OperandType.ShortInlineVar:
                    int var = body.Variables.IndexOf((VariableDefinition)instr.Operand);
                    ni.Operand = nb.Variables [var];
                    break;

                case OperandType.InlineField:
                    ni.Operand = context.Import((FieldReference)instr.Operand);
                    break;

                case OperandType.InlineMethod:
                    ni.Operand = context.Import((MethodReference)instr.Operand);
                    break;

                case OperandType.InlineType:
                    ni.Operand = context.Import((TypeReference)instr.Operand);
                    break;

                case OperandType.InlineTok:
                    if (instr.Operand is TypeReference)
                    {
                        ni.Operand = context.Import((TypeReference)instr.Operand);
                    }
                    else if (instr.Operand is FieldReference)
                    {
                        ni.Operand = context.Import((FieldReference)instr.Operand);
                    }
                    else if (instr.Operand is MethodReference)
                    {
                        ni.Operand = context.Import((MethodReference)instr.Operand);
                    }
                    break;

                case OperandType.ShortInlineBrTarget:
                case OperandType.InlineBrTarget:
                case OperandType.InlineSwitch:
                    break;

                default:
                    ni.Operand = instr.Operand;
                    break;
                }

                worker.Append(ni);
            }

            for (int i = 0; i < body.Instructions.Count; i++)
            {
                Instruction instr = nb.Instructions [i];
                Instruction oldi  = body.Instructions [i];

                if (instr.OpCode.OperandType == OperandType.InlineSwitch)
                {
                    Instruction [] olds    = (Instruction [])oldi.Operand;
                    Instruction [] targets = new Instruction [olds.Length];

                    for (int j = 0; j < targets.Length; j++)
                    {
                        targets [j] = GetInstruction(body, nb, olds [j]);
                    }

                    instr.Operand = targets;
                }
                else if (instr.OpCode.OperandType == OperandType.ShortInlineBrTarget || instr.OpCode.OperandType == OperandType.InlineBrTarget)
                {
                    instr.Operand = GetInstruction(body, nb, (Instruction)oldi.Operand);
                }
            }

            if (!body.HasExceptionHandlers)
            {
                return(nb);
            }

            foreach (ExceptionHandler eh in body.ExceptionHandlers)
            {
                ExceptionHandler neh = new ExceptionHandler(eh.Type);
                neh.TryStart     = GetInstruction(body, nb, eh.TryStart);
                neh.TryEnd       = GetInstruction(body, nb, eh.TryEnd);
                neh.HandlerStart = GetInstruction(body, nb, eh.HandlerStart);
                neh.HandlerEnd   = GetInstruction(body, nb, eh.HandlerEnd);

                switch (eh.Type)
                {
                case ExceptionHandlerType.Catch:
                    neh.CatchType = context.Import(eh.CatchType);
                    break;

                case ExceptionHandlerType.Filter:
                    neh.FilterStart = GetInstruction(body, nb, eh.FilterStart);
                    neh.FilterEnd   = GetInstruction(body, nb, eh.FilterEnd);
                    break;
                }

                nb.ExceptionHandlers.Add(neh);
            }

            return(nb);
        }
Esempio n. 21
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));
 }
        /// <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);
        }
Esempio n. 23
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);
        }
        public void EmitNewObject(MethodDefinition hostMethod, CilWorker IL, MethodReference targetConstructor, TypeReference concreteType)
        {
            var 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
            var parameterCount = parameters.Count;
            for (var index = 0; index < parameterCount; index++)
            {
                var 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);
        }
Esempio n. 25
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);
        }