Пример #1
0
        protected virtual void WeaveOnException(IList <AspectData> allAspects, Instruction instructionCallStart, Instruction instructionCallEnd, Instruction instructionAfterCall, IPersistable returnValue)
        {
            var realInstructionAfterCall = instructionAfterCall ?? instructionCallEnd.Next;
            var tryLeaveInstruction      = Instruction.Create(OpCodes.Leave, realInstructionAfterCall);

            _ilProcessor.InsertAfter(instructionCallEnd, tryLeaveInstruction);

            var exception = _creator.SaveThrownException();
            var exceptionHandlerCurrent = exception.InsertAfter(tryLeaveInstruction, _ilProcessor);

            var pushException = _creator.LoadValueOnStack(exception);

            exceptionHandlerCurrent = pushException.InsertAfter(exceptionHandlerCurrent, _ilProcessor);

            var setExceptionFromStack =
                _creator.SetMethodExecutionArgsExceptionFromStack(ExecutionArgs);

            exceptionHandlerCurrent = setExceptionFromStack.InsertAfter(exceptionHandlerCurrent, _ilProcessor);

            var returnAfterHandling = new InstructionBlockChain();

            if (returnValue != null)
            {
                returnAfterHandling.Add(returnValue.Load(false, false));
            }
            returnAfterHandling.Add(new InstructionBlock("Return", Instruction.Create(OpCodes.Ret)));

            var indices = allAspects
                          .Select((asp, index) => new { asp, index })
                          .Where(x => (x.asp.AspectMethods & AspectMethods.OnException) != 0)
                          .Select(x => x.index)
                          .Reverse()
                          .ToList();

            foreach (var index in indices)
            {
                var onExceptionAspect = allAspects[index];
                if (HasMultipleAspects)
                {
                    var load = _creator.LoadMethodExecutionArgsTagFromPersistable(ExecutionArgs,
                                                                                  onExceptionAspect.TagPersistable);
                    exceptionHandlerCurrent = load.InsertAfter(exceptionHandlerCurrent, _ilProcessor);
                }

                var callAspectOnException =
                    _creator.CallAspectOnException(onExceptionAspect, ExecutionArgs);
                var nop = new InstructionBlock("Nop", Instruction.Create(OpCodes.Nop));

                var callOnExitsAndReturn = new InstructionBlockChain();
                for (var i = index - 1; i >= 0; --i)
                {
                    var jthAspect = allAspects[i];
                    if ((jthAspect.AspectMethods & AspectMethods.OnExit) == 0)
                    {
                        continue;
                    }
                    if (HasMultipleAspects)
                    {
                        callOnExitsAndReturn.Add(_creator.LoadMethodExecutionArgsTagFromPersistable(ExecutionArgs, jthAspect.TagPersistable));
                    }
                    callOnExitsAndReturn.Add(_creator.CallAspectOnExit(jthAspect, ExecutionArgs));
                }

                if (returnValue != null)
                {
                    callOnExitsAndReturn.Add(_creator.ReadReturnValue(ExecutionArgs, returnValue));
                }

                callOnExitsAndReturn.Add(new InstructionBlock("Leave", Instruction.Create(OpCodes.Leave_S, returnAfterHandling.First)));

                callAspectOnException.Add(_creator.IfFlowBehaviorIsAnyOf(ExecutionArgs, nop.First, callOnExitsAndReturn, 1, 3));

                callAspectOnException.Add(nop);
                callAspectOnException.InsertAfter(exceptionHandlerCurrent, _ilProcessor);
                exceptionHandlerCurrent = callAspectOnException.Last;
            }

            var flowBehaviorHandler = new InstructionBlockChain();

            flowBehaviorHandler.Add(new InstructionBlock("throw", Instruction.Create(OpCodes.Rethrow)));
            flowBehaviorHandler.Add(new InstructionBlock("Leave", Instruction.Create(OpCodes.Leave_S, realInstructionAfterCall)));
            flowBehaviorHandler.InsertAfter(exceptionHandlerCurrent, _ilProcessor);

            returnAfterHandling.InsertAfter(flowBehaviorHandler.Last, _ilProcessor);

            _method.Body.ExceptionHandlers.Add(new ExceptionHandler(ExceptionHandlerType.Catch)
            {
                CatchType    = _creator.GetExceptionTypeReference(),
                TryStart     = instructionCallStart,
                TryEnd       = tryLeaveInstruction.Next,
                HandlerStart = tryLeaveInstruction.Next,
                HandlerEnd   = flowBehaviorHandler.Last.Next
            });
        }
