/** * Link primary body blocks to exception handler blocks as follows: * 1. For each block in the body, traverse from the innermost to * outermost exception handler that includes the block. For * catch handlers, add an edge to each handler entry point. For * fault handlers, add an edge to the fault handler and stop. * 2. For each fault handler block ending in Unwind, find the EH * entry for the funclet, then traverse outwards starting from the * next outermost. Add any catch edges found, and stop at the first * enclosing fault funclet, as in step 1. * The resulting linkage reflects exception control-flow; fault funclets * unconditionally handle any exception in their protected region, so they * "dominate" outer-more handlers. */ void GraphBuilder::linkExBlocks() { // For every block, add edges to reachable fault and catch handlers. for (LinearBlocks i = linearBlocks(m_graph); !i.empty(); ) { Block* b = i.popFront(); assert(m_func->findEH(offset(b->start)) == m_func->findEH(offset(b->last))); Offset off = offset(b->start); const EHEnt* eh = m_func->findEH(off); if (eh != nullptr) { assert(eh->m_base <= off && off < eh->m_past); // the innermost exception handler is reachable from b b->exn = at(eh->m_handler); } } }
/** * Link primary body blocks to exception handler blocks as follows: * 1. For each block in the body, traverse from the innermost to * outermost exception handler that includes the block. For * catch handlers, add an edge to each handler entry point. For * fault handlers, add an edge to the fault handler and stop. * 2. For each fault handler block ending in Unwind, find the EH * entry for the funclet, then traverse outwards starting from the * next outermost. Add any catch edges found, and stop at the first * enclosing fault funclet, as in step 1. * The resulting linkage reflects exception control-flow; fault funclets * unconditionally handle any exception in their protected region, so they * "dominate" outer-more handlers. */ void GraphBuilder::linkExBlocks() { const Func::EHEntVec& ehtab = m_func->ehtab(); // For every block, add edges to reachable fault and catch handlers. for (LinearBlocks i = linearBlocks(m_graph); !i.empty(); ) { Block* b = i.popFront(); assert(m_func->findEH(offset(b->start)) == m_func->findEH(offset(b->last))); Offset off = offset(b->start); int exn_index = 0; for (const EHEnt* eh = m_func->findEH(off); eh != 0; ) { assert(eh->m_base <= off && off < eh->m_past); if (eh->m_type == EHEnt::Type::Catch) { // each catch block is reachable from b for (Range<EHEnt::CatchVec> j(eh->m_catches); !j.empty(); ) { exns(b)[exn_index++] = at(j.popFront().second); } eh = nextOuter(ehtab, eh); } else { // this is the innermost fault funclet reachable from b. exns(b)[exn_index++] = at(eh->m_fault); break; } } if (Op(*b->last) == OpUnwind) { // We're in a fault funclet. Find which one, then add edges // to reachable catches and the enclosing fault funclet, if any. const EHEnt* eh = findFunclet(ehtab, offset(b->last)); eh = nextOuter(ehtab, eh); while (eh) { if (eh->m_type == EHEnt::Type::Catch) { // each catch target for eh is reachable from b for (Range<EHEnt::CatchVec> j(eh->m_catches); !j.empty(); ) { exns(b)[exn_index++] = at(j.popFront().second); } eh = nextOuter(ehtab, eh); } else { // eh is the innermost fault funclet reachable from b. exns(b)[exn_index++] = at(eh->m_fault); break; } } } } }
bool ProfData::anyBlockEndsAt(const Func* func, Offset offset) { auto const mapIt = m_blockEndOffsets.find(func->getFuncId()); if (mapIt != end(m_blockEndOffsets)) { return mapIt->second.count(offset); } using namespace Verifier; Arena arena; GraphBuilder builder{arena, func}; auto cfg = builder.build(); auto& offsets = m_blockEndOffsets[func->getFuncId()]; for (LinearBlocks blocks = linearBlocks(cfg); !blocks.empty(); ) { auto last = blocks.popFront()->last - func->unit()->entry(); offsets.insert(last); } return offsets.count(offset); }
bool Func::anyBlockEndsAt(Offset off) const { assert(JIT::Translator::WriteLease().amOwner()); // The empty() check relies on a Func's bytecode always being nonempty assert(base() != past()); if (m_shared->m_blockEnds.empty()) { using namespace Verifier; Arena arena; GraphBuilder builder{arena, this}; Graph* cfg = builder.build(); for (LinearBlocks blocks = linearBlocks(cfg); !blocks.empty(); ) { auto last = blocks.popFront()->last - m_unit->entry(); m_shared->m_blockEnds.insert(last); } assert(!m_shared->m_blockEnds.empty()); } return m_shared->m_blockEnds.count(off) != 0; }
void printGml(const Unit* unit) { string filename = unit->md5().toString() + ".gml"; FILE* file = fopen(filename.c_str(), "w"); if (!file) { std::cerr << "Couldn't open GML output file " << filename << std::endl; return; } int nextid = 1; fprintf(file, "graph [\n" " hierarchic 1\n" " directed 1\n"); for (AllFuncs i(unit); !i.empty(); ) { const Func* func = i.popFront(); Arena scratch; GraphBuilder builder(scratch, func); const Graph* g = builder.build(); int gid = nextid++; fprintf(file, "node [ isGroup 1 id %d ]\n", gid); // nodes for (LinearBlocks j = linearBlocks(g); !j.empty();) { const Block* b = j.popFront(); std::stringstream strbuf; unit->prettyPrint(strbuf, Unit::PrintOpts().range(unit->offsetOf(b->start), unit->offsetOf(b->end))); std::string code = strbuf.str(); for (int i = 0, n = code.size(); i < n; ++i) { if (code[i] == '"') code[i] = '\''; } fprintf(file, " node [ id %d gid %d\n" " graphics [ type \"roundrectangle\" ]" " LabelGraphics [" " anchor \"e\"" " alignment \"left\"" " fontName \"Consolas\"\n" " text \"%s\"\n" " ]\n" " ]\n", nextid + b->id, gid, code.c_str()); } // edges for (LinearBlocks j = linearBlocks(g); !j.empty();) { const Block* b = j.popFront(); for (BlockPtrRange k = succBlocks(b); !k.empty();) { const Block* s = k.popFront(); fprintf(file, " edge [ source %d target %d ]\n", nextid + b->id, nextid + s->id); } for (BlockPtrRange k = exnBlocks(g, b); !k.empty();) { const Block* s = k.popFront(); fprintf(file, " edge [ source %d target %d" " graphics [ style \"dotted\" ]" " ]\n", nextid + b->id, nextid + s->id); } } nextid += g->block_count + 1; } fprintf(file, "]\n"); fclose(file); }