public InstructionBlockChain IfFlowBehaviorIsAnyOf(Func <TypeReference, VariableDefinition> variableFactory, ILoadable args, Instruction nextInstruction, InstructionBlockChain thenBody, params int[] behaviors) { var typeRef = args.PersistedType.Resolve(); var getFlowBehavior = _referenceFinder.GetMethodReference(typeRef, m => m.Name == "get_FlowBehavior"); var flowBehaviorLocal = new VariablePersistable(variableFactory(_moduleDefinition.ImportReference(getFlowBehavior.ReturnType))); var flowBehaviorHandler = CallMethodWithReturn(getFlowBehavior, args, flowBehaviorLocal); if (behaviors.Length == 0) { return(flowBehaviorHandler); } for (var i = 0; i < behaviors.Length - 1; ++i) { flowBehaviorHandler.Add(flowBehaviorLocal.Load(false, false)); flowBehaviorHandler.Add(new InstructionBlock("FlowBehavior", Instruction.Create(OpCodes.Ldc_I4, behaviors[i]))); flowBehaviorHandler.Add(new InstructionBlock("If == then goto the 'then' block", Instruction.Create(OpCodes.Beq_S, thenBody.First))); } flowBehaviorHandler.Add(flowBehaviorLocal.Load(false, false)); flowBehaviorHandler.Add(new InstructionBlock("FlowBehavior", Instruction.Create(OpCodes.Ldc_I4, behaviors[behaviors.Length - 1]))); flowBehaviorHandler.Add(new InstructionBlock("If != then skip", Instruction.Create(OpCodes.Bne_Un, nextInstruction))); flowBehaviorHandler.Add(thenBody); return(flowBehaviorHandler); }
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); }
protected override void WeaveOnException(IList <AspectData> allAspects, Instruction instructionCallStart, Instruction instructionCallEnd, Instruction instructionAfterCall, IPersistable returnValue) { var handler = _moveNext.Body.ExceptionHandlers.FirstOrDefault(IsStateMachineCatchBlock); if (handler == null) { throw new InvalidOperationException($"Async state machine for {_method.FullName} did not catch exceptions in the expected way."); } var exceptionLocal = handler.HandlerStart.GetLocalStoredByInstruction(_moveNext.Body.Variables); Instruction firstInstructionToSetException = GetFirstInstructionToSetException(handler, out var setResultMethod, out var loadBuilder); Instruction exceptionHandlerCurrent = firstInstructionToSetException.Previous; // Need to start inserting before SetException Instruction retInstruction = handler.HandlerEnd; var processor = _moveNext.Body.GetILProcessor(); Instruction gotoSetException = Instruction.Create(OpCodes.Br, firstInstructionToSetException); new InstructionBlock("else", gotoSetException).InsertAfter(exceptionHandlerCurrent, processor); // Need to replace leave.s with leave since we are adding instructions // between here and the destination which may invalidate short form labels. for (int i = 0; _moveNext.Body.Instructions[i] != handler.HandlerStart; ++i) { var inst = _moveNext.Body.Instructions[i]; if (inst.OpCode == OpCodes.Leave_S) { _moveNext.Body.Instructions.RemoveAt(i); _moveNext.Body.Instructions.Insert(i, Instruction.Create(OpCodes.Leave, inst.Operand as Instruction)); } } foreach (var onExceptionAspect in allAspects .Where(a => (a.AspectMethods & AspectMethods.OnException) != 0) .Reverse() .OfType <AspectDataOnAsyncMethod>()) { if (HasMultipleAspects) { var load = onExceptionAspect.LoadTagInMoveNext(ExecutionArgs); exceptionHandlerCurrent = load.InsertAfter(exceptionHandlerCurrent, processor); } var callAspectOnException = onExceptionAspect.CallOnExceptionInMoveNext(ExecutionArgs, exceptionLocal); if (setResultMethod.Parameters.Count == 1) { returnValue = new VariablePersistable(new InstructionBlockCreator(_moveNext, new ReferenceFinder(_module)).CreateVariable( ((GenericInstanceType)setResultMethod.DeclaringType).GenericArguments[0])); } var thenBody = new InstructionBlockChain(); if (setResultMethod.Parameters.Count == 1) { thenBody.Add(_creator.ReadReturnValue(onExceptionAspect.GetMoveNextExecutionArgs(ExecutionArgs), returnValue)); } thenBody.Add(loadBuilder.Clone()); if (setResultMethod.Parameters.Count == 1) { thenBody.Add(returnValue.Load(false)); } thenBody.Add(new InstructionBlock("Call SetResult", Instruction.Create(OpCodes.Call, setResultMethod))); thenBody.Add(new InstructionBlock("Leave peacefully", Instruction.Create(OpCodes.Leave, handler.HandlerEnd))); var nop = Instruction.Create(OpCodes.Nop); callAspectOnException.Add(_creator.IfFlowBehaviorIsAnyOf( new InstructionBlockCreator(_moveNext, new ReferenceFinder(_module)).CreateVariable, onExceptionAspect.GetMoveNextExecutionArgs(ExecutionArgs), nop, thenBody, 1, 3)); callAspectOnException.Add(new InstructionBlock("", nop)); callAspectOnException.InsertAfter(exceptionHandlerCurrent, processor); exceptionHandlerCurrent = callAspectOnException.Last; } }