예제 #1
0
        public override BoundNode VisitBinaryOperator(BoundBinaryOperator node)
        {
            BoundSpillSequence2 ss = null;
            var             right  = VisitExpression(ref ss, node.Right);
            BoundExpression left;

            if (ss == null)
            {
                left = VisitExpression(ref ss, node.Left);
            }
            else
            {
                var ssLeft = new BoundSpillSequence2();
                left = VisitExpression(ref ssLeft, node.Left);
                left = Spill(ssLeft, left);
                if (node.OperatorKind == BinaryOperatorKind.LogicalBoolOr || node.OperatorKind == BinaryOperatorKind.LogicalBoolAnd)
                {
                    ssLeft.Add(F.If(
                                   node.OperatorKind == BinaryOperatorKind.LogicalBoolAnd ? left : F.Not(left),
                                   UpdateStatement(ss, F.Assignment(left, right))
                                   ));
                    return(UpdateExpression(ssLeft, left));
                }
                else
                {
                    // if the right-hand-side has await, spill the left
                    ssLeft.IncludeSequence(ss);
                    ss = ssLeft;
                }
            }

            return(UpdateExpression(ss, node.Update(node.OperatorKind, left, right, node.ConstantValue, node.MethodOpt, node.ResultKind, node.Type)));
        }
예제 #2
0
        public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node)
        {
            BoundSpillSequence2 ss = null;
            var             right  = VisitExpression(ref ss, node.Right);
            BoundExpression left;

            if (ss == null || node.Left.Kind == BoundKind.Local)
            {
                left = VisitExpression(ref ss, node.Left);
            }
            else
            {
                // if the right-hand-side has await, spill the left
                var ss2 = new BoundSpillSequence2();
                left = VisitExpression(ref ss2, node.Left);
                if (left.Kind != BoundKind.Local)
                {
                    left = Spill(ss2, left, RefKind.Ref);
                }
                ss2.IncludeSequence(ss);
                ss = ss2;
            }

            return(UpdateExpression(ss, node.Update(left, right, node.RefKind, node.Type)));
        }
예제 #3
0
        public override BoundNode VisitArrayCreation(BoundArrayCreation node)
        {
            BoundSpillSequence2 ss = null;
            var init = (BoundArrayInitialization)VisitExpression(ref ss, node.InitializerOpt);
            ImmutableArray <BoundExpression> bounds;

            if (ss == null)
            {
                bounds = VisitExpressionList(ref ss, node.Bounds);
            }
            else
            {
                // spill bounds expressions if initializers contain await
                var ss2 = new BoundSpillSequence2();
                bounds = VisitExpressionList(ref ss2, node.Bounds, forceSpill: true);
                ss2.IncludeSequence(ss);
                ss = ss2;
            }

            return(UpdateExpression(ss, node.Update(bounds, init, node.Type)));
        }
예제 #4
0
        public override BoundNode VisitPointerElementAccess(BoundPointerElementAccess node)
        {
            BoundSpillSequence2 ss = null;
            var             index  = VisitExpression(ref ss, node.Index);
            BoundExpression expression;

            if (ss == null)
            {
                expression = VisitExpression(ref ss, node.Expression);
            }
            else
            {
                // if the right-hand-side has await, spill the left
                var ss2 = new BoundSpillSequence2();
                expression = VisitExpression(ref ss2, node.Expression);
                expression = Spill(ss2, expression);
                ss2.IncludeSequence(ss);
                ss = ss2;
            }

            return(UpdateExpression(ss, node.Update(expression, index, node.Checked, node.Type)));
        }
예제 #5
0
        public override BoundNode VisitCall(BoundCall node)
        {
            BoundSpillSequence2 ss = null;
            var arguments          = this.VisitExpressionList(ref ss, node.Arguments, node.ArgumentRefKindsOpt);

            BoundExpression receiver = null;

            if (ss == null)
            {
                receiver = VisitExpression(ref ss, node.ReceiverOpt);
            }
            else if (!node.Method.IsStatic)
            {
                // spill the receiver if there were await expressions in the arguments
                var ss2 = new BoundSpillSequence2();
                receiver = Spill(ss2, VisitExpression(ref ss2, node.ReceiverOpt), refKind: node.ReceiverOpt.Type.IsReferenceType ? RefKind.None : RefKind.Ref);
                ss2.IncludeSequence(ss);
                ss = ss2;
            }

            return(UpdateExpression(ss, node.Update(receiver, node.Method, arguments)));
        }
