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))); }
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))); }
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); }
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)); }
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)); }
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; } } } } }
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; }
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); } } } } }