public MethodWeaver(ModuleDefinition module, MethodDefinition method, IList <AspectData> aspects) { _module = module; _method = method; _creator = new InstructionBlockChainCreator(method, module); _ilProcessor = _method.Body.GetILProcessor(); _aspects = aspects; }
public AspectData(AspectInfo info, AspectMethods methods, MethodDefinition method, ModuleDefinition module) { Info = info; AspectMethods = methods; _method = method; _module = module; _referenceFinder = new ReferenceFinder(module); _creator = new InstructionBlockChainCreator(method, module); }
public ArrayElementLoadable( VariableDefinition arrayVariableDefinition, int index, ParameterDefinition parameterDefinition, ILProcessor methodProcessor, InstructionBlockChainCreator creator) { _arrayVariableDefinition = arrayVariableDefinition; _index = index; _parameter = parameterDefinition; _processor = methodProcessor; _creator = creator; }
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++; }
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, 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++; }
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++; }