Beispiel #1
0
        public override void LeaveTryStatement(TryStatement node)
        {
            TryStatementInfo info = _tryStatementStack.Pop();

            if (info._containsYield)
            {
                ReplaceCurrentNode(info._replacement);
                TryStatementInfo currentTry = (_tryStatementStack.Count > 0) ? _tryStatementStack.Peek() : null;
                info._replacement.Add(node.ProtectedBlock);
                if (currentTry != null)
                {
                    ConvertTryStatement(currentTry);
                    info._replacement.Add(SetStateTo(currentTry._stateNumber));
                }
                else
                {
                    // leave try block, reset state to prevent ensure block from being called again
                    info._replacement.Add(SetStateTo(_finishedStateNumber));
                }
                BooMethodBuilder ensureMethod = _enumerator.AddMethod("$ensure" + info._stateNumber, TypeSystemServices.VoidType, TypeMemberModifiers.Private);
                ensureMethod.Body.Add(info._statement.EnsureBlock);
                info._ensureMethod = ensureMethod.Entity;
                info._replacement.Add(CallMethodOnSelf(ensureMethod.Entity));
                _convertedTryStatements.Add(info);
            }
        }
Beispiel #2
0
        public override bool EnterTryStatement(TryStatement node)
        {
            TryStatementInfo info = new TryStatementInfo();

            info._statement = node;
            if (_tryStatementStack.Count > 0)
            {
                info._parent = _tryStatementStack.Peek();
            }
            _tryStatementStack.Push(info);
            return(true);
        }
Beispiel #3
0
        IMethod CreateDisposeMethod()
        {
            BooMethodBuilder mn = _enumerator.AddVirtualMethod("Dispose", TypeSystemServices.VoidType);

            mn.Method.LexicalInfo = this.LexicalInfo;

            LabelStatement noEnsure = CodeBuilder.CreateLabel(_generator.Method, "noEnsure").LabelStatement;

            mn.Body.Add(noEnsure);
            mn.Body.Add(SetStateTo(_finishedStateNumber));
            mn.Body.Add(new ReturnStatement());

            // Create a section calling all ensure methods for each converted try block
            LabelStatement[] disposeLabels = new LabelStatement[_labels.Count];
            for (int i = 0; i < _convertedTryStatements.Count; i++)
            {
                TryStatementInfo info = _convertedTryStatements[i];
                disposeLabels[info._stateNumber] = CodeBuilder.CreateLabel(_generator.Method, "$ensure_" + info._stateNumber).LabelStatement;
                mn.Body.Add(disposeLabels[info._stateNumber]);
                mn.Body.Add(SetStateTo(_finishedStateNumber));
                Block block = mn.Body;
                while (info._parent != null)
                {
                    TryStatement ts = new TryStatement();
                    block.Add(ts);
                    ts.ProtectedBlock.Add(CallMethodOnSelf(info._ensureMethod));
                    block = ts.EnsureBlock = new Block();
                    info  = info._parent;
                }
                block.Add(CallMethodOnSelf(info._ensureMethod));
                mn.Body.Add(new ReturnStatement());
            }

            // now map the labels of the suspended states to the labels we just created
            for (int i = 0; i < _labels.Count; i++)
            {
                if (_tryStatementInfoForLabels[i] == null)
                {
                    disposeLabels[i] = noEnsure;
                }
                else
                {
                    disposeLabels[i] = disposeLabels[_tryStatementInfoForLabels[i]._stateNumber];
                }
            }

            mn.Body.Insert(0, CodeBuilder.CreateSwitch(
                               this.LexicalInfo,
                               CodeBuilder.CreateMemberReference(_state),
                               disposeLabels));
            return(mn.Entity);
        }
Beispiel #4
0
        void ConvertTryStatement(TryStatementInfo currentTry)
        {
            if (currentTry._containsYield)
            {
                return;
            }
            currentTry._containsYield = true;
            currentTry._stateNumber   = _labels.Count;
            Block tryReplacement = new Block();

            //tryReplacement.Add(CreateLabel(tryReplacement));
            // when the MoveNext() is called while the enumerator is still in running state, don't jump to the
            // try block, but handle it like MoveNext() calls when the enumerator is in the finished state.
            _labels.Add(_labels[_finishedStateNumber]);
            _tryStatementInfoForLabels.Add(currentTry);
            tryReplacement.Add(SetStateTo(currentTry._stateNumber));
            currentTry._replacement = tryReplacement;
        }
Beispiel #5
0
        override public void LeaveYieldStatement(YieldStatement node)
        {
            TryStatementInfo currentTry = (_tryStatementStack.Count > 0) ? _tryStatementStack.Peek() : null;

            if (currentTry != null)
            {
                ConvertTryStatement(currentTry);
            }
            Block block = new Block();

            block.Add(
                new ReturnStatement(
                    node.LexicalInfo,
                    CreateYieldInvocation(node.LexicalInfo, _labels.Count, node.Expression),
                    null));
            block.Add(CreateLabel(node));
            // setting the state back to the "running" state not required, as that state has the same ensure blocks
            // as the state we are currently in.
//			if (currentTry != null) {
//				block.Add(SetStateTo(currentTry._stateNumber));
//			}
            ReplaceCurrentNode(block);
        }
		void ConvertTryStatement(TryStatementInfo currentTry)
		{
			if (currentTry._containsYield)
				return;
			currentTry._containsYield = true;
			currentTry._stateNumber = _labels.Count;
			Block tryReplacement = new Block();
			//tryReplacement.Add(CreateLabel(tryReplacement));
			// when the MoveNext() is called while the enumerator is still in running state, don't jump to the
			// try block, but handle it like MoveNext() calls when the enumerator is in the finished state.
			_labels.Add(_labels[_finishedStateNumber]);
			_tryStatementInfoForLabels.Add(currentTry);
			tryReplacement.Add(SetStateTo(currentTry._stateNumber));
			currentTry._replacement = tryReplacement;
		}
		public override bool EnterTryStatement(TryStatement node)
		{
			TryStatementInfo info = new TryStatementInfo();
			info._statement = node;
			if (_tryStatementStack.Count > 0)
				info._parent = _tryStatementStack.Peek();
			_tryStatementStack.Push(info);
			return true;
		}