Пример #2
0
        public void Weave(
            ModuleDefinition module,
            MethodDefinition method,
            IEnumerable <AspectInfo> aspectInfos)
        {
            var usableAspects = aspectInfos
                                .Select(x => new
            {
                Aspect        = x,
                AspectMethods = GetUsedAspectMethods(x.AspectAttribute.AttributeType)
            })
                                .Where(x => x.AspectMethods != AspectMethods.None)
                                .ToList();

            if (usableAspects.Count == 0)
            {
                return;
            }

            var hasMultipleAspects = usableAspects.Count > 1;

            var clonedMethod = CloneMethod(method);

            method.DeclaringType.Methods.Add(clonedMethod);

            // redirect source call
            ClearMethod(method);

            var ilProcessor = method.Body.GetILProcessor();
            var creator     = new InstructionBlockChainCreator(method, module);
            var arguments   = creator.CreateMethodArgumentsArray();

            arguments.Append(ilProcessor);

            var executionArgs = creator.CreateMethodExecutionArgsInstance(
                arguments,
                usableAspects.First().Aspect.AspectAttribute.AttributeType);

            executionArgs.Append(ilProcessor);

            // create aspect instance
            var aspectInstances = new Dictionary <AspectInfo, NamedInstructionBlockChain>();
            var tagVariables    = new Dictionary <AspectInfo, VariableDefinition>();

            foreach (var aspect in usableAspects)
            {
                var instance = creator.CreateAspectInstance(aspect.Aspect.AspectAttribute);
                instance.Append(ilProcessor);

                if (hasMultipleAspects)
                {
                    var tagVariable = creator.CreateObjectVariable();
                    method.Body.Variables.Add(tagVariable.Variable);
                    tagVariables.Add(aspect.Aspect, tagVariable.Variable);
                }

                aspectInstances.Add(aspect.Aspect, instance);
            }

            //OnEntries
            foreach (var aspect in usableAspects.Where(x => x.AspectMethods.HasFlag(AspectMethods.OnEntry)))
            {
                var aspectInstance = aspectInstances[aspect.Aspect];
                var call           = creator.CallAspectOnEntry(aspectInstance, executionArgs);
                call.Append(ilProcessor);

                if (hasMultipleAspects)
                {
                    var tagVariable = tagVariables[aspect.Aspect];
                    var save        = creator.SaveMethodExecutionArgsTagToVariable(executionArgs, tagVariable);
                    save.Append(ilProcessor);
                }
            }

            // call original method
            VariableDefinition thisVariable = null;

            if (!method.IsStatic)
            {
                var thisVariableBlock = creator.CreateThisVariable(method.DeclaringType);
                thisVariableBlock.Append(ilProcessor);
                thisVariable = thisVariableBlock.Variable;
            }

            var hasReturnValue = !InstructionBlockCreator.IsVoid(method.ReturnType);
            var returnValue    = hasReturnValue
                ? creator.CreateVariable(method.ReturnType)
                : null;
            var callSourceMethod = creator.CallMethodWithLocalParameters(
                method,
                clonedMethod,
                thisVariable,
                returnValue?.Variable);

            callSourceMethod.Append(ilProcessor);
            var instructionCallStart = callSourceMethod.First;
            var instructionCallEnd   = callSourceMethod.Last;

            var onExitAspects = usableAspects
                                .Where(x => x.AspectMethods.HasFlag(AspectMethods.OnExit))
                                .Reverse()
                                .ToList();

            Instruction instructionAfterCall = null;

            if (hasReturnValue && onExitAspects.Any())
            {
                var loadReturnValue = creator.LoadValueOnStack(returnValue);

                var setMethodExecutionArgsReturnValue = creator.SetMethodExecutionArgsReturnValue(
                    executionArgs,
                    loadReturnValue);
                setMethodExecutionArgsReturnValue.Append(ilProcessor);

                instructionAfterCall = setMethodExecutionArgsReturnValue.First;
            }

            // OnExit
            foreach (var aspect in onExitAspects)
            {
                if (hasMultipleAspects)
                {
                    var tagVariable = tagVariables[aspect.Aspect];
                    var load        = creator.LoadMethodExecutionArgsTagFromVariable(executionArgs,
                                                                                     tagVariable);
                    load.Append(ilProcessor);
                }

                var aspectInstance = aspectInstances[aspect.Aspect];
                var call           = creator.CallAspectOnExit(aspectInstance, executionArgs);
                call.Append(ilProcessor);
            }

            // return
            if (hasReturnValue)
            {
                var load = creator.LoadValueOnStack(returnValue);
                load.Append(ilProcessor);
            }

            var returnCall = creator.CreateReturn();

            returnCall.Append(ilProcessor);

            // add exception handling
            var onExceptionAspects = usableAspects
                                     .Where(x => x.AspectMethods.HasFlag(AspectMethods.OnException))
                                     .Reverse()
                                     .ToList();

            if (onExceptionAspects.Any())
            {
                var realInstructionAfterCall = instructionAfterCall ?? instructionCallEnd.Next;
                var tryLeaveInstruction      = Instruction.Create(OpCodes.Leave, realInstructionAfterCall);
                ilProcessor.InsertAfter(instructionCallEnd, tryLeaveInstruction);

                var exception = creator.SaveThrownException();
                var exceptionHandlerCurrent = exception.InsertAfter(tryLeaveInstruction, ilProcessor);

                var pushException = creator.LoadValueOnStack(exception);
                exceptionHandlerCurrent = pushException.InsertAfter(exceptionHandlerCurrent, ilProcessor);

                var setExceptionFromStack =
                    creator.SetMethodExecutionArgsExceptionFromStack(executionArgs);
                exceptionHandlerCurrent = setExceptionFromStack.InsertAfter(exceptionHandlerCurrent, ilProcessor);

                foreach (var onExceptionAspect in onExceptionAspects)
                {
                    if (hasMultipleAspects)
                    {
                        var tagVariable = tagVariables[onExceptionAspect.Aspect];
                        var load        = creator.LoadMethodExecutionArgsTagFromVariable(executionArgs,
                                                                                         tagVariable);
                        exceptionHandlerCurrent = load.InsertAfter(exceptionHandlerCurrent, ilProcessor);
                    }

                    var aspectInstance        = aspectInstances[onExceptionAspect.Aspect];
                    var callAspectOnException =
                        creator.CallAspectOnException(aspectInstance, executionArgs);
                    callAspectOnException.InsertAfter(exceptionHandlerCurrent, ilProcessor);
                    exceptionHandlerCurrent = callAspectOnException.Last;
                }

                var pushException2 = creator.LoadValueOnStack(exception);
                exceptionHandlerCurrent = pushException2.InsertAfter(exceptionHandlerCurrent, ilProcessor);

                ////var catchLeaveInstruction = Instruction.Create(OpCodes.Leave, realInstructionAfterCall);
                var catchLastInstruction = Instruction.Create(OpCodes.Throw);
                ilProcessor.InsertAfter(exceptionHandlerCurrent, catchLastInstruction);

                method.Body.ExceptionHandlers.Add(new ExceptionHandler(ExceptionHandlerType.Catch)
                {
                    CatchType    = creator.GetExceptionTypeReference(),
                    TryStart     = instructionCallStart,
                    TryEnd       = tryLeaveInstruction.Next,
                    HandlerStart = tryLeaveInstruction.Next,
                    HandlerEnd   = catchLastInstruction.Next
                });
            }

            // add DebuggerStepThrough attribute to avoid compiler searching for
            // non existing soure code for weaved il code
            var attributeCtor = creator.GetDebuggerStepThroughAttributeCtorReference();

            method.CustomAttributes.Add(new CustomAttribute(attributeCtor));

            method.Body.InitLocals = true;
            method.Body.Optimize();
            Catel.Fody.CecilExtensions.UpdateDebugInfo(method);

            clonedMethod.Body.InitLocals = true;
            clonedMethod.Body.Optimize();
            Catel.Fody.CecilExtensions.UpdateDebugInfo(clonedMethod);

            WeaveCounter++;
        }
