summaryrefslogtreecommitdiff
path: root/src/jit/jiteh.cpp
diff options
context:
space:
mode:
authorJoseph Tremoulet <jotrem@microsoft.com>2016-04-04 17:25:20 -0400
committerJoseph Tremoulet <jotrem@microsoft.com>2016-04-27 11:33:42 -0400
commit0029475f1bc2cf20aee290d453d9e8e7bc738d84 (patch)
tree83b8ddc7da32d46d058d620f16e2a82e28176481 /src/jit/jiteh.cpp
parent5fe61b36cc72d43263fc892c754bb9f46acb5ef5 (diff)
downloadcoreclr-0029475f1bc2cf20aee290d453d9e8e7bc738d84.tar.gz
coreclr-0029475f1bc2cf20aee290d453d9e8e7bc738d84.tar.bz2
coreclr-0029475f1bc2cf20aee290d453d9e8e7bc738d84.zip
Separate TryDsc and ExnFlowDsc
Supplement the helpers for finding a block's `TryDsc` (the `EHblkDsc` of the innermost `try` region containing it) and a block's `HndDsc` (the `EHblkDsc` of the innermost handler it is part of) with helpers for finding a block's `ExnFlowDsc` (the `EHblkDsc` of the innermost handler to which control may be transferred if an exception occurs in the given block). The `ExnFlowDsc` is the same as the `TryDsc` in most cases, but differs for blocks in filter expressions -- when an exception escapes a filter, that new exception is discarded and the search for a handler for the prior exception is resumed at the next-outer handler, which corresponds to the next-outer try enclosing the try that the filter protects. This is not the try enclosing the filter itself for "mutual-protect" clauses such as are generated for try { ... } catch when (E) { // <-- E is not in the 'try' but an exception ... // in it causes flow to go to the 'finally' } finally { ... } This change adds helpers around the `ExnFlowDsc` and updates code that was using the `TryDsc`/`TryIndex` where appropriate. This fixes #4044.
Diffstat (limited to 'src/jit/jiteh.cpp')
-rw-r--r--src/jit/jiteh.cpp97
1 files changed, 97 insertions, 0 deletions
diff --git a/src/jit/jiteh.cpp b/src/jit/jiteh.cpp
index 531c17170f..f8e3cebbef 100644
--- a/src/jit/jiteh.cpp
+++ b/src/jit/jiteh.cpp
@@ -431,6 +431,40 @@ bool Compiler::bbInTryRegions(unsigned regionIndex, BasicBlock *
return (tryIndex == regionIndex);
}
+//------------------------------------------------------------------------
+// bbInExnFlowRegions:
+// Check to see if an exception raised in the given block could be
+// handled by the given region (possibly after inner regions).
+//
+// Arguments:
+// regionIndex - Check if this region can handle exceptions from 'blk'
+// blk - Consider exceptions raised from this block
+//
+// Return Value:
+// true - The region with index 'regionIndex' can handle exceptions from 'blk'
+// false - The region with index 'regionIndex' can't handle exceptions from 'blk'
+//
+// Notes:
+// For this check, a funclet is considered to be in the region it was
+// extracted from.
+
+bool Compiler::bbInExnFlowRegions(unsigned regionIndex, BasicBlock * blk)
+{
+ assert(regionIndex < EHblkDsc::NO_ENCLOSING_INDEX);
+ EHblkDsc* ExnFlowRegion = ehGetBlockExnFlowDsc(blk);
+ unsigned tryIndex = (ExnFlowRegion == nullptr ? EHblkDsc::NO_ENCLOSING_INDEX : ehGetIndex(ExnFlowRegion));
+
+ // Loop outward until we find an enclosing try that is the same as the one
+ // we are looking for or an outer/later one
+ while (tryIndex < regionIndex)
+ {
+ tryIndex = ehGetEnclosingTryIndex(tryIndex);
+ }
+
+ // Now we have the index of 2 try bodies, either they match or not!
+ return (tryIndex == regionIndex);
+}
+
/*
Given a block, check to see if it is in the handler block of the EH descriptor.
For this check, a funclet is considered to be in the region it was extracted from.
@@ -637,6 +671,69 @@ bool Compiler::ehIsBlockEHLast(BasicBlock* block)
(ehIsBlockHndLast(block) != nullptr);
}
+//------------------------------------------------------------------------
+// ehGetBlockExnFlowDsc:
+// Get the EH descriptor for the most nested region (if any) that may
+// handle exceptions raised in the given block
+//
+// Arguments:
+// block - Consider exceptions raised from this block
+//
+// Return Value:
+// nullptr - The given block's exceptions propagate to caller
+// non-null - This region is the innermost handler for exceptions raised in
+// the given block
+
+EHblkDsc* Compiler::ehGetBlockExnFlowDsc(BasicBlock* block)
+{
+ EHblkDsc* hndDesc = ehGetBlockHndDsc(block);
+
+ if ((hndDesc != nullptr) && hndDesc->InFilterRegionBBRange(block))
+ {
+ // If an exception is thrown in a filter (or escapes a callee in a filter),
+ // or if exception_continue_search (0/false) is returned at
+ // the end of a filter, the (original) exception is propagated to
+ // the next outer handler. The "next outer handler" is the handler
+ // of the try region enclosing the try that the filter protects.
+ // This may not be the same as the try region enclosing the filter,
+ // e.g. in cases like this:
+ // try {
+ // ...
+ // } filter (filter-part) {
+ // handler-part
+ // } catch { (or finally/fault/filter)
+ // which is represented as two EHblkDscs with the same try range,
+ // the inner protected by a filter and the outer protected by the
+ // other handler; exceptions in the filter-part propagate to the
+ // other handler, even though the other handler's try region does not
+ // enclose the filter.
+
+ unsigned outerIndex = hndDesc->ebdEnclosingTryIndex;
+
+ if (outerIndex == EHblkDsc::NO_ENCLOSING_INDEX)
+ {
+ assert(!block->hasTryIndex());
+ return nullptr;
+ }
+ return ehGetDsc(outerIndex);
+ }
+
+ return ehGetBlockTryDsc(block);
+}
+
+bool Compiler::ehBlockHasExnFlowDsc(BasicBlock* block)
+{
+ if (block->hasTryIndex())
+ {
+ return true;
+ }
+
+ EHblkDsc* hndDesc = ehGetBlockHndDsc(block);
+
+ return ((hndDesc != nullptr)
+ && hndDesc->InFilterRegionBBRange(block)
+ && (hndDesc->ebdEnclosingTryIndex != EHblkDsc::NO_ENCLOSING_INDEX));
+}
//------------------------------------------------------------------------
// ehGetMostNestedRegionIndex: Return the region index of the most nested EH region this block is in.