public override InstructionBlockChain CreateAspectInstance() { var aspectTypeReference = _module.ImportReference(Info.AspectAttribute.AttributeType); _aspectField = _module.ImportReference(_stateMachine.AddPublicInstanceField(aspectTypeReference)); var loadMachine = new VariablePersistable(_stateMachineLocal).Load(true); var newObjectAspectBlock = _creator.CreateAndNewUpAspect(Info.AspectAttribute); var loadOnStack = new InstructionBlock("Load on stack", Instruction.Create(OpCodes.Ldloc, newObjectAspectBlock.Variable)); var storeField = new InstructionBlock("Store Field", Instruction.Create(OpCodes.Stfld, _aspectField)); var newObjectAspectBlockChain = new InstructionBlockChain(); newObjectAspectBlockChain.Add(loadMachine); newObjectAspectBlockChain.Add(newObjectAspectBlock); newObjectAspectBlockChain.Add(loadOnStack); newObjectAspectBlockChain.Add(storeField); AspectPersistable = new FieldPersistable(new VariablePersistable(_stateMachineLocal), _aspectField); return(newObjectAspectBlockChain); }
public void Add(InstructionBlock block) { InstructionBlocks.Add(block); }
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 }); }
protected virtual void HandleBody( NamedInstructionBlockChain arguments, VariableDefinition returnValue, out Instruction instructionCallStart, out Instruction instructionCallEnd) { VariableDefinition thisVariable = null; if (!_method.IsStatic) { var thisVariableBlock = _creator.CreateThisVariable(_method.DeclaringType); thisVariableBlock.Append(_ilProcessor); thisVariable = thisVariableBlock.Variable; } InstructionBlockChain callSourceMethod; ILoadable[] args = null; var allowChangingInputArguments = _aspects.Any(x => x.Info.AllowChangingInputArguments); if (allowChangingInputArguments) { // get arguments from ExecutionArgs because they could have been changed in aspect code args = _method.Parameters .Select((x, i) => new ArrayElementLoadable(arguments.Variable, i, x, _method.Body.GetILProcessor(), _creator)) .Cast <ILoadable>() .ToArray(); callSourceMethod = _creator.CallMethodWithReturn( _clonedMethod, thisVariable == null ? null : new VariablePersistable(thisVariable), returnValue == null ? null : new VariablePersistable(returnValue), args); } else { callSourceMethod = _creator.CallMethodWithLocalParameters( _method, _clonedMethod, thisVariable == null ? null : new VariablePersistable(thisVariable), returnValue == null ? null : new VariablePersistable(returnValue)); } if (allowChangingInputArguments) { // write byref variables back for origin source method var copyBackInstructions = new List <Instruction>(); foreach (var parameter in _method.Parameters.Where(x => x.ParameterType.IsByReference)) { var arg = args[parameter.Index]; copyBackInstructions.Add(_ilProcessor.Create(OpCodes.Ldarg, parameter)); var loadBlock = arg.Load(false, true); copyBackInstructions.AddRange(loadBlock.Instructions); var storeOpCode = parameter.ParameterType.MetadataType.GetStIndCode(); copyBackInstructions.Add(_ilProcessor.Create(storeOpCode)); } if (copyBackInstructions.Any()) { var copyBackBlock = new InstructionBlock("Copy back ref values", copyBackInstructions); callSourceMethod.Add(copyBackBlock); } } callSourceMethod.Append(_ilProcessor); instructionCallStart = callSourceMethod.First; instructionCallEnd = callSourceMethod.Last; }
public NamedInstructionBlockChain CreateMethodExecutionArgsInstance( NamedInstructionBlockChain argumentsArrayChain, TypeReference anyAspectTypeDefinition) { // instance value var createThisVariableBlock = CreateThisVariable(); // MethodExecutionArgs instance var onEntryMethodTypeRef = anyAspectTypeDefinition.Resolve().BaseType.Resolve().Methods.Single(x => x.Name == "OnEntry"); var firstParameterType = onEntryMethodTypeRef.Parameters.Single().ParameterType; var methodExecutionArgsTypeRef = _moduleDefinition.ImportReference(firstParameterType); var methodExecutionArgsVariable = _creator.CreateVariable(methodExecutionArgsTypeRef); var newObjectMethodExecutionArgsBlock = _creator.NewObject( methodExecutionArgsVariable, methodExecutionArgsTypeRef, _moduleDefinition); InstructionBlock callSetInstanceBlock = null; if (!_method.IsStatic) { var methodExecutionArgsSetInstanceMethodRef = _referenceFinder.GetMethodReference(methodExecutionArgsTypeRef, md => md.Name == "set_Instance"); callSetInstanceBlock = _creator.CallVoidInstanceMethod(methodExecutionArgsSetInstanceMethodRef, new VariablePersistable(methodExecutionArgsVariable), new VariablePersistable(createThisVariableBlock.Variable)); } var methodExecutionArgsSetArgumentsMethodRef = _referenceFinder.GetMethodReference(methodExecutionArgsTypeRef, md => md.Name == "set_Arguments"); var callSetArgumentsBlock = _creator.CallVoidInstanceMethod(methodExecutionArgsSetArgumentsMethodRef, new VariablePersistable(methodExecutionArgsVariable), new VariablePersistable(argumentsArrayChain.Variable)); var methodBaseTypeRef = _referenceFinder.GetTypeReference(typeof(MethodBase)); var methodBaseVariable = _creator.CreateVariable(methodBaseTypeRef); var methodBaseGetCurrentMethod = _referenceFinder.GetMethodReference(methodBaseTypeRef, md => md.Name == "GetCurrentMethod"); var callGetCurrentMethodBlock = _creator.CallStaticMethod(methodBaseGetCurrentMethod, new VariablePersistable(methodBaseVariable)); var methodExecutionArgsSetMethodBaseMethodRef = _referenceFinder.GetMethodReference(methodExecutionArgsTypeRef, md => md.Name == "set_Method"); var callSetMethodBlock = _creator.CallVoidInstanceMethod(methodExecutionArgsSetMethodBaseMethodRef, new VariablePersistable(methodExecutionArgsVariable), new VariablePersistable(methodBaseVariable)); var newMethodExecutionArgsBlockChain = new NamedInstructionBlockChain(methodExecutionArgsVariable, methodExecutionArgsTypeRef); newMethodExecutionArgsBlockChain.Add(newObjectMethodExecutionArgsBlock); newMethodExecutionArgsBlockChain.Add(callSetArgumentsBlock); newMethodExecutionArgsBlockChain.Add(callGetCurrentMethodBlock); newMethodExecutionArgsBlockChain.Add(callSetMethodBlock); if (callSetInstanceBlock != null) { newMethodExecutionArgsBlockChain.Add(createThisVariableBlock); newMethodExecutionArgsBlockChain.Add(callSetInstanceBlock); } return(newMethodExecutionArgsBlockChain); }
private static List <Instruction> CreateMethodCallInstructions( MethodReference methodReference, ILoadable instance, IPersistable returnValue, params ILoadable[] arguments) { InstructionBlock loadVariableInstruction = null; if (instance != null) { loadVariableInstruction = instance.Load(true, false); } var loadArgumentsInstructions = new List <Instruction>(); var parameterCount = 0; foreach (var argument in arguments) { var paramIsByRef = methodReference.Parameters[parameterCount].ParameterType.IsByReference; loadArgumentsInstructions.AddRange(argument.Load(false, false).Instructions); var varType = argument.PersistedType; if (varType.IsByReference && !paramIsByRef) { varType = ((ByReferenceType)varType).ElementType; loadArgumentsInstructions.Add(Instruction.Create(OpCodes.Ldobj, varType)); } var parameter = methodReference.Parameters[parameterCount]; if (parameter.ParameterType.FullName != varType.FullName) { if (varType.IsValueType || varType.IsGenericParameter) { loadArgumentsInstructions.Add(Instruction.Create(OpCodes.Box, varType)); } } parameterCount++; } var methodDefinition = methodReference.Resolve(); var methodCallInstruction = Instruction.Create( methodDefinition.IsVirtual ? OpCodes.Callvirt : OpCodes.Call, methodReference); var methodReturnsVoid = IsVoid(methodDefinition.ReturnType); var returnValueShouldBeStored = (returnValue != null); List <Instruction> HandleReturnValue(List <Instruction> methodWork) { if (methodReturnsVoid && returnValueShouldBeStored) { throw new InvalidOperationException("Method has no return value"); } if (!methodReturnsVoid && !returnValueShouldBeStored) { methodWork.Add(Instruction.Create(OpCodes.Pop)); return(methodWork); } if (methodReturnsVoid && !returnValueShouldBeStored) { return(methodWork); } // Therefore, !methodReturnsVoid && returnValueShouldBeStored var castToType = returnValue.PersistedType; var castFromType = methodDefinition.ReturnType; if (castToType.FullName != castFromType.FullName) { if (castToType.IsByReference) { castToType = ((ByReferenceType)castToType).ElementType; } if (castFromType.IsByReference) { castFromType = ((ByReferenceType)castFromType).ElementType; } methodWork.AddRange(CastValueCurrentlyOnStack(castFromType, castToType)); } return(returnValue.Store(new InstructionBlock("", methodWork), castToType).Instructions.ToList()); } var instructions = new List <Instruction>(); if (loadVariableInstruction != null) { instructions.AddRange(loadVariableInstruction.Instructions); } instructions.AddRange(loadArgumentsInstructions); instructions.Add(methodCallInstruction); return(HandleReturnValue(instructions)); }
InstructionBlock IPersistable.Store(InstructionBlock loadNewValueOntoStack, TypeReference typeOnStack) => Persistable.Store(loadNewValueOntoStack, typeOnStack);
public NamedInstructionBlockChain CreateMethodExecutionArgsInstance(NamedInstructionBlockChain argumentsArrayChain, TypeReference weavingType) { // instance value var objectType = _referenceFinder.GetTypeReference(typeof(object)); var instanceVariable = _creator.CreateVariable(objectType); var createThisVariableBlock = _creator.CreateThisVariable(instanceVariable, objectType); // MethodExecutionArgs instance var onEntryMethodTypeRef = _aspectTypeDefinition.Resolve().BaseType.Resolve().Methods.Single(x => x.Name == "OnEntry"); var firstParameterType = onEntryMethodTypeRef.Parameters.Single().ParameterType; var methodExecutionArgsTypeRef = _moduleDefinition.ImportReference(firstParameterType); var methodExecutionArgsVariable = _creator.CreateVariable(methodExecutionArgsTypeRef); var newObjectMethodExecutionArgsBlock = _creator.NewObject( methodExecutionArgsVariable, methodExecutionArgsTypeRef, _moduleDefinition, _aspectCounter); InstructionBlock callSetInstanceBlock = null; if (!_method.IsStatic) { var methodExecutionArgsSetInstanceMethodRef = _referenceFinder.GetMethodReference(methodExecutionArgsTypeRef, md => md.Name == "set_Instance"); callSetInstanceBlock = _creator.CallVoidInstanceMethod(methodExecutionArgsVariable, methodExecutionArgsSetInstanceMethodRef, instanceVariable); } var methodExecutionArgsSetArgumentsMethodRef = _referenceFinder.GetMethodReference(methodExecutionArgsTypeRef, md => md.Name == "set_Arguments"); var callSetArgumentsBlock = _creator.CallVoidInstanceMethod(methodExecutionArgsVariable, methodExecutionArgsSetArgumentsMethodRef, argumentsArrayChain.Variable); var methodInfoField = _creator.StoreMethodInfoInStaticField(_method, weavingType); var methodBaseVariable = _creator.CreateVariable(_referenceFinder.GetTypeReference(typeof(MethodInfo))); var callGetCurrentMethodBlock = new InstructionBlock("CallGetCurrentMethod: ", Instruction.Create(OpCodes.Ldsfld, methodInfoField), Instruction.Create(OpCodes.Stloc, methodBaseVariable)); var methodExecutionArgsSetMethodBaseMethodRef = _referenceFinder.GetMethodReference(methodExecutionArgsTypeRef, md => md.Name == "set_Method"); var callSetMethodBlock = _creator.CallVoidInstanceMethod(methodExecutionArgsVariable, methodExecutionArgsSetMethodBaseMethodRef, methodBaseVariable); var newMethodExectionArgsBlockChain = new NamedInstructionBlockChain(methodExecutionArgsVariable, methodExecutionArgsTypeRef); newMethodExectionArgsBlockChain.Add(newObjectMethodExecutionArgsBlock); newMethodExectionArgsBlockChain.Add(callSetArgumentsBlock); newMethodExectionArgsBlockChain.Add(callGetCurrentMethodBlock); newMethodExectionArgsBlockChain.Add(callSetMethodBlock); if (callSetInstanceBlock != null) { newMethodExectionArgsBlockChain.Add(createThisVariableBlock); newMethodExectionArgsBlockChain.Add(callSetInstanceBlock); } return(newMethodExectionArgsBlockChain); }