예제 #6
0
        public override BoundNode VisitPointerElementAccess(BoundPointerElementAccess node)
        {
            BoundSpillSequence2 ss = null;
            var index = VisitExpression(ref ss, node.Index);
            BoundExpression expression;
            if (ss == null)
            {
                expression = VisitExpression(ref ss, node.Expression);
            }
            else
            {
                // if the right-hand-side has await, spill the left
                var ss2 = new BoundSpillSequence2();
                expression = VisitExpression(ref ss2, node.Expression);
                expression = Spill(ss2, expression);
                ss2.IncludeSequence(ss);
                ss = ss2;
            }

            return UpdateExpression(ss, node.Update(expression, index, node.Checked, node.Type));
        }
예제 #7
0
        public override BoundNode VisitCall(BoundCall node)
        {
            BoundSpillSequence2 ss = null;
            var arguments = this.VisitExpressionList(ref ss, node.Arguments, node.ArgumentRefKindsOpt);

            BoundExpression receiver = null;
            if (ss == null)
            {
                receiver = VisitExpression(ref ss, node.ReceiverOpt);
            }
            else if (!node.Method.IsStatic)
            {
                // spill the receiver if there were await expressions in the arguments
                var ss2 = new BoundSpillSequence2();
                receiver = Spill(ss2, VisitExpression(ref ss2, node.ReceiverOpt), refKind: node.ReceiverOpt.Type.IsReferenceType ? RefKind.None : RefKind.Ref);
                ss2.IncludeSequence(ss);
                ss = ss2;
            }

            return UpdateExpression(ss, node.Update(receiver, node.Method, arguments));
        }
예제 #8
0
        public override BoundNode VisitBinaryOperator(BoundBinaryOperator node)
        {
            BoundSpillSequence2 ss = null;
            var right = VisitExpression(ref ss, node.Right);
            BoundExpression left;
            if (ss == null)
            {
                left = VisitExpression(ref ss, node.Left);
            }
            else
            {
                var ssLeft = new BoundSpillSequence2();
                left = VisitExpression(ref ssLeft, node.Left);
                left = Spill(ssLeft, left);
                if (node.OperatorKind == BinaryOperatorKind.LogicalBoolOr || node.OperatorKind == BinaryOperatorKind.LogicalBoolAnd)
                {
                    ssLeft.Add(F.If(
                        node.OperatorKind == BinaryOperatorKind.LogicalBoolAnd ? left : F.Not(left),
                        UpdateStatement(ss, F.Assignment(left, right))
                        ));
                    return UpdateExpression(ssLeft, left);
                }
                else
                {
                    // if the right-hand-side has await, spill the left
                    ssLeft.IncludeSequence(ss);
                    ss = ssLeft;
                }
            }

            return UpdateExpression(ss, node.Update(node.OperatorKind, left, right, node.ConstantValue, node.MethodOpt, node.ResultKind, node.Type));
        }
예제 #9
0
        public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node)
        {
            BoundSpillSequence2 ss = null;
            var right = VisitExpression(ref ss, node.Right);
            BoundExpression left;
            if (ss == null || node.Left.Kind == BoundKind.Local)
            {
                left = VisitExpression(ref ss, node.Left);
            }
            else
            {
                // if the right-hand-side has await, spill the left
                var ss2 = new BoundSpillSequence2();
                left = VisitExpression(ref ss2, node.Left);
                if (left.Kind != BoundKind.Local) left = Spill(ss2, left, RefKind.Ref);
                ss2.IncludeSequence(ss);
                ss = ss2;
            }

            return UpdateExpression(ss, node.Update(left, right, node.RefKind, node.Type));
        }
