1
0
Fork 0
mirror of https://github.com/VSadov/Satori.git synced 2025-06-09 17:44:48 +09:00

JIT: Ensure EH clauses with same try region are reported contiguously to the VM (#104531)

The CORINFO_EH_CLAUSE_SAMETRY flag indicates to the VM that a given EH clause maps to the same try region as the previous EH clause. However, the JIT's internal invariants may result in an EH table ordering such that clauses mapped to the same try region aren't contiguous, thus breaking the functionality of this flag. To address this without changing the JIT's EH invariants, ensure the JIT reports clauses with the same try region contiguously to the VM, and sets CORINFO_EH_CLAUSE_SAMETRY accordingly.

Fixes #101772.
This commit is contained in:
Aman Khalid 2024-07-08 20:00:21 +00:00 committed by GitHub
parent dd2120b9f8
commit f99194cb7f
Signed by: github
GPG key ID: B5690EEEBB952194

View file

@ -30,6 +30,8 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
#include "patchpointinfo.h"
#include "optcse.h" // for cse metrics
#include "jitstd/algorithm.h"
/*****************************************************************************/
void CodeGenInterface::setFramePointerRequiredEH(bool value)
@ -2404,8 +2406,16 @@ void CodeGen::genReportEH()
// Tell the VM how many EH clauses to expect.
compiler->eeSetEHcount(EHCount);
XTnum = 0; // This is the index we pass to the VM
struct EHClauseInfo
{
CORINFO_EH_CLAUSE clause;
EHblkDsc* HBtab;
};
EHClauseInfo* clauses = new (compiler, CMK_Codegen) EHClauseInfo[compiler->compHndBBtabCount];
// Set up EH clause table, but don't report anything to the VM, yet.
XTnum = 0;
for (EHblkDsc* const HBtab : EHClauses(compiler))
{
UNATIVE_OFFSET tryBeg, tryEnd, hndBeg, hndEnd, hndTyp;
@ -2427,7 +2437,43 @@ void CodeGen::genReportEH()
hndTyp = HBtab->ebdTyp;
}
CORINFO_EH_CLAUSE_FLAGS flags = ToCORINFO_EH_CLAUSE_FLAGS(HBtab->ebdHandlerType);
// Note that we reuse the CORINFO_EH_CLAUSE type, even though the names of
// the fields aren't accurate.
CORINFO_EH_CLAUSE clause;
clause.ClassToken = hndTyp; /* filter offset is passed back here for filter-based exception handlers */
clause.Flags = ToCORINFO_EH_CLAUSE_FLAGS(HBtab->ebdHandlerType);
clause.TryOffset = tryBeg;
clause.TryLength = tryEnd;
clause.HandlerOffset = hndBeg;
clause.HandlerLength = hndEnd;
clauses[XTnum++] = {clause, HBtab};
}
// The JIT's ordering of EH clauses does not guarantee that clauses covering the same try region are contiguous.
// We need this property to hold true so the CORINFO_EH_CLAUSE_SAMETRY flag is accurate.
jitstd::sort(clauses, clauses + compiler->compHndBBtabCount,
[this](const EHClauseInfo& left, const EHClauseInfo& right) {
const unsigned short leftTryIndex = left.HBtab->ebdTryBeg->bbTryIndex;
const unsigned short rightTryIndex = right.HBtab->ebdTryBeg->bbTryIndex;
if (leftTryIndex == rightTryIndex)
{
// We have two clauses mapped to the same try region.
// Make sure we report the clause with the smaller index first.
const ptrdiff_t leftIndex = left.HBtab - this->compiler->compHndBBtab;
const ptrdiff_t rightIndex = right.HBtab - this->compiler->compHndBBtab;
return leftIndex < rightIndex;
}
return leftTryIndex < rightTryIndex;
});
// Now, report EH clauses to the VM in order of increasing try region index.
for (XTnum = 0; XTnum < compiler->compHndBBtabCount; XTnum++)
{
CORINFO_EH_CLAUSE& clause = clauses[XTnum].clause;
EHblkDsc* const HBtab = clauses[XTnum].HBtab;
if (XTnum > 0)
{
@ -2436,33 +2482,18 @@ void CodeGen::genReportEH()
// native code offsets because of different try blocks can have same offsets. Alternative
// solution to this problem would be inserting extra nops to ensure that different try
// blocks have different offsets.
if (EHblkDsc::ebdIsSameTry(HBtab, HBtab - 1))
if (EHblkDsc::ebdIsSameTry(HBtab, clauses[XTnum - 1].HBtab))
{
// The SAMETRY bit should only be set on catch clauses. This is ensured in IL, where only 'catch' is
// allowed to be mutually-protect. E.g., the C# "try {} catch {} catch {} finally {}" actually exists in
// IL as "try { try {} catch {} catch {} } finally {}".
assert(HBtab->HasCatchHandler());
flags = (CORINFO_EH_CLAUSE_FLAGS)(flags | CORINFO_EH_CLAUSE_SAMETRY);
clause.Flags = (CORINFO_EH_CLAUSE_FLAGS)(clause.Flags | CORINFO_EH_CLAUSE_SAMETRY);
}
}
// Note that we reuse the CORINFO_EH_CLAUSE type, even though the names of
// the fields aren't accurate.
CORINFO_EH_CLAUSE clause;
clause.ClassToken = hndTyp; /* filter offset is passed back here for filter-based exception handlers */
clause.Flags = flags;
clause.TryOffset = tryBeg;
clause.TryLength = tryEnd;
clause.HandlerOffset = hndBeg;
clause.HandlerLength = hndEnd;
assert(XTnum < EHCount);
// Tell the VM about this EH clause.
compiler->eeSetEHinfo(XTnum, &clause);
++XTnum;
}
// Now output duplicated clauses.