示例#1
0
        public override BoundNode VisitNullCoalescingOperator(BoundNullCoalescingOperator node)
        {
            BoundSpillSequence2 ss = null;
            var             right  = VisitExpression(ref ss, node.RightOperand);
            BoundExpression left;

            if (ss == null)
            {
                left = VisitExpression(ref ss, node.LeftOperand);
            }
            else
            {
                var ssLeft = new BoundSpillSequence2();
                left = VisitExpression(ref ssLeft, node.LeftOperand);
                left = Spill(ssLeft, left);

                ssLeft.Add(F.If(
                               F.ObjectEqual(left, F.Null(left.Type)),
                               UpdateStatement(ss, F.Assignment(left, right))
                               ));
                return(UpdateExpression(ssLeft, left));
            }

            return(UpdateExpression(ss, node.Update(left, right, node.LeftConversion, node.Type)));
        }
示例#2
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)));
        }
示例#3
0
        private BoundStatement UpdateStatement(BoundSpillSequence2 ss, BoundStatement stmt)
        {
            if (ss == null)
            {
                Debug.Assert(stmt != null);
                return(stmt);
            }

            Debug.Assert(ss.Value == null);
            if (stmt != null)
            {
                ss.Add(stmt);
            }
            var result = F.Block(ss.Locals, ss.Statements);

            ss.Free();
            return(result);
        }
示例#4
0
        public override BoundNode VisitNullCoalescingOperator(BoundNullCoalescingOperator node)
        {
            BoundSpillSequence2 ss = null;
            var right = VisitExpression(ref ss, node.RightOperand);
            BoundExpression left;
            if (ss == null)
            {
                left = VisitExpression(ref ss, node.LeftOperand);
            }
            else
            {
                var ssLeft = new BoundSpillSequence2();
                left = VisitExpression(ref ssLeft, node.LeftOperand);
                left = Spill(ssLeft, left);

                ssLeft.Add(F.If(
                    F.ObjectEqual(left, F.Null(left.Type)),
                    UpdateStatement(ss, F.Assignment(left, right))
                    ));
                return UpdateExpression(ssLeft, left);
            }

            return UpdateExpression(ss, node.Update(left, right, node.LeftConversion, node.Type));
        }
示例#5
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));
        }
示例#6
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;
                     }
                 }
         }
     }
 }
示例#7
0
        private BoundStatement UpdateStatement(BoundSpillSequence2 ss, BoundStatement stmt)
        {
            if (ss == null)
            {
                Debug.Assert(stmt != null);
                return stmt;
            }

            Debug.Assert(ss.Value == null);
            if (stmt != null) ss.Add(stmt);
            var result = F.Block(ss.Locals, ss.Statements);
            ss.Free();
            return result;
        }
示例#8
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);
                    }
                }
                }
            }
        }