Пример #3
0
        public void Weave(
            MethodDefinition method,
            CustomAttribute aspect,
            AspectMethods overriddenAspectMethods,
            ModuleDefinition moduleDefinition,
            TypeReference type,
            byte[] unweavedAssembly)
        {
            if (overriddenAspectMethods == AspectMethods.None)
            {
                return;
            }

            if (overriddenAspectMethods.HasFlag(AspectMethods.CompileTimeValidate))
            {
                var      asm          = AppDomain.CurrentDomain.Load(unweavedAssembly);
                string   methodName   = method.Name;
                string[] methodParams = method.Parameters.Select(p => p.ParameterType.FullName).ToArray();
                string[] ctorParams   = aspect.Constructor.Parameters.Select(p => p.ParameterType.FullName).ToArray();
                try
                {
                    var typeInfo = asm.GetTypes().FirstOrDefault(t => t.FullName == type.FullName);
                    if (typeInfo == null)
                    {
                        throw new InvalidOperationException(String.Format("Could not find type '{0}'.", type.FullName));
                    }

                    Type[] parameters = methodParams.Select(Type.GetType).ToArray();
                    var    methodInfo = typeInfo.GetMethod(methodName, System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Instance, null, parameters, new ParameterModifier[0]);

                    Type aspectType = asm.GetTypes().FirstOrDefault(t => t.FullName == aspect.AttributeType.FullName);
                    var  ctorInfo   = aspectType.GetConstructor(ctorParams.Select(Type.GetType).ToArray());
                    if (ctorInfo == null)
                    {
                        throw new InvalidOperationException("Could not find constructor for aspect.");
                    }

                    object[] ctorArgs       = GetRuntimeAttributeArgs(aspect.ConstructorArguments);
                    var      aspectInstance = Activator.CreateInstance(aspectType, ctorArgs) as OnMethodBoundaryAspect;
                    if (aspectInstance == null)
                    {
                        throw new InvalidOperationException("Could not create aspect.");
                    }

                    foreach (var fieldSetter in aspect.Fields)
                    {
                        var field = aspectType.GetField(fieldSetter.Name);
                        if (field == null)
                        {
                            throw new InvalidOperationException(String.Format("Could not find field named {0}", fieldSetter.Name));
                        }
                        field.SetValue(aspectInstance, fieldSetter.Argument.Value);
                    }

                    foreach (var propSetter in aspect.Properties)
                    {
                        var prop = aspectType.GetProperty(propSetter.Name);
                        if (prop == null)
                        {
                            throw new InvalidOperationException(String.Format("Could not find property named {0}", propSetter.Name));
                        }
                        prop.SetValue(aspectInstance, propSetter.Argument.Value);
                    }

                    if (!aspectInstance.CompileTimeValidate(methodInfo))
                    {
                        return;
                    }
                }
                catch (Exception e)
                {
                    throw new InvalidOperationException("Error while trying to compile-time validate.", e);
                }
            }

            var creator = new InstructionBlockChainCreator(method, aspect.AttributeType, moduleDefinition, WeaveCounter);

            _methodBodyChanger = new MethodBodyPatcher(method.Name, method);
            var saveReturnValue = creator.SaveReturnValue();
            var loadReturnValue = creator.LoadValueOnStack(saveReturnValue);

            _methodBodyChanger.Unify(saveReturnValue, loadReturnValue);

            if (WeaveCounter == 0)
            {
                _createArgumentsArray = creator.CreateMethodArgumentsArray();
            }

            var createMethodExecutionArgsInstance = creator.CreateMethodExecutionArgsInstance(_createArgumentsArray, type);

            _methodBodyChanger.AddCreateMethodExecutionArgs(createMethodExecutionArgsInstance);

            var createAspectInstance = creator.LoadAspectInstance(aspect, type);

            if (overriddenAspectMethods.HasFlag(AspectMethods.OnEntry))
            {
                var callAspectOnEntry = creator.CallAspectOnEntry(createAspectInstance,
                                                                  createMethodExecutionArgsInstance);
                var loadExecuteBodyVar = creator.LoadExecuteBodyVariable(createMethodExecutionArgsInstance, out NamedInstructionBlockChain executeBodyVar);
                executeBodyVar = creator.LoadValueOnStack(executeBodyVar);
                _methodBodyChanger.AddOnEntryCall(createAspectInstance, callAspectOnEntry, loadExecuteBodyVar, executeBodyVar);
            }

            if (overriddenAspectMethods.HasFlag(AspectMethods.OnExit))
            {
                var setMethodExecutionArgsReturnValue =
                    creator.SetMethodExecutionArgsReturnValue(createMethodExecutionArgsInstance, loadReturnValue);
                var callAspectOnExit = creator.CallAspectOnExit(createAspectInstance,
                                                                createMethodExecutionArgsInstance);

                var readReturnValue = creator.ReadReturnValue(createMethodExecutionArgsInstance, loadReturnValue);

                _methodBodyChanger.AddOnExitCall(createAspectInstance, callAspectOnExit,
                                                 setMethodExecutionArgsReturnValue, readReturnValue);
            }

            if (overriddenAspectMethods.HasFlag(AspectMethods.OnException))
            {
                var setMethodExecutionArgsExceptionFromStack =
                    creator.SetMethodExecutionArgsExceptionFromStack(createMethodExecutionArgsInstance);

                var callAspectOnException = creator.CallAspectOnException(createAspectInstance,
                                                                          createMethodExecutionArgsInstance);
                _methodBodyChanger.AddOnExceptionCall(createAspectInstance, callAspectOnException,
                                                      setMethodExecutionArgsExceptionFromStack);
            }

            if (_methodBodyChanger.HasMultipleReturnAndEndsWithThrow)
            {
                _methodBodyChanger.ReplaceThrowAtEndOfRealBodyWithReturn();
            }
            else if (_methodBodyChanger.EndsWithThrow)
            {
                var saveThrownException  = creator.SaveThrownException();
                var loadThrownException  = creator.LoadValueOnStack(saveThrownException);
                var loadThrownException2 = creator.LoadValueOnStack(saveThrownException);
                _methodBodyChanger.FixThrowAtEndOfRealBody(
                    saveThrownException,
                    loadThrownException,
                    loadThrownException2);
            }

            _methodBodyChanger.OptimizeBody();

            Catel.Fody.CecilExtensions.UpdateDebugInfo(method);

            WeaveCounter++;
        }
