-
Notifications
You must be signed in to change notification settings - Fork 4.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Avoid using a ref local for array element l-value #24070
Conversation
@dotnet/roslyn-compiler, @AlekseyTs, @VSadov, please review. |
@cston It looks like a bunch of tests require an IL baseline change. #Closed |
@@ -1,5 +1,7 @@ | |||
' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. | |||
|
|||
#Const DONT_USE_BYREF_LOCALS_FOR_USE_TWICE = True |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe this affects more scenarios than we would like to. We only need to change behavior of UseTwiceArrayAccess method. #Closed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated.
@@ -507,17 +507,7 @@ private BoundExpression TransformCompoundAssignmentLHS(BoundExpression originalL | |||
break; | |||
|
|||
case BoundKind.ArrayAccess: | |||
if (isDynamicAssignment) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just removing this seems pretty heavy.
We should do this only when element type is an unsealed reference type.
We definitely do not want to do this with struct arrays or we might degrade fairly common patterns like intArray[i]++
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we have a test that generates / diffs IL to verify the intArray[i]++
case maintains the current code generation?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this fix addresses such a corner case, I think the right expectation is that most or none of the existing tests need to change.
And there should be a lot of existing tests doing intArray[i]++
or similar.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like it is the case after the last commit.
It looks like we need to make similar changes to WithExpressionRewriter in VB. #Closed |
Done with review pass (iteration 2). #Closed |
In reply to: 355709608 [](ancestors = 355709608) |
// *tmp = *L op R; | ||
// where T is the type of L. | ||
// | ||
// If L is an array access, the assignment is dynamic, the compile-time of the array is dynamic[] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This paragraph doesn't mention covariant array access. Should it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added.
@@ -603,6 +604,11 @@ private BoundExpression TransformCompoundAssignmentLHS(BoundExpression originalL | |||
return variableTemp; | |||
} | |||
|
|||
private static bool IsInvariantArray(TypeSymbol type) | |||
{ | |||
return (type as ArrayTypeSymbol)?.ElementType?.IsSealed == true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What does this return for T where T : struct
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can treat T where T : struct
arrays as nonvariant.
I think IsSealed
returns false for type parameters regardless of constraints, so it may need to be checked separately. Or not at all - it would be a rare and hardly testable scenario.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, IsSealed
returns false
for type parameters (and IsMustInherit
returns False
in VB), regardless of constraints. I've added tests for Structure
and reference type constraints in VB but I'm not able to hit IsInvariantArray
with an array of type parameters in C#. I've left the implementations of IsInvariantArray
as is, returning false
for type parameters.
@@ -603,6 +604,11 @@ private BoundExpression TransformCompoundAssignmentLHS(BoundExpression originalL | |||
return variableTemp; | |||
} | |||
|
|||
private static bool IsInvariantArray(TypeSymbol type) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: CLR spec uses "non-variant" term for this.
@cston It looks like there are legitimate test failures. #Closed |
} | ||
static void G(object[] a, string s) | ||
{ | ||
a[0] += s; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps one more test where the index is a nonconstant expression like a function call - to see two temps.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
@dotnet-bot test windows_release_vs-integration_prtest |
@AlekseyTs, @jaredpar, @agocke, all feedback has been addressed. |
@@ -603,6 +604,11 @@ private BoundExpression TransformCompoundAssignmentLHS(BoundExpression originalL | |||
return variableTemp; | |||
} | |||
|
|||
private static bool IsInvariantArray(TypeSymbol type) | |||
{ | |||
return (type as ArrayTypeSymbol)?.ElementType?.IsSealed == true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
? [](start = 57, length = 1)
It feels like the second conditional access is redundant. #Closed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated.
@@ -208,7 +208,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic | |||
|
|||
Debug.Assert(node.IsLValue) | |||
|
|||
#If DONT_USE_BYREF_LOCALS_FOR_USE_TWICE Then |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is not clear why is this conditional compilation got removed from this method. I would expect it to be adjusted to ensure that UseTwiceLValue is still not called when DONT_USE_BYREF_LOCALS_FOR_USE_TWICE is defined. #Closed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added #If
.
End Function | ||
|
||
Private Shared Function IsInvariantArray(type As TypeSymbol) As Boolean | ||
Dim value = TryCast(type, ArrayTypeSymbol)?.ElementType?.IsNotInheritable |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
? [](start = 67, length = 1)
The second conditional access feels redundant. #Closed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated.
|
||
Private Shared Function IsInvariantArray(type As TypeSymbol) As Boolean | ||
Dim value = TryCast(type, ArrayTypeSymbol)?.ElementType?.IsNotInheritable | ||
Return value.HasValue AndAlso value.GetValueOrDefault() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
value.HasValue AndAlso [](start = 19, length = 22)
The value.HasValue
check is redundant. #Closed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
End Sub | ||
|
||
<Fact> | ||
Public Sub ArrayElementWithBlock_Invariant() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ArrayElementWithBlock_Invariant [](start = 19, length = 31)
I think that "With Block" tests would be more interesting if they were accessing the implicit receiver more than once. #Closed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated.
Done with review pass (iteration 10) #Closed |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM (iteration 12)
@dotnet-bot test windows_release_vs-integration_prtest |
@MeiChin-Tsai for approval. |
approved. |
Customer scenario
Using a co-variant array element as an l-value results in
ArrayTypeMismatchException
.Bugs this fixes
547533
Workarounds, if any
Copy array element.
Risk
Low: Removes an optimization for array element l-values for compound assignment (C# and VB) and passing by reference (VB).
Performance impact
Low: Removes an optimization for array element l-values for compound assignment (C# and VB) and passing by reference (VB).
Is this a regression from a previous update?
Regression from Visual Studio 2013.
How was the bug found?
Customer reported.