예제 #10
0
        public override BoundNode VisitArrayCreation(BoundArrayCreation node)
        {
            BoundSpillSequence2 ss = null;
            var init = (BoundArrayInitialization)VisitExpression(ref ss, node.InitializerOpt);
            ImmutableArray<BoundExpression> bounds;
            if (ss == null)
            {
                bounds = VisitExpressionList(ref ss, node.Bounds);
            }
            else
            {
                // spill bounds expressions if initializers contain await
                var ss2 = new BoundSpillSequence2();
                bounds = VisitExpressionList(ref ss2, node.Bounds, forceSpill: true);
                ss2.IncludeSequence(ss);
                ss = ss2;
            }

            return UpdateExpression(ss, node.Update(bounds, init, node.Type));
        }
예제 #11
0
 private BoundExpression Spill(
     BoundSpillSequence2 spill,
     BoundExpression e,
     RefKind refKind = RefKind.None,
     bool sideEffectsOnly = false)
 {
     Debug.Assert(spill != null);
     while (true)
     {
         switch (e.Kind)
         {
             case BoundKind.ArrayInitialization:
                 {
                     Debug.Assert(refKind == RefKind.None);
                     Debug.Assert(!sideEffectsOnly);
                     var ai = (BoundArrayInitialization)e;
                     var newInitializers = VisitExpressionList(ref spill, ai.Initializers, forceSpill: true);
                     return ai.Update(newInitializers);
                 }
             case BoundKind.ArgListOperator:
                 {
                     Debug.Assert(refKind == RefKind.None);
                     Debug.Assert(!sideEffectsOnly);
                     var al = (BoundArgListOperator)e;
                     var newArgs = VisitExpressionList(ref spill, al.Arguments, al.ArgumentRefKindsOpt, forceSpill: true);
                     return al.Update(newArgs, al.ArgumentRefKindsOpt, al.Type);
                 }
             case SpillSequence2:
                 {
                     var ss = (BoundSpillSequence2)e;
                     spill.IncludeSequence(ss);
                     e = ss.Value;
                     continue;
                 }
             case BoundKind.Sequence:
                 {
                     var ss = (BoundSequence)e;
                     spill.AddRange(ss.Locals);
                     spill.AddRange(ss.SideEffects, MakeExpressionStatement);
                     e = ss.Value;
                     continue;
                 }
             case BoundKind.ThisReference:
             case BoundKind.BaseReference:
                 {
                     if (refKind != RefKind.None || e.Type.IsReferenceType) return e;
                     goto default;
                 }
             case BoundKind.Parameter:
                 {
                     if (refKind != RefKind.None) return e;
                     goto default;
                 }
             case BoundKind.Local:
                 {
                     var local = (BoundLocal)e;
                     if (writeOnceTemps.Contains(local.LocalSymbol) || refKind != RefKind.None) return local;
                     goto default;
                 }
             case BoundKind.FieldAccess:
                 {
                     var field = (BoundFieldAccess)e;
                     if (field.FieldSymbol.IsReadOnly)
                     {
                         if (field.FieldSymbol.IsStatic) return field;
                         if (field.FieldSymbol.ContainingType.IsValueType) goto default;
                         // save the receiver; can get the field later.
                         var receiver = Spill(spill, field.ReceiverOpt, (refKind != RefKind.None && field.FieldSymbol.Type.IsReferenceType) ? refKind : RefKind.None, sideEffectsOnly);
                         return field.Update(receiver, field.FieldSymbol, field.ConstantValueOpt, field.ResultKind, field.Type);
                     }
                     goto default;
                 }
             case BoundKind.Literal:
             case BoundKind.TypeExpression:
                 return e;
             default:
                 {
                     if (e.Type.SpecialType == SpecialType.System_Void || sideEffectsOnly)
                     {
                         spill.Add(F.ExpressionStatement(e));
                         return null;
                     }
                     else
                     { 
                         BoundAssignmentOperator assignToTemp;
                         var replacement = F.StoreToTemp(e, out assignToTemp, refKind: refKind, kind: SynthesizedLocalKind.AwaitSpilledTemp);
                         spill.Add(replacement.LocalSymbol);
                         writeOnceTemps.Add(replacement.LocalSymbol);
                         spill.Add(F.ExpressionStatement(assignToTemp));
                         return replacement;
                     }
                 }
         }
     }
 }
