diff options
author | Joseph Tremoulet <jotrem@microsoft.com> | 2016-04-04 17:25:20 -0400 |
---|---|---|
committer | Joseph Tremoulet <jotrem@microsoft.com> | 2016-04-27 11:33:42 -0400 |
commit | 0029475f1bc2cf20aee290d453d9e8e7bc738d84 (patch) | |
tree | 83b8ddc7da32d46d058d620f16e2a82e28176481 /src/jit/jiteh.cpp | |
parent | 5fe61b36cc72d43263fc892c754bb9f46acb5ef5 (diff) | |
download | coreclr-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.cpp | 97 |
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. |