diff --git a/src/Compilers/VisualBasic/Portable/CodeGen/Optimizer/StackScheduler.Analyzer.vb b/src/Compilers/VisualBasic/Portable/CodeGen/Optimizer/StackScheduler.Analyzer.vb
index 2411a4a1caec7cc1a631d43ca382c00ae1c66f24..492896e101406ff5bf10fb44dadf865ab2b51bac 100644
--- a/src/Compilers/VisualBasic/Portable/CodeGen/Optimizer/StackScheduler.Analyzer.vb
+++ b/src/Compilers/VisualBasic/Portable/CodeGen/Optimizer/StackScheduler.Analyzer.vb
@@ -73,7 +73,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGen
' this is the top of eval stack
DeclareLocal(_empty, 0)
- RecordVarWrite(_empty)
+ RecordDummyWrite(_empty)
End Sub
Public Shared Function Analyze(
@@ -576,16 +576,25 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGen
' Such call will push the receiver ref before the arguments
' so we need to ensure that arguments cannot use stack temps
Dim leftType As TypeSymbol = left.Type
- Dim cookie As Object = Nothing
+ Dim mayPushReceiver As Boolean = False
If right.Kind = BoundKind.ObjectCreationExpression Then
Dim ctor = DirectCast(right, BoundObjectCreationExpression).ConstructorOpt
If ctor IsNot Nothing AndAlso ctor.ParameterCount <> 0 Then
- cookie = GetStackStateCookie()
+ mayPushReceiver = True
End If
End If
+ If mayPushReceiver Then
+ 'push unknown value just to prevent access to stack locals.
+ PushEvalStack(Nothing, ExprContext.Address)
+ End If
+
right = VisitExpression(node.Right, rhsContext)
+ If mayPushReceiver Then
+ PopEvalStack()
+ End If
+
' if assigning to a local, now it is the time to record the Write
If storedAssignmentLocal IsNot Nothing Then
' this assert will fire if code relies on implicit CLR coercions
@@ -599,12 +608,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGen
RecordVarWrite(storedAssignmentLocal.LocalSymbol)
End If
- If cookie IsNot Nothing Then
- ' There is still RHS on the stack, adjust for that
- Me.PopEvalStack()
- EnsureStackState(cookie)
- End If
-
Return node.Update(left, Nothing, right, node.SuppressObjectClone, node.Type)
End Function
@@ -1147,7 +1150,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGen
Dim dummy As New DummyLocal(Me._container)
Me._dummyVariables.Add(dummy, dummy)
Me._locals.Add(dummy, New LocalDefUseInfo(Me.StackDepth))
- RecordVarWrite(dummy)
+ RecordDummyWrite(dummy)
Return dummy
End Function
@@ -1166,7 +1169,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGen
dummy = New DummyLocal(Me._container)
Me._dummyVariables.Add(label, dummy)
Me._locals.Add(dummy, New LocalDefUseInfo(Me.StackDepth))
- RecordVarWrite(dummy)
+ RecordDummyWrite(dummy)
End If
End Sub
@@ -1241,6 +1244,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGen
End Function
Private Sub RecordVarWrite(local As LocalSymbol)
+ Debug.Assert(local.SynthesizedKind <> SynthesizedLocalKind.OptimizerTemp)
+
If Not CanScheduleToStack(local) Then
Return
End If
@@ -1250,26 +1255,32 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGen
Return
End If
- ' if accessing real val, check stack
- If Not TypeOf local Is DummyLocal Then
-
- ' -1 because real assignment "consumes" value.
- Dim evalStack = Me.StackDepth - 1
+ ' check stack
+ ' -1 because real assignment "consumes" value.
+ Dim evalStack = Me.StackDepth - 1
- If locInfo.StackAtDeclaration <> evalStack Then
- ' writing at different eval stack.
- locInfo.ShouldNotSchedule()
- Return
- End If
- Else
- ' dummy must be accessed on same stack.
- Debug.Assert(local Is _empty OrElse locInfo.StackAtDeclaration = StackDepth())
+ If locInfo.StackAtDeclaration <> evalStack Then
+ ' writing at different eval stack.
+ locInfo.ShouldNotSchedule()
+ Return
End If
Dim locDef = New LocalDefUseSpan(Me._counter)
locInfo.localDefs.Add(locDef)
End Sub
+ Private Sub RecordDummyWrite(local As LocalSymbol)
+ Debug.Assert(local.SynthesizedKind = SynthesizedLocalKind.OptimizerTemp)
+
+ Dim locInfo = _locals(local)
+
+ ' dummy must be accessed on same stack.
+ Debug.Assert(local Is _empty OrElse locInfo.StackAtDeclaration = StackDepth())
+
+ Dim locDef = New LocalDefUseSpan(Me._counter)
+ locInfo.localDefs.Add(locDef)
+ End Sub
+
Private Sub ShouldNotSchedule(local As LocalSymbol)
Dim localDefInfo As LocalDefUseInfo = Nothing
If _locals.TryGetValue(local, localDefInfo) Then
diff --git a/src/Compilers/VisualBasic/Portable/CodeGen/Optimizer/StackScheduler.LocalDefUseSpan.vb b/src/Compilers/VisualBasic/Portable/CodeGen/Optimizer/StackScheduler.LocalDefUseSpan.vb
index c7612c83da017e80afe4cbf00f378aa1687b044c..cd54375bddd1a5cd988fbab5b18baed3cc09019b 100644
--- a/src/Compilers/VisualBasic/Portable/CodeGen/Optimizer/StackScheduler.LocalDefUseSpan.vb
+++ b/src/Compilers/VisualBasic/Portable/CodeGen/Optimizer/StackScheduler.LocalDefUseSpan.vb
@@ -39,37 +39,42 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGen
End Function
'''
- ''' That said, when current and other use spans are regular spans we can have
- ''' only 2 conflict cases:
- ''' [1, 3) conflicts with [0, 2)
- ''' [1, 3) conflicts with [2, 4)
+ ''' when current And other use spans are regular spans we can have only 2 conflict cases:
+ ''' [1, 3) conflicts with [0, 2)
+ ''' [1, 3) conflicts with [2, 4)
'''
- ''' specifically:
- ''' [1, 3) does not conflict with [0, 1)
+ ''' NOTE: With regular spans, it is not possible for two spans to share an edge point
+ ''' unless they belong to the same local. (because we cannot aceess two real locals at the same time)
'''
- ''' NOTE: with regular spans, it is not possible to have start1 == start2 or
- ''' end1 == end2 since at the same node we can access only one real local.
- '''
- ''' However at the same node we can access one or more dummy locals. So we can
- ''' have start1 == start2 and end1 == end2 scenarios, but only if the other span
- ''' is a span of a dummy.
+ ''' specifically:
+ ''' [1, 3) does Not conflict with [0, 1) since such spans would need to belong to the same local
'''
Public Function ConflictsWith(other As LocalDefUseSpan) As Boolean
- ' NOTE: this logic is moved from CS as-is
- ' TODO: revise the definition of ConflictsWith
- Dim containsStart As Boolean = other.ContainsStart(Me.Start)
- Dim containsEnd = other.ContainsEnd(Me.End)
- Return containsStart Xor containsEnd
+ Return Contains(other.Start) Xor Contains(other.End)
+ End Function
+
+ Private Function Contains(val As Integer) As Boolean
+ Return Me.Start < val AndAlso Me.End > val
End Function
- Private Function ContainsStart(otherStart As Integer) As Boolean
- Return Me.Start <= otherStart AndAlso Me.End > otherStart
+ '''
+ ''' Dummy locals represent implicit control flow
+ ''' it is not allowed for a regular local span to cross into or
+ ''' be immediately adjacent to a dummy span.
+ '''
+ ''' specifically:
+ ''' [1, 3) does conflict with [0, 1) since that would imply a value flowing into or out of a span surrounded by a branch/label
+ '''
+ '''
+ Public Function ConflictsWithDummy(dummy As LocalDefUseSpan) As Boolean
+ Return Includes(dummy.Start) Xor Includes(dummy.End)
End Function
- Private Function ContainsEnd(otherEnd As Integer) As Boolean
- Return Me.Start < otherEnd AndAlso Me.End > otherEnd
+ Private Function Includes(val As Integer) As Boolean
+ Return Me.Start <= val AndAlso Me.End >= val
End Function
+
End Class
End Class
diff --git a/src/Compilers/VisualBasic/Portable/CodeGen/Optimizer/StackScheduler.vb b/src/Compilers/VisualBasic/Portable/CodeGen/Optimizer/StackScheduler.vb
index 9123484e52fa42ca0c3cb95806189b3f7d040bac..c31e1efd1de52852a10db896100122c908aa8fda 100644
--- a/src/Compilers/VisualBasic/Portable/CodeGen/Optimizer/StackScheduler.vb
+++ b/src/Compilers/VisualBasic/Portable/CodeGen/Optimizer/StackScheduler.vb
@@ -63,8 +63,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGen
Next
Next
- ' TODO: perf. This can be simplified to not use a query.
+ Dim dummyCnt = defs.Count
+ ' TODO: perf. This can be simplified to not use a query.
' order locals by the number of usages, then by the declaration in descending order
For Each localInfo In From i In info
Where i.Value.localDefs.Count > 0
@@ -85,14 +86,22 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGen
For Each newDef In localInfo.Value.localDefs
Debug.Assert(Not intersects)
- ' TODO: This piece makes the whole thing O(n^2), revise
- For i = 0 To defs.Count - 1
- If newDef.ConflictsWith(defs(i)) Then
+ For i = 0 To dummyCnt - 1
+ If newDef.ConflictsWithDummy(defs(i)) Then
intersects = True
Exit For
End If
Next
+ If Not intersects Then
+ For i = dummyCnt To defs.Count - 1
+ If newDef.ConflictsWith(defs(i)) Then
+ intersects = True
+ Exit For
+ End If
+ Next
+ End If
+
If intersects Then
info.Remove(localInfo.Key)
Exit For
diff --git a/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenTests.vb b/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenTests.vb
index be2ab01db97444bea9209365cffc9df4db5f68a6..06b69e66598bb9f47092e43afa4f9822333c08b7 100644
--- a/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenTests.vb
+++ b/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenTests.vb
@@ -13403,5 +13403,73 @@ End Structure
)
End Sub
+
+
+ Public Sub InplaceCtorUsesLocal()
+ Dim c = CompileAndVerify(
+
+
+
+
+
+, options:=TestOptions.ReleaseExe,
+ expectedOutput:="2")
+
+ c.VerifyIL("Module1.Main",
+ )
+ End Sub
+
End Class
End Namespace