예제 #12
0
        private BoundExpression Spill(
            BoundSpillSequence2 spill,
            BoundExpression e,
            RefKind refKind      = RefKind.None,
            bool sideEffectsOnly = false)
        {
            Debug.Assert(spill != null);
            while (true)
            {
                switch (e.Kind)
                {
                case BoundKind.ArrayInitialization:
                {
                    Debug.Assert(refKind == RefKind.None);
                    Debug.Assert(!sideEffectsOnly);
                    var ai = (BoundArrayInitialization)e;
                    var newInitializers = VisitExpressionList(ref spill, ai.Initializers, forceSpill: true);
                    return(ai.Update(newInitializers));
                }

                case BoundKind.ArgListOperator:
                {
                    Debug.Assert(refKind == RefKind.None);
                    Debug.Assert(!sideEffectsOnly);
                    var al      = (BoundArgListOperator)e;
                    var newArgs = VisitExpressionList(ref spill, al.Arguments, al.ArgumentRefKindsOpt, forceSpill: true);
                    return(al.Update(newArgs, al.ArgumentRefKindsOpt, al.Type));
                }

                case SpillSequence2:
                {
                    var ss = (BoundSpillSequence2)e;
                    spill.IncludeSequence(ss);
                    e = ss.Value;
                    continue;
                }

                case BoundKind.Sequence:
                {
                    var ss = (BoundSequence)e;
                    spill.AddRange(ss.Locals);
                    spill.AddRange(ss.SideEffects, MakeExpressionStatement);
                    e = ss.Value;
                    continue;
                }

                case BoundKind.ThisReference:
                case BoundKind.BaseReference:
                {
                    if (refKind != RefKind.None || e.Type.IsReferenceType)
                    {
                        return(e);
                    }
                    goto default;
                }

                case BoundKind.Parameter:
                {
                    if (refKind != RefKind.None)
                    {
                        return(e);
                    }
                    goto default;
                }

                case BoundKind.Local:
                {
                    var local = (BoundLocal)e;
                    if (writeOnceTemps.Contains(local.LocalSymbol) || refKind != RefKind.None)
                    {
                        return(local);
                    }
                    goto default;
                }

                case BoundKind.FieldAccess:
                {
                    var field = (BoundFieldAccess)e;
                    if (field.FieldSymbol.IsReadOnly)
                    {
                        if (field.FieldSymbol.IsStatic)
                        {
                            return(field);
                        }
                        if (field.FieldSymbol.ContainingType.IsValueType)
                        {
                            goto default;
                        }
                        // save the receiver; can get the field later.
                        var receiver = Spill(spill, field.ReceiverOpt, (refKind != RefKind.None && field.FieldSymbol.Type.IsReferenceType) ? refKind : RefKind.None, sideEffectsOnly);
                        return(field.Update(receiver, field.FieldSymbol, field.ConstantValueOpt, field.ResultKind, field.Type));
                    }
                    goto default;
                }

                case BoundKind.Literal:
                case BoundKind.TypeExpression:
                    return(e);

                default:
                {
                    if (e.Type.SpecialType == SpecialType.System_Void || sideEffectsOnly)
                    {
                        spill.Add(F.ExpressionStatement(e));
                        return(null);
                    }
                    else
                    {
                        BoundAssignmentOperator assignToTemp;
                        var replacement = F.StoreToTemp(e, out assignToTemp, refKind: refKind, kind: SynthesizedLocalKind.AwaitSpilledTemp);
                        spill.Add(replacement.LocalSymbol);
                        writeOnceTemps.Add(replacement.LocalSymbol);
                        spill.Add(F.ExpressionStatement(assignToTemp));
                        return(replacement);
                    }
                }
                }
            }
        }