flowList* Compiler::BlockPredsWithEH(BasicBlock* blk) { BlockToFlowListMap* ehPreds = GetBlockToEHPreds(); flowList* res; if (ehPreds->Lookup(blk, &res)) { return res; } res = blk->bbPreds; unsigned tryIndex; if (bbIsExFlowBlock(blk, &tryIndex)) { // Find the first block of the try. EHblkDsc* ehblk = ehGetDsc(tryIndex); BasicBlock* tryStart = ehblk->ebdTryBeg; for (flowList* tryStartPreds = tryStart->bbPreds; tryStartPreds != nullptr; tryStartPreds = tryStartPreds->flNext) { res = new (this, CMK_FlowList) flowList(tryStartPreds->flBlock, res); #if MEASURE_BLOCK_SIZE genFlowNodeCnt += 1; genFlowNodeSize += sizeof(flowList); #endif // MEASURE_BLOCK_SIZE } // Now add all blocks within the try (except for second blocks of BBJ_CALLFINALLY/BBJ_ALWAYS pairs; // these cannot cause transfer to the handler...) BasicBlock* prevBB = NULL; // TODO-Throughput: It would be nice if we could iterate just over the blocks in the try, via // something like: // for (BasicBlock* bb = ehblk->ebdTryBeg; bb != ehblk->ebdTryLast->bbNext; bb = bb->bbNext) // That doesn't work, however: funclets have caused us to sometimes split the body of a try into // more than one sequence of contiguous blocks. We need to find a better way to do this. for (BasicBlock* bb = fgFirstBB; bb != NULL; prevBB = bb, bb = bb->bbNext) { if (bbInTryRegions(tryIndex, bb) && (prevBB == NULL || !prevBB->isBBCallAlwaysPair())) { res = new (this, CMK_FlowList) flowList(bb, res); #if MEASURE_BLOCK_SIZE genFlowNodeCnt += 1; genFlowNodeSize += sizeof(flowList); #endif // MEASURE_BLOCK_SIZE } } #ifdef DEBUG unsigned hash = SsaStressHashHelper(); if (hash != 0) { res = ShuffleHelper(hash, res); } #endif // DEBUG ehPreds->Set(blk, res); } return res; }
//------------------------------------------------------------------------ // Compiler::unwindGetFuncLocations: Get the start/end emitter locations for this // function or funclet. If 'getHotSectionData' is true, get the start/end locations // for the hot section. Otherwise, get the data for the cold section. // // Note that we grab these locations before the prolog and epilogs are generated, so the // locations must remain correct after the prolog and epilogs are generated. // // For the prolog, instructions are put in the special, preallocated, prolog instruction group. // We don't want to expose the emitPrologIG unnecessarily (locations are actually pointers to // emitter instruction groups). Since we know the offset of the start of the function/funclet, // where the prolog is, will be zero, we use a nullptr start location to indicate that. // // There is no instruction group beyond the end of the end of the function, so there is no // location to indicate that. Once again, use nullptr for that. // // Intermediate locations point at the first instruction group of a funclet, which is a // placeholder IG. These are converted to real IGs, not deleted and replaced, so the location // remains valid. // // Arguments: // func - main function or funclet to get locations for. // getHotSectionData - 'true' to get the hot section data, 'false' to get the cold section data. // ppStartLoc - OUT parameter. Set to the start emitter location. // ppEndLoc - OUT parameter. Set to the end emitter location (the location immediately // the range; the 'end' location is not inclusive). // // Notes: // A start location of nullptr means the beginning of the code. // An end location of nullptr means the end of the code. // void Compiler::unwindGetFuncLocations(FuncInfoDsc* func, bool getHotSectionData, /* OUT */ emitLocation** ppStartLoc, /* OUT */ emitLocation** ppEndLoc) { if (func->funKind == FUNC_ROOT) { // Since all funclets are pulled out of line, the main code size is everything // up to the first handler. If the function is hot/cold split, we need to get the // appropriate sub-range. if (getHotSectionData) { *ppStartLoc = nullptr; // nullptr emit location means the beginning of the code. This is to handle the first // fragment prolog. if (fgFirstColdBlock != nullptr) { // The hot section only goes up to the cold section assert(fgFirstFuncletBB == nullptr); *ppEndLoc = new (this, CMK_UnwindInfo) emitLocation(ehEmitCookie(fgFirstColdBlock)); } else { if (fgFirstFuncletBB != nullptr) { *ppEndLoc = new (this, CMK_UnwindInfo) emitLocation(ehEmitCookie(fgFirstFuncletBB)); } else { *ppEndLoc = nullptr; // nullptr end location means the end of the code } } } else { assert(fgFirstFuncletBB == nullptr); // TODO-CQ: support hot/cold splitting in functions with EH assert(fgFirstColdBlock != nullptr); // There better be a cold section! *ppStartLoc = new (this, CMK_UnwindInfo) emitLocation(ehEmitCookie(fgFirstColdBlock)); *ppEndLoc = nullptr; // nullptr end location means the end of the code } } else { assert(getHotSectionData); // TODO-CQ: support funclets in cold section EHblkDsc* HBtab = ehGetDsc(func->funEHIndex); if (func->funKind == FUNC_FILTER) { assert(HBtab->HasFilter()); *ppStartLoc = new (this, CMK_UnwindInfo) emitLocation(ehEmitCookie(HBtab->ebdFilter)); *ppEndLoc = new (this, CMK_UnwindInfo) emitLocation(ehEmitCookie(HBtab->ebdHndBeg)); } else { assert(func->funKind == FUNC_HANDLER); *ppStartLoc = new (this, CMK_UnwindInfo) emitLocation(ehEmitCookie(HBtab->ebdHndBeg)); *ppEndLoc = (HBtab->ebdHndLast->bbNext == nullptr) ? nullptr : new (this, CMK_UnwindInfo) emitLocation(ehEmitCookie(HBtab->ebdHndLast->bbNext)); } } }