Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/coreclr/jit/codegencommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1623,7 +1623,7 @@ void CodeGen::genExitCode(BasicBlock* block)
// genJumpToThrowHlpBlk: Generate code for an out-of-line exception.
//
// Notes:
// For code that uses throw helper blocks, we share the helper blocks created by fgAddCodeRef().
// For code that uses throw helper blocks, we share the helper blocks.
// Otherwise, we generate the 'throw' inline.
//
// Arguments:
Expand Down
4 changes: 0 additions & 4 deletions src/coreclr/jit/compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4898,10 +4898,6 @@ void Compiler::compCompile(void** methodCodePtr, uint32_t* methodCodeSize, JitFl
// Insert GC Polls
DoPhase(this, PHASE_INSERT_GC_POLLS, &Compiler::fgInsertGCPolls);

// Create any throw helper blocks that might be needed
//
DoPhase(this, PHASE_CREATE_THROW_HELPERS, &Compiler::fgCreateThrowHelperBlocks);

if (opts.OptimizationEnabled())
{
// Conditional to switch conversion, and switch peeling
Expand Down
11 changes: 5 additions & 6 deletions src/coreclr/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -6774,7 +6774,7 @@ class Compiler

struct AddCodeDsc
{
// After fgCreateThrowHelperBlocks, the block to which
// The block to which
// we jump to raise the exception.
BasicBlock* acdDstBlk;

Expand Down Expand Up @@ -6838,16 +6838,15 @@ class Compiler
private:
static unsigned acdHelper(SpecialCodeKind codeKind);

bool fgRngChkThrowAdded = false;
AddCodeDscMap* fgAddCodeDscMap = nullptr;

void fgAddCodeRef(BasicBlock* srcBlk, SpecialCodeKind kind);
PhaseStatus fgCreateThrowHelperBlocks();
AddCodeDsc* fgCreateAddCodeDsc(BasicBlock* fromBlock, SpecialCodeKind kind);
void fgCreateThrowHelperBlock(AddCodeDsc* add);

public:

bool fgRngChkThrowAdded = false;
bool fgHasAddCodeDscMap() const { return fgAddCodeDscMap != nullptr; }
AddCodeDsc* fgFindExcptnTarget(SpecialCodeKind kind, BasicBlock* fromBlock);
AddCodeDsc* fgFindExcptnTarget(SpecialCodeKind kind, BasicBlock* fromBlock, bool createIfNeeded = false);
bool fgUseThrowHelperBlocks();
void fgCreateThrowHelperBlockCode(AddCodeDsc* add);
void fgSequenceLocals(Statement* stmt);
Expand Down
218 changes: 94 additions & 124 deletions src/coreclr/jit/flowgraph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3384,7 +3384,7 @@ Compiler::AddCodeDscMap* Compiler::fgGetAddCodeDscMap()
}

//------------------------------------------------------------------------
// fgAddCodeRef: Indicate that a particular throw helper block will
// fgCreateAddCodeDsc: Indicate that a particular throw helper block will
// be needed by the method.
//
// Arguments:
Expand All @@ -3395,42 +3395,18 @@ Compiler::AddCodeDscMap* Compiler::fgGetAddCodeDscMap()
// You can call this method after throw helpers have been created,
// but it will assert if this entails creation of a new helper.
//
void Compiler::fgAddCodeRef(BasicBlock* srcBlk, SpecialCodeKind kind)
Compiler::AddCodeDsc* Compiler::fgCreateAddCodeDsc(BasicBlock* srcBlk, SpecialCodeKind kind)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: missing // Returns (or is it Return Value) in the comment

{
// Record that the code will call a THROW_HELPER
// so on Windows Amd64 we can allocate the 4 outgoing
// arg slots on the stack frame if there are no other calls.
//
compUsesThrowHelper = true;

if (!fgUseThrowHelperBlocks() && (kind != SCK_FAIL_FAST))
{
// FailFast will still use a common throw helper, even in debuggable modes.
//
return;
}
assert(!fgRngChkThrowAdded);

// Fetch block data and designator
//
AcdKeyDesignator dsg = AcdKeyDesignator::KD_NONE;
unsigned const refData = (kind == SCK_FAIL_FAST) ? 0 : bbThrowIndex(srcBlk, &dsg);

// Look for an existing entry that matches what we're looking for
//
AddCodeDsc* add = fgFindExcptnTarget(kind, srcBlk);

if (add != nullptr)
{
JITDUMP(FMT_BB " requires throw helper block for %s, sharing ACD%u (data 0x%08x)\n", srcBlk->bbNum,
sckName(kind), add->acdNum, refData);
return;
}

assert(!fgRngChkThrowAdded);

// Allocate a new entry and prepend it to the list
//
add = new (this, CMK_Unknown) AddCodeDsc;
AddCodeDsc* add = new (this, CMK_BasicBlock) AddCodeDsc;
add->acdDstBlk = nullptr;
add->acdTryIndex = srcBlk->bbTryIndex;

Expand Down Expand Up @@ -3467,25 +3443,26 @@ void Compiler::fgAddCodeRef(BasicBlock* srcBlk, SpecialCodeKind kind)
assert(map->Lookup(key2, &add2));
assert(add == add2);
#endif

return add;
}

//------------------------------------------------------------------------
// fgCreateThrowHelperBlocks: create the needed throw helpers
// fgCreateThrowHelperBlock: create a throw helper block
//
// Returns:
// Suitable phase status
// Arguments:
// add -- addCodeDesc describing the block to create
//
// Notes:
// Creates a new block if necessary, and sets the add->acdDstBlk to the new block.
//
PhaseStatus Compiler::fgCreateThrowHelperBlocks()
void Compiler::fgCreateThrowHelperBlock(AddCodeDsc* add)
{
if (fgAddCodeDscMap == nullptr)
if (add->acdDstBlk != nullptr)
{
return PhaseStatus::MODIFIED_NOTHING;
return;
}

// We should not have added throw helper blocks yet.
//
assert(!fgRngChkThrowAdded);

const static BBKinds jumpKinds[] = {
BBJ_ALWAYS, // SCK_NONE
BBJ_THROW, // SCK_RNGCHK_FAIL
Expand All @@ -3499,89 +3476,82 @@ PhaseStatus Compiler::fgCreateThrowHelperBlocks()

noway_assert(sizeof(jumpKinds) == SCK_COUNT); // sanity check

for (AddCodeDsc* const add : AddCodeDscMap::ValueIteration(fgAddCodeDscMap))
{
// Create the target basic block in the region indicated by the acd info
//
assert(add->acdKind != SCK_NONE);
bool const putInFilter = (add->acdKeyDsg == AcdKeyDesignator::KD_FLT);
BasicBlock* const newBlk = fgNewBBinRegion(jumpKinds[add->acdKind], add->acdTryIndex, add->acdHndIndex,
/* nearBlk */ nullptr, putInFilter,
/* runRarely */ true, /* insertAtEnd */ true);
// Create the target basic block in the region indicated by the acd info
//
assert(add->acdKind != SCK_NONE);
bool const putInFilter = (add->acdKeyDsg == AcdKeyDesignator::KD_FLT);
BasicBlock* const newBlk = fgNewBBinRegion(jumpKinds[add->acdKind], add->acdTryIndex, add->acdHndIndex,
/* nearBlk */ nullptr, putInFilter,
/* runRarely */ true, /* insertAtEnd */ true);

// Update the descriptor so future lookups can find the block
//
add->acdDstBlk = newBlk;
// Update the descriptor so future lookups can find the block
//
add->acdDstBlk = newBlk;

#ifdef DEBUG
if (verbose)
if (verbose)
{
const char* msgWhere = "";
switch (add->acdKeyDsg)
{
const char* msgWhere = "";
switch (add->acdKeyDsg)
{
case AcdKeyDesignator::KD_NONE:
msgWhere = "non-EH region";
break;

case AcdKeyDesignator::KD_HND:
msgWhere = "handler";
break;
case AcdKeyDesignator::KD_NONE:
msgWhere = "non-EH region";
break;

case AcdKeyDesignator::KD_TRY:
msgWhere = "try";
break;
case AcdKeyDesignator::KD_HND:
msgWhere = "handler";
break;

case AcdKeyDesignator::KD_FLT:
msgWhere = "filter";
break;
case AcdKeyDesignator::KD_TRY:
msgWhere = "try";
break;

default:
msgWhere = "? unexpected";
}
case AcdKeyDesignator::KD_FLT:
msgWhere = "filter";
break;

const char* msg;
switch (add->acdKind)
{
case SCK_RNGCHK_FAIL:
msg = " for RNGCHK_FAIL";
break;
case SCK_DIV_BY_ZERO:
msg = " for DIV_BY_ZERO";
break;
case SCK_OVERFLOW:
msg = " for OVERFLOW";
break;
case SCK_ARG_EXCPN:
msg = " for ARG_EXCPN";
break;
case SCK_ARG_RNG_EXCPN:
msg = " for ARG_RNG_EXCPN";
break;
case SCK_FAIL_FAST:
msg = " for FAIL_FAST";
break;
case SCK_NULL_CHECK:
msg = " for NULL_CHECK";
break;
default:
msg = " for ??";
break;
}
default:
msgWhere = "? unexpected";
}

printf("\nAdding throw helper " FMT_BB " for ACD%u %s in %s%s\n", newBlk->bbNum, add->acdNum,
sckName(add->acdKind), msgWhere, msg);
const char* msg;
switch (add->acdKind)
{
case SCK_RNGCHK_FAIL:
msg = " for RNGCHK_FAIL";
break;
case SCK_DIV_BY_ZERO:
msg = " for DIV_BY_ZERO";
break;
case SCK_OVERFLOW:
msg = " for OVERFLOW";
break;
case SCK_ARG_EXCPN:
msg = " for ARG_EXCPN";
break;
case SCK_ARG_RNG_EXCPN:
msg = " for ARG_RNG_EXCPN";
break;
case SCK_FAIL_FAST:
msg = " for FAIL_FAST";
break;
case SCK_NULL_CHECK:
msg = " for NULL_CHECK";
break;
default:
msg = " for ??";
break;
}
#endif // DEBUG

// Mark the block as added by the compiler and not removable by future flow
// graph optimizations. Note that no target block points to these blocks.
//
newBlk->SetFlags(BBF_IMPORTED | BBF_DONT_REMOVE);
printf("\nAdding throw helper " FMT_BB " for ACD%u %s in %s%s\n", newBlk->bbNum, add->acdNum,
sckName(add->acdKind), msgWhere, msg);
}
#endif // DEBUG

fgRngChkThrowAdded = true;

return PhaseStatus::MODIFIED_EVERYTHING;
// Mark the block as added by the compiler and not removable by future flow
// graph optimizations. Note that no target block points to these blocks.
//
newBlk->SetFlags(BBF_IMPORTED | BBF_DONT_REMOVE);
}

//------------------------------------------------------------------------
Expand Down Expand Up @@ -3627,6 +3597,10 @@ void Compiler::fgCreateThrowHelperBlockCode(AddCodeDsc* add)
helper = CORINFO_HELP_FAIL_FAST;
break;

case SCK_NULL_CHECK:
helper = CORINFO_HELP_THROWNULLREF;
break;

default:
noway_assert(!"unexpected code addition kind");
}
Expand All @@ -3637,7 +3611,9 @@ void Compiler::fgCreateThrowHelperBlockCode(AddCodeDsc* add)
//
GenTreeCall* tree = gtNewHelperCallNode(helper, TYP_VOID);

// There are no args here but fgMorphArgs has side effects
// For Wasm we may add an arg to the throw helper.
//
// Also fgMorphArgs has side effects
// such as setting the outgoing arg area (which is necessary
// on AMD if there are any calls).
//
Expand All @@ -3651,8 +3627,8 @@ void Compiler::fgCreateThrowHelperBlockCode(AddCodeDsc* add)
}
else
{
LIR::AsRange(block).InsertAtEnd(tree);
LIR::ReadOnlyRange range(tree, tree);
LIR::Range range = LIR::SeqTree(this, tree);
LIR::AsRange(block).InsertAtEnd(std::move(range));
m_pLowering->LowerRange(block, range);
}
}
Expand All @@ -3668,7 +3644,7 @@ void Compiler::fgCreateThrowHelperBlockCode(AddCodeDsc* add)
// Code descriptor for the appropriate throw helper block, or nullptr if no such
// descriptor exists.
//
Compiler::AddCodeDsc* Compiler::fgFindExcptnTarget(SpecialCodeKind kind, BasicBlock* fromBlock)
Compiler::AddCodeDsc* Compiler::fgFindExcptnTarget(SpecialCodeKind kind, BasicBlock* fromBlock, bool createIfNeeded)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nit]
Could we either:

  1. Rename this to fgGetExcptnTarget or update the comment to indicate we always return a descriptor OR
  2. Move the createIfNeeded logic to the caller to separate that side effect out?