Пример #4
0
        public void Weave(
            MethodDefinition method,
            CustomAttribute aspect,
            AspectMethods overriddenAspectMethods,
            ModuleDefinition moduleDefinition)
        {
            if (overriddenAspectMethods == AspectMethods.None)
            {
                return;
            }

            var creator = new InstructionBlockChainCreator(method, aspect.AttributeType, moduleDefinition, WeaveCounter);

            _methodBodyChanger = new MethodBodyPatcher(method.Name, method);
            var saveReturnValue = creator.SaveReturnValue();
            var loadReturnValue = creator.LoadValueOnStack(saveReturnValue);

            _methodBodyChanger.Unify(saveReturnValue, loadReturnValue);

            if (WeaveCounter == 0)
            {
                _createArgumentsArray = creator.CreateMethodArgumentsArray();
            }

            var createMethodExecutionArgsInstance = creator.CreateMethodExecutionArgsInstance(_createArgumentsArray);

            _methodBodyChanger.AddCreateMethodExecutionArgs(createMethodExecutionArgsInstance);

            var createAspectInstance = creator.CreateAspectInstance(aspect);

            if (overriddenAspectMethods.HasFlag(AspectMethods.OnEntry))
            {
                var callAspectOnEntry = creator.CallAspectOnEntry(createAspectInstance,
                                                                  createMethodExecutionArgsInstance);
                _methodBodyChanger.AddOnEntryCall(createAspectInstance, callAspectOnEntry);
            }

            if (overriddenAspectMethods.HasFlag(AspectMethods.OnExit))
            {
                var setMethodExecutionArgsReturnValue =
                    creator.SetMethodExecutionArgsReturnValue(createMethodExecutionArgsInstance, loadReturnValue);
                var callAspectOnExit = creator.CallAspectOnExit(createAspectInstance,
                                                                createMethodExecutionArgsInstance);
                _methodBodyChanger.AddOnExitCall(createAspectInstance, callAspectOnExit,
                                                 setMethodExecutionArgsReturnValue);
            }

            if (overriddenAspectMethods.HasFlag(AspectMethods.OnException))
            {
                var setMethodExecutionArgsExceptionFromStack =
                    creator.SetMethodExecutionArgsExceptionFromStack(createMethodExecutionArgsInstance);

                var callAspectOnException = creator.CallAspectOnException(createAspectInstance,
                                                                          createMethodExecutionArgsInstance);
                _methodBodyChanger.AddOnExceptionCall(createAspectInstance, callAspectOnException,
                                                      setMethodExecutionArgsExceptionFromStack);
            }

            if (_methodBodyChanger.EndsWithThrow)
            {
                var saveThrownException  = creator.SaveThrownException();
                var loadThrownException  = creator.LoadValueOnStack(saveThrownException);
                var loadThrownException2 = creator.LoadValueOnStack(saveThrownException);
                _methodBodyChanger.FixThrowAtEndOfRealBody(
                    saveThrownException,
                    loadThrownException,
                    loadThrownException2);
            }

            _methodBodyChanger.OptimizeBody();

            WeaveCounter++;
        }
        public void Weave(
            MethodDefinition method,
            CustomAttribute aspect,
            AspectMethods overriddenAspectMethods,
            ModuleDefinition moduleDefinition)
        {
            if (overriddenAspectMethods == AspectMethods.None)
                return;
            
            var creator = new InstructionBlockChainCreator(method, aspect.AttributeType, moduleDefinition, WeaveCounter);

            _methodBodyChanger = new MethodBodyPatcher(method.Name, method);
            var saveReturnValue = creator.SaveReturnValue();
            var loadReturnValue = creator.LoadValueOnStack(saveReturnValue);
            _methodBodyChanger.Unify(saveReturnValue, loadReturnValue);

            if (WeaveCounter == 0)
                _createArgumentsArray = creator.CreateMethodArgumentsArray();

            var createMethodExecutionArgsInstance = creator.CreateMethodExecutionArgsInstance(_createArgumentsArray);
            _methodBodyChanger.AddCreateMethodExecutionArgs(createMethodExecutionArgsInstance);

            var createAspectInstance = creator.CreateAspectInstance(aspect);
            if (overriddenAspectMethods.HasFlag(AspectMethods.OnEntry))
            {
                var callAspectOnEntry = creator.CallAspectOnEntry(createAspectInstance,
                    createMethodExecutionArgsInstance);
                _methodBodyChanger.AddOnEntryCall(createAspectInstance, callAspectOnEntry);
            }

            if (overriddenAspectMethods.HasFlag(AspectMethods.OnExit))
            {
                var setMethodExecutionArgsReturnValue =
                    creator.SetMethodExecutionArgsReturnValue(createMethodExecutionArgsInstance, loadReturnValue);
                var callAspectOnExit = creator.CallAspectOnExit(createAspectInstance,
                    createMethodExecutionArgsInstance);
                _methodBodyChanger.AddOnExitCall(createAspectInstance, callAspectOnExit,
                    setMethodExecutionArgsReturnValue);
            }

            if (overriddenAspectMethods.HasFlag(AspectMethods.OnException))
            {
                var setMethodExecutionArgsExceptionFromStack =
                    creator.SetMethodExecutionArgsExceptionFromStack(createMethodExecutionArgsInstance);

                var callAspectOnException = creator.CallAspectOnException(createAspectInstance,
                    createMethodExecutionArgsInstance);
                _methodBodyChanger.AddOnExceptionCall(createAspectInstance, callAspectOnException,
                    setMethodExecutionArgsExceptionFromStack);
            }

            if (_methodBodyChanger.EndsWithThrow)
            {
                var saveThrownException = creator.SaveThrownException();
                var loadThrownException = creator.LoadValueOnStack(saveThrownException);
                var loadThrownException2 = creator.LoadValueOnStack(saveThrownException);
                _methodBodyChanger.FixThrowAtEndOfRealBody(
                    saveThrownException, 
                    loadThrownException,
                    loadThrownException2);
            }

            _methodBodyChanger.OptimizeBody();

            WeaveCounter++;
        }