Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit 0aea0a9

Browse files
authored
Merge pull request #23256 from dotnet-maestro-bot/merge/release/2.1-to-release/2.2
[automated] Merge branch 'release/2.1' => 'release/2.2'
2 parents a3d715b + a1f417b commit 0aea0a9

File tree

4 files changed

+202
-6
lines changed

4 files changed

+202
-6
lines changed

ILAsmVersion.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
2.2.3-servicing-27414-05
1+
2.2.3-servicing-27414-05

src/jit/liveness.cpp

Lines changed: 108 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1104,6 +1104,42 @@ void Compiler::fgExtendDbgLifetimes()
11041104
#endif // DEBUG
11051105
}
11061106

1107+
//------------------------------------------------------------------------
1108+
// fgGetHandlerLiveVars: determine set of locals live because of implicit
1109+
// exception flow from a block.
1110+
//
1111+
// Arguments:
1112+
// block - the block in question
1113+
//
1114+
// Returns:
1115+
// Additional set of locals to be considered live throughout the block.
1116+
//
1117+
// Notes:
1118+
// Assumes caller has screened candidate blocks to only those with
1119+
// exception flow, via `ehBlockHasExnFlowDsc`.
1120+
//
1121+
// Exception flow can arise because of a newly raised exception (for
1122+
// blocks within try regions) or because of an actively propagating exception
1123+
// (for filter blocks). This flow effectively creates additional successor
1124+
// edges in the flow graph that the jit does not model. This method computes
1125+
// the net contribution from all the missing successor edges.
1126+
//
1127+
// For example, with the following C# source, during EH processing of the throw,
1128+
// the outer filter will execute in pass1, before the inner handler executes
1129+
// in pass2, and so the filter blocks should show the inner handler's local is live.
1130+
//
1131+
// try
1132+
// {
1133+
// using (AllocateObject()) // ==> try-finally; handler calls Dispose
1134+
// {
1135+
// throw new Exception();
1136+
// }
1137+
// }
1138+
// catch (Exception e1) when (IsExpectedException(e1))
1139+
// {
1140+
// Console.WriteLine("In catch 1");
1141+
// }
1142+
11071143
VARSET_VALRET_TP Compiler::fgGetHandlerLiveVars(BasicBlock* block)
11081144
{
11091145
noway_assert(block);
@@ -1115,7 +1151,6 @@ VARSET_VALRET_TP Compiler::fgGetHandlerLiveVars(BasicBlock* block)
11151151
do
11161152
{
11171153
/* Either we enter the filter first or the catch/finally */
1118-
11191154
if (HBtab->HasFilter())
11201155
{
11211156
VarSetOps::UnionD(this, liveVars, HBtab->ebdFilter->bbLiveIn);
@@ -1147,6 +1182,72 @@ VARSET_VALRET_TP Compiler::fgGetHandlerLiveVars(BasicBlock* block)
11471182

11481183
} while (true);
11491184

1185+
// If this block is within a filter, we also need to report as live
1186+
// any vars live into enclosed finally or fault handlers, since the
1187+
// filter will run during the first EH pass, and enclosed or enclosing
1188+
// handlers will run during the second EH pass. So all these handlers
1189+
// are "exception flow" successors of the filter.
1190+
//
1191+
// Note we are relying on ehBlockHasExnFlowDsc to return true
1192+
// for any filter block that we should examine here.
1193+
if (block->hasHndIndex())
1194+
{
1195+
const unsigned thisHndIndex = block->getHndIndex();
1196+
EHblkDsc* enclosingHBtab = ehGetDsc(thisHndIndex);
1197+
1198+
if (enclosingHBtab->InFilterRegionBBRange(block))
1199+
{
1200+
assert(enclosingHBtab->HasFilter());
1201+
1202+
// Search the EH table for enclosed regions.
1203+
//
1204+
// All the enclosed regions will be lower numbered and
1205+
// immediately prior to and contiguous with the enclosing
1206+
// region in the EH tab.
1207+
unsigned index = thisHndIndex;
1208+
1209+
while (index > 0)
1210+
{
1211+
index--;
1212+
unsigned enclosingIndex = ehGetEnclosingTryIndex(index);
1213+
bool isEnclosed = false;
1214+
1215+
// To verify this is an enclosed region, search up
1216+
// through the enclosing regions until we find the
1217+
// region associated with the filter.
1218+
while (enclosingIndex != EHblkDsc::NO_ENCLOSING_INDEX)
1219+
{
1220+
if (enclosingIndex == thisHndIndex)
1221+
{
1222+
isEnclosed = true;
1223+
break;
1224+
}
1225+
1226+
enclosingIndex = ehGetEnclosingTryIndex(enclosingIndex);
1227+
}
1228+
1229+
// If we found an enclosed region, check if the region
1230+
// is a try fault or try finally, and if so, add any
1231+
// locals live into the enclosed region's handler into this
1232+
// block's live-in set.
1233+
if (isEnclosed)
1234+
{
1235+
EHblkDsc* enclosedHBtab = ehGetDsc(index);
1236+
1237+
if (enclosedHBtab->HasFinallyOrFaultHandler())
1238+
{
1239+
VarSetOps::UnionD(this, liveVars, enclosedHBtab->ebdHndBeg->bbLiveIn);
1240+
}
1241+
}
1242+
// Once we run across a non-enclosed region, we can stop searching.
1243+
else
1244+
{
1245+
break;
1246+
}
1247+
}
1248+
}
1249+
}
1250+
11501251
return liveVars;
11511252
}
11521253

@@ -1219,14 +1320,17 @@ class LiveVarAnalysis
12191320
// since (without proof otherwise) the use and def may touch different memory at run-time.
12201321
m_memoryLiveIn = m_memoryLiveOut | block->bbMemoryUse;
12211322

1222-
/* Can exceptions from this block be handled (in this function)? */
1223-
1323+
// Does this block have implicit exception flow to a filter or handler?
1324+
// If so, include the effects of that flow.
12241325
if (m_compiler->ehBlockHasExnFlowDsc(block))
12251326
{
12261327
const VARSET_TP& liveVars(m_compiler->fgGetHandlerLiveVars(block));
1227-
12281328
VarSetOps::UnionD(m_compiler, m_liveIn, liveVars);
12291329
VarSetOps::UnionD(m_compiler, m_liveOut, liveVars);
1330+
1331+
// Implicit eh edges can induce loop-like behavior,
1332+
// so make sure we iterate to closure.
1333+
m_hasPossibleBackEdge = true;
12301334
}
12311335

12321336
/* Has there been any change in either live set? */
@@ -3093,7 +3197,6 @@ void Compiler::fgInterBlockLocalVarLiveness()
30933197
if (block->bbCatchTyp != BBCT_NONE)
30943198
{
30953199
/* Note the set of variables live on entry to exception handler */
3096-
30973200
VarSetOps::UnionD(this, exceptVars, block->bbLiveIn);
30983201
}
30993202

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using System;
6+
7+
// Repro for issue 22820. On x86 we need to report enclosed handler
8+
// live-in locals as live into any enclosing filter.
9+
//
10+
// Run with optimized codegen and COMPlus_GCStress=0x4
11+
12+
class DisposableObject : IDisposable
13+
{
14+
public void Dispose()
15+
{
16+
Console.WriteLine("In dispose");
17+
}
18+
}
19+
20+
class Program
21+
{
22+
public static bool IsExpectedException(Exception e)
23+
{
24+
Console.WriteLine("In filter");
25+
GC.Collect();
26+
return e is OperationCanceledException;
27+
}
28+
29+
public static IDisposable AllocateObject()
30+
{
31+
return new DisposableObject();
32+
}
33+
34+
static int Main(string[] args)
35+
{
36+
int result = 0;
37+
38+
try
39+
{
40+
try
41+
{
42+
using (AllocateObject())
43+
{
44+
throw new Exception();
45+
}
46+
}
47+
catch (Exception e1) when (IsExpectedException(e1))
48+
{
49+
Console.WriteLine("In catch 1");
50+
}
51+
}
52+
catch (Exception e2)
53+
{
54+
Console.WriteLine("In catch 2");
55+
result = 100;
56+
}
57+
58+
return result;
59+
}
60+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3+
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
4+
<PropertyGroup>
5+
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
6+
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
7+
<SchemaVersion>2.0</SchemaVersion>
8+
<ProjectGuid>{2649FAFE-07BF-4F93-8120-BA9A69285ABB}</ProjectGuid>
9+
<OutputType>Exe</OutputType>
10+
<ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
11+
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
12+
</PropertyGroup>
13+
<!-- Default configurations to help VS understand the configurations -->
14+
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "></PropertyGroup>
15+
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "></PropertyGroup>
16+
<PropertyGroup>
17+
<DebugType>None</DebugType>
18+
<Optimize>True</Optimize>
19+
</PropertyGroup>
20+
<ItemGroup>
21+
<CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies">
22+
<Visible>False</Visible>
23+
</CodeAnalysisDependentAssemblyPaths>
24+
</ItemGroup>
25+
<ItemGroup>
26+
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
27+
</ItemGroup>
28+
<ItemGroup>
29+
<Compile Include="$(MSBuildProjectName).cs" />
30+
</ItemGroup>
31+
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
32+
<PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "></PropertyGroup>
33+
</Project>

0 commit comments

Comments
 (0)