Esempio n. 1
0
        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;
            }
        }