-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Don't hoist IConHandle statics above cctors #11694
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6142,9 +6142,15 @@ bool Compiler::optHoistLoopExprsForTree(GenTreePtr tree, | |
childrenCctorDependent[i] = false; | ||
} | ||
|
||
// Initclass CLS_VARs are the base case of cctor dependent trees. | ||
bool treeIsCctorDependent = (tree->OperIs(GT_CLS_VAR) && ((tree->gtFlags & GTF_CLS_VAR_INITCLASS) != 0)); | ||
bool treeIsInvariant = true; | ||
// Initclass CLS_VARs and IconHandles are the base cases of cctor dependent trees. | ||
// In the IconHandle case, it's of course the dereference, rather than the constant itself, that is | ||
// truly dependent on the cctor. So a more precise approach would be to separately propagate | ||
// isCctorDependent and isAddressWhoseDereferenceWouldBeCctorDependent, but we don't for simplicity/throughput; | ||
// the constant itself would be considered non-hoistable anyway, since optIsCSEcandidate returns | ||
// false for constants. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
This might not continue to be true in the future. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, GT_IND is already dipping into the common bits: #define GTF_IND_NONFAULTING 0x00000800 // An indir that cannot fault. GTF_SET_FLAGS is not used on indirs We could (maybe?) similarly "steal" There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm comfortable with this fix for now and don't want to complicate this right now by fishing for extra flag bits for the GT_IND node. |
||
bool treeIsCctorDependent = ((tree->OperIs(GT_CLS_VAR) && ((tree->gtFlags & GTF_CLS_VAR_INITCLASS) != 0)) || | ||
(tree->OperIs(GT_CNS_INT) && ((tree->gtFlags & GTF_ICON_INITCLASS) != 0))); | ||
bool treeIsInvariant = true; | ||
for (unsigned childNum = 0; childNum < nChildren; childNum++) | ||
{ | ||
if (!optHoistLoopExprsForTree(tree->GetChild(childNum), lnum, hoistCtxt, pFirstBlockAndBeforeSideEffect, | ||
|
@@ -6172,9 +6178,9 @@ bool Compiler::optHoistLoopExprsForTree(GenTreePtr tree, | |
// with the static field reference. | ||
treeIsCctorDependent = false; | ||
// Hoisting the static field without hoisting the initialization would be | ||
// incorrect; unset childrenHoistable for the field to ensure this doesn't | ||
// happen. | ||
childrenHoistable[0] = false; | ||
// incorrect, make sure we consider the field (which we flagged as | ||
// cctor-dependent) non-hoistable. | ||
noway_assert(!childrenHoistable[childNum]); | ||
} | ||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
// See the LICENSE file in the project root for more information. | ||
|
||
// Repro case for a bug involving hoisting of static field loads out of | ||
// loops and (illegally) above the corresponding type initializer calls. | ||
|
||
using System.Runtime.CompilerServices; | ||
|
||
namespace N | ||
{ | ||
struct WrappedInt | ||
{ | ||
public int Value; | ||
|
||
public static WrappedInt Twenty = new WrappedInt() { Value = 20 }; | ||
} | ||
public static class C | ||
{ | ||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||
static int unwrap(WrappedInt wi) => wi.Value; | ||
|
||
[MethodImpl(MethodImplOptions.NoInlining)] | ||
static int foo(int s, int n) | ||
{ | ||
for (int i = 0; i < n; ++i) | ||
{ | ||
s += unwrap(WrappedInt.Twenty); // Loading WrappedInt.Twenty must happen after calling the cctor | ||
} | ||
|
||
return s; | ||
} | ||
|
||
public static int Main(string[] args) | ||
{ | ||
return foo(20, 4); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | ||
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> | ||
<PropertyGroup> | ||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> | ||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> | ||
<AssemblyName>$(MSBuildProjectName)</AssemblyName> | ||
<SchemaVersion>2.0</SchemaVersion> | ||
<ProjectGuid>{A04B4F1F-62D3-4799-94AB-ABFB220415BE}</ProjectGuid> | ||
<OutputType>Exe</OutputType> | ||
<AppDesignerFolder>Properties</AppDesignerFolder> | ||
<FileAlignment>512</FileAlignment> | ||
<ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> | ||
<ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\11.0\UITestExtensionPackages</ReferencePath> | ||
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> | ||
|
||
<NuGetPackageImportStamp>7a9bfb7d</NuGetPackageImportStamp> | ||
</PropertyGroup> | ||
<!-- Default configurations to help VS understand the configurations --> | ||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> | ||
</PropertyGroup> | ||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> | ||
</PropertyGroup> | ||
<ItemGroup> | ||
<CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> | ||
<Visible>False</Visible> | ||
</CodeAnalysisDependentAssemblyPaths> | ||
</ItemGroup> | ||
<PropertyGroup> | ||
<DebugType></DebugType> | ||
<Optimize>True</Optimize> | ||
<AllowUnsafeBlocks>True</AllowUnsafeBlocks> | ||
</PropertyGroup> | ||
<ItemGroup> | ||
<Compile Include="GitHub_11689.cs" /> | ||
</ItemGroup> | ||
<PropertyGroup> | ||
<CLRTestBatchPreCommands><![CDATA[ | ||
$(CLRTestBatchPreCommands) | ||
set COMPlus_TailcallStress=1 | ||
]]></CLRTestBatchPreCommands> | ||
<BashCLRTestPreCommands><![CDATA[ | ||
$(BashCLRTestPreCommands) | ||
export COMPlus_TailcallStress=1 | ||
]]></BashCLRTestPreCommands> | ||
</PropertyGroup> | ||
<ItemGroup> | ||
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> | ||
</ItemGroup> | ||
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> | ||
<PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "> | ||
</PropertyGroup> | ||
</Project> |
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.
Also line 6468 contains a dangerous SetOper call which can cause the
flag GTF_FLD_INITCLASS to be interpreted as GTF_IND_REFARR_LAYOUT
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.
6468 is dealing with instance fields (it's under the
if (objRef)
on line 6239 withelse
on line 6500)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.
OK