Beispiel #8
0
        private Block VisitAwaitExpression(AwaitExpression node, Expression resultPlace)
        {
            _seenAwait = true;
            var expression = Visit(node.BaseExpression);

            resultPlace = Visit(resultPlace);
            var getAwaiter = (IMethod)node["$GetAwaiter"];
            var getResult  = (IMethod)node["$GetResult"];

            if (getAwaiter == null)
            {
                var resolveList = new List <IEntity>();
                if (expression.ExpressionType.Resolve(resolveList, "GetAwaiter", EntityType.Method))
                {
                    getAwaiter = resolveList.Cast <IMethod>().First(m => m.GetParameters().Length == 0 && m.IsPublic);
                }
                else
                {
                    throw CompilerErrorFactory.MissingGetAwaiter(expression);
                }
                getResult = getAwaiter.ReturnType.GetMembers().OfType <IMethod>().Single(m => m.Name.Equals("GetResult"));
            }
            Debug.Assert(getAwaiter != null && getResult != null);
            var isCompletedProp = getAwaiter.ReturnType.GetMembers().OfType <IProperty>().SingleOrDefault(p => p.Name.Equals("IsCompleted"));

            if (isCompletedProp == null)
            {
                var resolveList = new List <IEntity>();
                if (getAwaiter.ReturnType.Resolve(resolveList, "IsCompleted", EntityType.Property))
                {
                    isCompletedProp = resolveList.Cast <IProperty>().First(p => p.GetParameters().Length == 0 && p.IsPublic);
                }
                if (isCompletedProp == null)
                {
                    throw new ArgumentException("No valid IsCompleted property found");
                }
            }
            var   isCompletedMethod = isCompletedProp.GetGetMethod();
            IType type;

            if (IsCustomTaskType(expression.ExpressionType))
            {
                type = getResult.ReturnType;
            }
            else
            {
                type = expression.ExpressionType.ConstructedInfo == null
                                ? TypeSystemServices.VoidType
                                : expression.ExpressionType.ConstructedInfo.GenericArguments[0];
            }

            // The awaiter temp facilitates EnC method remapping and thus have to be long-lived.
            // It transfers the awaiter objects from the old version of the MoveNext method to the new one.
            var awaiterType = getAwaiter.ReturnType;
            var awaiterTemp = CodeBuilder.DeclareTempLocal(_moveNext.Method, awaiterType);

            var getAwaiterInvocation = getAwaiter.IsExtension ?
                                       CodeBuilder.CreateMethodInvocation(getAwaiter, expression) :
                                       CodeBuilder.CreateMethodInvocation(expression, getAwaiter);
            var awaitIfIncomplete = new Block(
                // temp $awaiterTemp = <expr>.GetAwaiter();
                new ExpressionStatement(
                    CodeBuilder.CreateAssignment(
                        CodeBuilder.CreateLocalReference(awaiterTemp),
                        getAwaiterInvocation)),

                // if(!($awaiterTemp.IsCompleted)) { ... }
                new IfStatement(
                    new UnaryExpression(
                        UnaryOperatorType.LogicalNot,
                        GenerateGetIsCompleted(awaiterTemp, isCompletedMethod)),
                    GenerateAwaitForIncompleteTask(awaiterTemp),
                    null));

            TryStatementInfo currentTry = _tryStatementStack.Count > 0 ? _tryStatementStack.Peek() : null;

            if (currentTry != null)
            {
                ConvertTryStatement(currentTry);
            }

            var getResultCall = CodeBuilder.CreateMethodInvocation(
                CodeBuilder.CreateLocalReference(awaiterTemp),
                getResult);

            var nullAwaiter = CodeBuilder.CreateAssignment(
                CodeBuilder.CreateLocalReference(awaiterTemp),
                CodeBuilder.CreateDefaultInvocation(this.LexicalInfo, awaiterTemp.Type));

            if (resultPlace != null && type != TypeSystemServices.VoidType)
            {
                // $resultTemp = $awaiterTemp.GetResult();
                // $awaiterTemp = null;
                // $resultTemp
                InternalLocal resultTemp = CodeBuilder.DeclareTempLocal(_moveNext.Method, type);
                return(new Block(
                           awaitIfIncomplete,
                           new ExpressionStatement(
                               CodeBuilder.CreateAssignment(CodeBuilder.CreateLocalReference(resultTemp), getResultCall)),
                           new ExpressionStatement(nullAwaiter),
                           new ExpressionStatement(
                               CodeBuilder.CreateAssignment(resultPlace, CodeBuilder.CreateLocalReference(resultTemp)))));
            }

            // $awaiterTemp.GetResult();
            // $awaiterTemp = null;
            return(new Block(
                       awaitIfIncomplete,
                       new ExpressionStatement(getResultCall),
                       new ExpressionStatement(nullAwaiter)));
        }