未验证 提交 b18cb030 编写于 作者: F Fred Silberberg 提交者: GitHub

Merge pull request #42807 from YairHalberstadt/fix-ltr-semantics-async

......@@ -677,17 +677,15 @@ public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node)
if (field.FieldSymbol.IsStatic) break;
// instance fields are directly assignable, but receiver is pushed, so need to spill that.
var receiver = VisitExpression(ref leftBuilder, field.ReceiverOpt);
receiver = Spill(builder, receiver, field.FieldSymbol.ContainingType.IsValueType ? RefKind.Ref : RefKind.None);
left = field.Update(receiver, field.FieldSymbol, field.ConstantValueOpt, field.ResultKind, field.Type);
left = fieldWithSpilledReceiver(field, ref leftBuilder, isAssignmentTarget: true);
break;
case BoundKind.ArrayAccess:
var arrayAccess = (BoundArrayAccess)left;
// array and indices are pushed on stack so need to spill that
var expression = VisitExpression(ref leftBuilder, arrayAccess.Expression);
expression = Spill(builder, expression, RefKind.None);
var indices = this.VisitExpressionList(ref builder, arrayAccess.Indices, forceSpill: true);
expression = Spill(leftBuilder, expression, RefKind.None);
var indices = this.VisitExpressionList(ref leftBuilder, arrayAccess.Indices, forceSpill: true);
left = arrayAccess.Update(expression, indices, arrayAccess.Type);
break;
......@@ -710,6 +708,53 @@ public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node)
}
return UpdateExpression(builder, node.Update(left, right, node.IsRef, node.Type));
BoundExpression fieldWithSpilledReceiver(BoundFieldAccess field, ref BoundSpillSequenceBuilder leftBuilder, bool isAssignmentTarget)
{
BoundExpression receiver;
var generateDummyFieldAccess = false;
if (field.FieldSymbol.ContainingType.IsReferenceType)
{
// a reference type can always live across await so Spill using leftBuilder
receiver = Spill(leftBuilder, VisitExpression(ref leftBuilder, field.ReceiverOpt));
// dummy field access to trigger NRE
// a.b = c will trigger a NRE if a is null on assignment,
// but a.b.c = d will trigger a NRE if a is null before evaluating d
// so check whether we assign to the field directly
generateDummyFieldAccess = !isAssignmentTarget;
}
else if (field.ReceiverOpt is BoundArrayAccess arrayAccess)
{
// an arrayAccess returns a ref so can only be called after the await, but spill expression and indices
var expression = VisitExpression(ref leftBuilder, arrayAccess.Expression);
expression = Spill(leftBuilder, expression, RefKind.None);
var indices = this.VisitExpressionList(ref leftBuilder, arrayAccess.Indices, forceSpill: true);
receiver = arrayAccess.Update(expression, indices, arrayAccess.Type);
// dummy array access to trigger IndexOutRangeException or NRE
// we only need this if the array access is a receiver since
// a[0] = b triggers a NRE/IORE on assignment
// but a[0].b = c triggers an NRE/IORE before evaluating c
Spill(leftBuilder, receiver, sideEffectsOnly: true);
}
else if (field.ReceiverOpt is BoundFieldAccess receiverField)
{
receiver = fieldWithSpilledReceiver(receiverField, ref leftBuilder, isAssignmentTarget: false);
}
else
{
receiver = Spill(leftBuilder, VisitExpression(ref leftBuilder, field.ReceiverOpt), RefKind.Ref);
}
field = field.Update(receiver, field.FieldSymbol, field.ConstantValueOpt, field.ResultKind, field.Type);
if (generateDummyFieldAccess)
{
Spill(leftBuilder, field, sideEffectsOnly: true);
}
return field;
}
}
public override BoundNode VisitBadExpression(BoundBadExpression node)
......
......@@ -235,7 +235,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Dim builder As New SpillBuilder()
Debug.Assert(left.IsLValue)
Dim spilledLeft As BoundExpression = SpillLValue(left, isReceiver:=False, builder:=builder)
Dim spilledLeft As BoundExpression = SpillLValue(left, isReceiver:=False, evaluateSideEffects:=True, builder:=builder, isAssignmentTarget:=True)
Dim rightAsSpillSequence = DirectCast(right, BoundSpillSequence)
builder.AddSpill(rightAsSpillSequence)
......@@ -565,7 +565,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
' to enforce order of evaluation and to decrease the size of the code that we will duplicate (1 - receiver evaluation during capture,
' 2 - value type receiver evaluation).
If Not receiver.Type.IsReferenceType Then
receiver = SpillValue(receiver, isReceiver:=True, builder:=builder)
receiver = SpillValue(receiver, isReceiver:=True, evaluateSideEffects:=True, builder:=builder)
End If
' If receiver is not spilled, we can use a local to capture receiver's value. If receiver is spilled, use SpillRValue to accomplish this
......@@ -600,7 +600,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
End If
Else
Debug.Assert(conditionalAccessReceiverPlaceholderReplacementInfo.IsSpilled)
placeholderReplacement = SpillValue(receiver, isReceiver:=True, builder:=builder)
placeholderReplacement = SpillValue(receiver, isReceiver:=True, evaluateSideEffects:=True, builder:=builder)
nullCheckTarget = placeholderReplacement.MakeRValue()
End If
Else
......
......@@ -218,7 +218,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
End If
Else
' We are to the left of an await-containing expression. Spill the arg.
newExpression = SpillValue(arg, isReceiver:=(index = 0 AndAlso firstArgumentIsAReceiverOfAMethodCall), builder:=builder)
newExpression = SpillValue(arg,
isReceiver:=(index = 0 AndAlso firstArgumentIsAReceiverOfAMethodCall),
evaluateSideEffects:=True,
builder:=builder)
End If
newArgs(index) = newExpression
......@@ -232,22 +235,22 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
End Function
Private Function SpillValue(expr As BoundExpression, <[In], Out> ByRef builder As SpillBuilder) As BoundExpression
Return SpillValue(expr, isReceiver:=False, builder:=builder)
Return SpillValue(expr, isReceiver:=False, evaluateSideEffects:=True, builder:=builder)
End Function
Private Function SpillValue(expr As BoundExpression, isReceiver As Boolean, <[In], Out> ByRef builder As SpillBuilder) As BoundExpression
Private Function SpillValue(expr As BoundExpression, isReceiver As Boolean, evaluateSideEffects As Boolean, <[In], Out> ByRef builder As SpillBuilder) As BoundExpression
If Unspillable(expr) Then
Return expr
ElseIf isReceiver OrElse expr.IsLValue Then
Return SpillLValue(expr, isReceiver, builder)
Return SpillLValue(expr, isReceiver, evaluateSideEffects, builder)
Else
Return SpillRValue(expr, builder)
End If
End Function
Private Function SpillLValue(expr As BoundExpression, isReceiver As Boolean, <[In], Out> ByRef builder As SpillBuilder) As BoundExpression
Private Function SpillLValue(expr As BoundExpression, isReceiver As Boolean, evaluateSideEffects As Boolean, <[In], Out> ByRef builder As SpillBuilder, Optional isAssignmentTarget As Boolean = False) As BoundExpression
Debug.Assert(expr IsNot Nothing)
Debug.Assert(isReceiver OrElse expr.IsLValue)
......@@ -277,13 +280,13 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Next
End If
Return SpillLValue(sequence.ValueOpt, isReceiver, builder)
Return SpillLValue(sequence.ValueOpt, evaluateSideEffects, isReceiver, builder)
Case BoundKind.SpillSequence
Dim spill = DirectCast(expr, BoundSpillSequence)
builder.AddSpill(spill)
Debug.Assert(spill.ValueOpt IsNot Nothing)
Return SpillLValue(spill.ValueOpt, isReceiver, builder)
Return SpillLValue(spill.ValueOpt, isReceiver, evaluateSideEffects, builder)
Case BoundKind.ArrayAccess
Dim array = DirectCast(expr, BoundArrayAccess)
......@@ -298,8 +301,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
array = array.Update(spilledExpression, spilledIndices.AsImmutableOrNull, array.IsLValue, array.Type)
' Make sure side effects are checked
builder.AddStatement(Me.F.ExpressionStatement(array))
' An assignment target is only evaluated on write, so don't evaluate it's side effects
If evaluateSideEffects And Not isAssignmentTarget Then
builder.AddStatement(Me.F.ExpressionStatement(array))
End If
Return array
......@@ -310,7 +315,14 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Return fieldAccess
End If
Dim newReceiver As BoundExpression = SpillValue(fieldAccess.ReceiverOpt, isReceiver:=True, builder:=builder)
' An assignment target is only evaluated on write, so don't evaluate it's side effects, but do evaluate side effects of the reciever expression
' Evaluating a field of a struct has no side effects, so only evaluate side effects of the reciever expression
Dim evaluateSideEffectsHere = evaluateSideEffects And Not isAssignmentTarget And fieldAccess.FieldSymbol.ContainingType.IsReferenceType
Dim newReceiver As BoundExpression = SpillValue(fieldAccess.ReceiverOpt,
isReceiver:=True,
evaluateSideEffects:=evaluateSideEffects And Not evaluateSideEffectsHere,
builder:=builder)
fieldAccess = fieldAccess.Update(newReceiver,
fieldAccess.FieldSymbol,
......@@ -319,8 +331,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
fieldAccess.ConstantsInProgressOpt,
fieldAccess.Type)
' Make sure side effects are checked
builder.AddStatement(Me.F.ExpressionStatement(fieldAccess))
If evaluateSideEffectsHere Then
builder.AddStatement(Me.F.ExpressionStatement(fieldAccess))
End If
Return fieldAccess
......
......@@ -783,7 +783,7 @@ End Module
v.VerifyIL("M.VB$StateMachine_0_F.MoveNext", "
{
// Code size 266 (0x10a)
// Code size 254 (0xfe)
.maxstack 3
.locals init (Boolean V_0,
Integer V_1,
......@@ -800,7 +800,7 @@ End Module
~IL_0007: ldloc.1
IL_0008: brfalse.s IL_000c
IL_000a: br.s IL_000e
IL_000c: br.s IL_006f
IL_000c: br.s IL_0063
-IL_000e: nop
~IL_000f: ldarg.0
IL_0010: newobj ""Sub M._Closure$__0-0..ctor()""
......@@ -809,95 +809,91 @@ End Module
IL_001b: ldarg.0
IL_001c: ldfld ""M.VB$StateMachine_0_F.$VB$ResumableLocal_$VB$Closure_$0 As M._Closure$__0-0""
IL_0021: stfld ""M.VB$StateMachine_0_F.$U1 As M._Closure$__0-0""
IL_0026: ldarg.0
IL_0027: ldfld ""M.VB$StateMachine_0_F.$U1 As M._Closure$__0-0""
IL_002c: ldfld ""M._Closure$__0-0.$VB$Local_z As Integer""
IL_0031: pop
IL_0032: ldc.i4.1
IL_0033: call ""Function System.Threading.Tasks.Task.FromResult(Of Integer)(Integer) As System.Threading.Tasks.Task(Of Integer)""
IL_0038: callvirt ""Function System.Threading.Tasks.Task(Of Integer).GetAwaiter() As System.Runtime.CompilerServices.TaskAwaiter(Of Integer)""
IL_003d: stloc.3
~IL_003e: ldloca.s V_3
IL_0040: call ""Function System.Runtime.CompilerServices.TaskAwaiter(Of Integer).get_IsCompleted() As Boolean""
IL_0045: brtrue.s IL_008d
IL_0047: ldarg.0
IL_0048: ldc.i4.0
IL_0049: dup
IL_004a: stloc.1
IL_004b: stfld ""M.VB$StateMachine_0_F.$State As Integer""
<IL_0050: ldarg.0
IL_0051: ldloc.3
IL_0052: stfld ""M.VB$StateMachine_0_F.$A0 As System.Runtime.CompilerServices.TaskAwaiter(Of Integer)""
IL_0057: ldarg.0
IL_0058: ldflda ""M.VB$StateMachine_0_F.$Builder As System.Runtime.CompilerServices.AsyncTaskMethodBuilder(Of Boolean)""
IL_005d: ldloca.s V_3
IL_005f: ldarg.0
IL_0060: stloc.s V_4
IL_0062: ldloca.s V_4
IL_0064: call ""Sub System.Runtime.CompilerServices.AsyncTaskMethodBuilder(Of Boolean).AwaitUnsafeOnCompleted(Of System.Runtime.CompilerServices.TaskAwaiter(Of Integer), M.VB$StateMachine_0_F)(ByRef System.Runtime.CompilerServices.TaskAwaiter(Of Integer), ByRef M.VB$StateMachine_0_F)""
IL_0069: nop
IL_006a: leave IL_0109
>IL_006f: ldarg.0
IL_0070: ldc.i4.m1
IL_0071: dup
IL_0072: stloc.1
IL_0073: stfld ""M.VB$StateMachine_0_F.$State As Integer""
IL_0078: ldarg.0
IL_0079: ldfld ""M.VB$StateMachine_0_F.$A0 As System.Runtime.CompilerServices.TaskAwaiter(Of Integer)""
IL_007e: stloc.3
IL_007f: ldarg.0
IL_0080: ldflda ""M.VB$StateMachine_0_F.$A0 As System.Runtime.CompilerServices.TaskAwaiter(Of Integer)""
IL_0085: initobj ""System.Runtime.CompilerServices.TaskAwaiter(Of Integer)""
IL_008b: br.s IL_008d
IL_008d: ldarg.0
IL_008e: ldfld ""M.VB$StateMachine_0_F.$U1 As M._Closure$__0-0""
IL_0093: ldloca.s V_3
IL_0095: call ""Function System.Runtime.CompilerServices.TaskAwaiter(Of Integer).GetResult() As Integer""
IL_009a: stloc.s V_5
IL_009c: ldloca.s V_3
IL_009e: initobj ""System.Runtime.CompilerServices.TaskAwaiter(Of Integer)""
IL_00a4: ldloc.s V_5
IL_00a6: stfld ""M._Closure$__0-0.$VB$Local_z As Integer""
IL_00ab: ldarg.0
IL_00ac: ldnull
IL_00ad: stfld ""M.VB$StateMachine_0_F.$U1 As M._Closure$__0-0""
-IL_00b2: ldarg.0
IL_00b3: ldarg.0
IL_00b4: ldfld ""M.VB$StateMachine_0_F.$VB$ResumableLocal_$VB$Closure_$0 As M._Closure$__0-0""
IL_00b9: ldftn ""Sub M._Closure$__0-0._Lambda$__0()""
IL_00bf: newobj ""Sub VB$AnonymousDelegate_0..ctor(Object, System.IntPtr)""
IL_00c4: stfld ""M.VB$StateMachine_0_F.$VB$ResumableLocal_x$1 As <generated method>""
-IL_00c9: ldc.i4.0
IL_00ca: stloc.0
IL_00cb: leave.s IL_00f2
IL_0026: ldc.i4.1
IL_0027: call ""Function System.Threading.Tasks.Task.FromResult(Of Integer)(Integer) As System.Threading.Tasks.Task(Of Integer)""
IL_002c: callvirt ""Function System.Threading.Tasks.Task(Of Integer).GetAwaiter() As System.Runtime.CompilerServices.TaskAwaiter(Of Integer)""
IL_0031: stloc.3
~IL_0032: ldloca.s V_3
IL_0034: call ""Function System.Runtime.CompilerServices.TaskAwaiter(Of Integer).get_IsCompleted() As Boolean""
IL_0039: brtrue.s IL_0081
IL_003b: ldarg.0
IL_003c: ldc.i4.0
IL_003d: dup
IL_003e: stloc.1
IL_003f: stfld ""M.VB$StateMachine_0_F.$State As Integer""
<IL_0044: ldarg.0
IL_0045: ldloc.3
IL_0046: stfld ""M.VB$StateMachine_0_F.$A0 As System.Runtime.CompilerServices.TaskAwaiter(Of Integer)""
IL_004b: ldarg.0
IL_004c: ldflda ""M.VB$StateMachine_0_F.$Builder As System.Runtime.CompilerServices.AsyncTaskMethodBuilder(Of Boolean)""
IL_0051: ldloca.s V_3
IL_0053: ldarg.0
IL_0054: stloc.s V_4
IL_0056: ldloca.s V_4
IL_0058: call ""Sub System.Runtime.CompilerServices.AsyncTaskMethodBuilder(Of Boolean).AwaitUnsafeOnCompleted(Of System.Runtime.CompilerServices.TaskAwaiter(Of Integer), M.VB$StateMachine_0_F)(ByRef System.Runtime.CompilerServices.TaskAwaiter(Of Integer), ByRef M.VB$StateMachine_0_F)""
IL_005d: nop
IL_005e: leave IL_00fd
>IL_0063: ldarg.0
IL_0064: ldc.i4.m1
IL_0065: dup
IL_0066: stloc.1
IL_0067: stfld ""M.VB$StateMachine_0_F.$State As Integer""
IL_006c: ldarg.0
IL_006d: ldfld ""M.VB$StateMachine_0_F.$A0 As System.Runtime.CompilerServices.TaskAwaiter(Of Integer)""
IL_0072: stloc.3
IL_0073: ldarg.0
IL_0074: ldflda ""M.VB$StateMachine_0_F.$A0 As System.Runtime.CompilerServices.TaskAwaiter(Of Integer)""
IL_0079: initobj ""System.Runtime.CompilerServices.TaskAwaiter(Of Integer)""
IL_007f: br.s IL_0081
IL_0081: ldarg.0
IL_0082: ldfld ""M.VB$StateMachine_0_F.$U1 As M._Closure$__0-0""
IL_0087: ldloca.s V_3
IL_0089: call ""Function System.Runtime.CompilerServices.TaskAwaiter(Of Integer).GetResult() As Integer""
IL_008e: stloc.s V_5
IL_0090: ldloca.s V_3
IL_0092: initobj ""System.Runtime.CompilerServices.TaskAwaiter(Of Integer)""
IL_0098: ldloc.s V_5
IL_009a: stfld ""M._Closure$__0-0.$VB$Local_z As Integer""
IL_009f: ldarg.0
IL_00a0: ldnull
IL_00a1: stfld ""M.VB$StateMachine_0_F.$U1 As M._Closure$__0-0""
-IL_00a6: ldarg.0
IL_00a7: ldarg.0
IL_00a8: ldfld ""M.VB$StateMachine_0_F.$VB$ResumableLocal_$VB$Closure_$0 As M._Closure$__0-0""
IL_00ad: ldftn ""Sub M._Closure$__0-0._Lambda$__0()""
IL_00b3: newobj ""Sub VB$AnonymousDelegate_0..ctor(Object, System.IntPtr)""
IL_00b8: stfld ""M.VB$StateMachine_0_F.$VB$ResumableLocal_x$1 As <generated method>""
-IL_00bd: ldc.i4.0
IL_00be: stloc.0
IL_00bf: leave.s IL_00e6
}
catch System.Exception
{
~IL_00cd: dup
IL_00ce: call ""Sub Microsoft.VisualBasic.CompilerServices.ProjectData.SetProjectError(System.Exception)""
IL_00d3: stloc.s V_6
~IL_00d5: ldarg.0
IL_00d6: ldc.i4.s -2
IL_00d8: stfld ""M.VB$StateMachine_0_F.$State As Integer""
IL_00dd: ldarg.0
IL_00de: ldflda ""M.VB$StateMachine_0_F.$Builder As System.Runtime.CompilerServices.AsyncTaskMethodBuilder(Of Boolean)""
IL_00e3: ldloc.s V_6
IL_00e5: call ""Sub System.Runtime.CompilerServices.AsyncTaskMethodBuilder(Of Boolean).SetException(System.Exception)""
IL_00ea: nop
IL_00eb: call ""Sub Microsoft.VisualBasic.CompilerServices.ProjectData.ClearProjectError()""
IL_00f0: leave.s IL_0109
~IL_00c1: dup
IL_00c2: call ""Sub Microsoft.VisualBasic.CompilerServices.ProjectData.SetProjectError(System.Exception)""
IL_00c7: stloc.s V_6
~IL_00c9: ldarg.0
IL_00ca: ldc.i4.s -2
IL_00cc: stfld ""M.VB$StateMachine_0_F.$State As Integer""
IL_00d1: ldarg.0
IL_00d2: ldflda ""M.VB$StateMachine_0_F.$Builder As System.Runtime.CompilerServices.AsyncTaskMethodBuilder(Of Boolean)""
IL_00d7: ldloc.s V_6
IL_00d9: call ""Sub System.Runtime.CompilerServices.AsyncTaskMethodBuilder(Of Boolean).SetException(System.Exception)""
IL_00de: nop
IL_00df: call ""Sub Microsoft.VisualBasic.CompilerServices.ProjectData.ClearProjectError()""
IL_00e4: leave.s IL_00fd
}
-IL_00f2: ldarg.0
IL_00f3: ldc.i4.s -2
IL_00f5: dup
IL_00f6: stloc.1
IL_00f7: stfld ""M.VB$StateMachine_0_F.$State As Integer""
~IL_00fc: ldarg.0
IL_00fd: ldflda ""M.VB$StateMachine_0_F.$Builder As System.Runtime.CompilerServices.AsyncTaskMethodBuilder(Of Boolean)""
IL_0102: ldloc.0
IL_0103: call ""Sub System.Runtime.CompilerServices.AsyncTaskMethodBuilder(Of Boolean).SetResult(Boolean)""
IL_0108: nop
IL_0109: ret
-IL_00e6: ldarg.0
IL_00e7: ldc.i4.s -2
IL_00e9: dup
IL_00ea: stloc.1
IL_00eb: stfld ""M.VB$StateMachine_0_F.$State As Integer""
~IL_00f0: ldarg.0
IL_00f1: ldflda ""M.VB$StateMachine_0_F.$Builder As System.Runtime.CompilerServices.AsyncTaskMethodBuilder(Of Boolean)""
IL_00f6: ldloc.0
IL_00f7: call ""Sub System.Runtime.CompilerServices.AsyncTaskMethodBuilder(Of Boolean).SetResult(Boolean)""
IL_00fc: nop
IL_00fd: ret
}
", sequencePoints:="M+VB$StateMachine_0_F.MoveNext")
End Sub
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册