ExnTreeInfo build_exn_tree(const FuncEmitter& fe, php::Func& func, FindBlock findBlock) { ExnTreeInfo ret; uint32_t nextExnNode = 0; for (auto& eh : fe.ehtab()) { auto node = folly::make_unique<php::ExnNode>(); node->id = nextExnNode++; node->parent = nullptr; switch (eh.m_type) { case EHEnt::Type::Fault: { auto const fault = findBlock(eh.m_fault); assert(ret.funcletNodes[fault] == nullptr); ret.funcletNodes[fault] = borrow(node); /* * We know the block for this offset starts a fault funclet, * but we won't know its extents until we've built the cfg and * can look at the control flow in the funclet. Set the block * type to Fault for now, but we won't propagate the value to * the rest of the funclet blocks until find_fault_funclets. */ fault->kind = php::Block::Kind::Fault; node->info = php::FaultRegion { fault, eh.m_iterId, eh.m_itRef }; } break; case EHEnt::Type::Catch: { auto treg = php::TryRegion {}; for (auto& centry : eh.m_catches) { auto const catchBlk = findBlock(centry.second); catchBlk->kind = php::Block::Kind::CatchEntry; treg.catches.emplace_back( fe.ue().lookupLitstr(centry.first), catchBlk ); } node->info = treg; } break; } ret.ehMap[&eh] = borrow(node); if (eh.m_parentIndex != -1) { auto it = ret.ehMap.find(&fe.ehtab()[eh.m_parentIndex]); assert(it != end(ret.ehMap)); node->parent = it->second; it->second->children.emplace_back(std::move(node)); } else { func.exnNodes.emplace_back(std::move(node)); } } return ret; }
ExnTreeInfo build_exn_tree(const FuncEmitter& fe, php::Func& func, FindBlock findBlock) { ExnTreeInfo ret; auto nextExnNode = uint32_t{0}; for (auto& eh : fe.ehtab()) { auto node = folly::make_unique<php::ExnNode>(); node->id = nextExnNode++; node->parent = nullptr; switch (eh.m_type) { case EHEnt::Type::Fault: { auto const fault = findBlock(eh.m_fault); ret.funcletNodes[fault].push_back(borrow(node)); ret.faultFuncletStarts.insert(eh.m_fault); node->info = php::FaultRegion { fault, eh.m_iterId, eh.m_itRef }; } break; case EHEnt::Type::Catch: { auto treg = php::TryRegion {}; for (auto& centry : eh.m_catches) { auto const catchBlk = findBlock(centry.second); treg.catches.emplace_back( fe.ue().lookupLitstr(centry.first), catchBlk ); } node->info = treg; } break; } ret.ehMap[&eh] = borrow(node); if (eh.m_parentIndex != -1) { auto it = ret.ehMap.find(&fe.ehtab()[eh.m_parentIndex]); assert(it != end(ret.ehMap)); node->parent = it->second; it->second->children.emplace_back(std::move(node)); } else { func.exnNodes.emplace_back(std::move(node)); } } ret.faultFuncletStarts.insert(fe.past()); return ret; }
void build_cfg(ParseUnitState& puState, php::Func& func, const FuncEmitter& fe) { auto const blockStarts = findBasicBlocks(fe); FTRACE(3, " blocks are at: {}\n", [&]() -> std::string { using namespace folly::gen; return from(blockStarts) | eachTo<std::string>() | unsplit<std::string>(" "); }() ); std::map<Offset,std::unique_ptr<php::Block>> blockMap; auto const bc = fe.ue().bc(); auto findBlock = [&] (Offset off) { auto& ptr = blockMap[off]; if (!ptr) { ptr = folly::make_unique<php::Block>(); ptr->id = func.nextBlockId++; ptr->section = php::Block::Section::Main; ptr->exnNode = nullptr; } return borrow(ptr); }; auto exnTreeInfo = build_exn_tree(fe, func, findBlock); for (auto it = begin(blockStarts); boost::next(it) != end(blockStarts); ++it) { auto const block = findBlock(*it); auto const bcStart = bc + *it; auto const bcStop = bc + *boost::next(it); if (auto const eh = findEH(fe.ehtab(), *it)) { auto it = exnTreeInfo.ehMap.find(eh); assert(it != end(exnTreeInfo.ehMap)); block->exnNode = it->second; add_factored_exits(*block, block->exnNode); } populate_block(puState, fe, func, *block, bcStart, bcStop, findBlock); } link_entry_points(func, fe, findBlock); find_fault_funclets(exnTreeInfo, func, blockStarts, findBlock); for (auto& kv : blockMap) { func.blocks.emplace_back(std::move(kv.second)); } }
void emit_eh_region(FuncEmitter& fe, borrowed_ptr<const EHRegion> region, const BlockInfo& blockInfo, ParentIndexMap& parentIndexMap) { // A region on a single empty block. if (region->start == region->past) return; auto& eh = fe.addEHEnt(); eh.m_base = region->start; eh.m_past = region->past; assert(eh.m_past >= eh.m_base); assert(eh.m_base != kInvalidOffset && eh.m_past != kInvalidOffset); if (region->parent) { auto parentIt = parentIndexMap.find(region->parent); assert(parentIt != end(parentIndexMap)); eh.m_parentIndex = parentIt->second; } else { eh.m_parentIndex = -1; } parentIndexMap[region] = fe.ehtab().size() - 1; match<void>( region->node->info, [&] (const php::TryRegion& tr) { eh.m_type = EHEnt::Type::Catch; for (auto& c : tr.catches) { eh.m_catches.emplace_back( fe.ue().mergeLitstr(c.first), blockInfo[c.second->id].offset ); } eh.m_fault = kInvalidOffset; eh.m_iterId = -1; eh.m_itRef = false; }, [&] (const php::FaultRegion& fr) { eh.m_type = EHEnt::Type::Fault; eh.m_fault = blockInfo[fr.faultEntry->id].offset; eh.m_iterId = fr.iterId; eh.m_itRef = fr.itRef; } ); }