{
assert(fgUseThrowHelperBlocks() || (kind == SCK_FAIL_FAST));
AddCodeDsc* add = nullptr;
Expand All @@ -3678,20 +3654,14 @@ Compiler::AddCodeDsc* Compiler::fgFindExcptnTarget(SpecialCodeKind kind, BasicBl

if (add == nullptr)
{
// We shouldn't be asking for these blocks late in compilation
// unless we know there are entries to be found.
if (fgRngChkThrowAdded)
{
JITDUMP(FMT_BB ": unexpected request for new throw helper: kind %d (%s), data 0x%08x\n", fromBlock->bbNum,
kind, sckName(kind), key.Data());
add = fgCreateAddCodeDsc(fromBlock, kind);

if (kind == SCK_NULL_CHECK)
{
NYI_WASM("Missing null check demand");
}
// Create the block...
//
if (createIfNeeded)
{
fgCreateThrowHelperBlock(add);
}

assert(!fgRngChkThrowAdded);
}

return add;
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/jit/lower.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12115,7 +12115,7 @@ void Lowering::FinalizeOutgoingArgSpace()
// Finish computing the outgoing args area size
//
// Need to make sure the MIN_ARG_AREA_FOR_CALL space is added to the frame if:
// 1. there are calls to THROW_HELPER methods.
// 1. there may be calls to THROW_HELPER methods.
// 2. we are generating profiling Enter/Leave/TailCall hooks. This will ensure
// that even methods without any calls will have outgoing arg area space allocated.
// 3. We will be generating calls to PInvoke helpers. TODO: This shouldn't be required because
Expand Down
Loading
Loading