static bool isMainExit(const Block* b) { if (b->hint() == Block::Hint::Unlikely) return false; if (b->next()) return false; auto taken = b->taken(); if (!taken) return true; if (taken->isCatch()) return true; return false; }
/* * Whether the block appears to be the exit block of the main code * path of a region. This is conservative, so it may return false on * all blocks in a region. */ static bool isMainExit(const Block* b) { if (!isMainBlock(b)) return false; if (b->next()) return false; // The Await bytecode instruction does a RetCtrl to the scheduler, // which is in a likely block. We don't want to consider this as // the main exit. auto const& back = b->back(); if (back.op() == RetCtrl && back.marker().sk().op() == OpAwait) return false; auto const taken = b->taken(); return !taken || taken->isCatch(); }
/* * Unit */ void print(std::ostream& os, const IRUnit& unit, const AsmInfo* asmInfo, const GuardConstraints* guards) { // For nice-looking dumps, we want to remember curMarker between blocks. BCMarker curMarker; static bool dotBodies = getenv("HHIR_DOT_BODIES"); auto blocks = rpoSortCfg(unit); // Partition into main, cold and frozen, without changing relative order. auto cold = std::stable_partition(blocks.begin(), blocks.end(), [&] (Block* b) { return b->hint() == Block::Hint::Neither || b->hint() == Block::Hint::Likely; } ); auto frozen = std::stable_partition(cold, blocks.end(), [&] (Block* b) { return b->hint() == Block::Hint::Unlikely; } ); if (dumpIREnabled(kExtraExtraLevel)) printOpcodeStats(os, blocks); // Print the block CFG above the actual code. auto const retreating_edges = findRetreatingEdges(unit); os << "digraph G {\n"; for (auto block : blocks) { if (block->empty()) continue; if (dotBodies && block->hint() != Block::Hint::Unlikely && block->hint() != Block::Hint::Unused) { // Include the IR in the body of the node std::ostringstream out; print(out, block, AreaIndex::Main, asmInfo, guards, &curMarker); auto bodyRaw = out.str(); std::string body; body.reserve(bodyRaw.size() * 1.25); for (auto c : bodyRaw) { if (c == '\n') body += "\\n"; else if (c == '"') body += "\\\""; else if (c == '\\') body += "\\\\"; else body += c; } os << folly::format("B{} [shape=\"box\" label=\"{}\"]\n", block->id(), body); } auto next = block->nextEdge(); auto taken = block->takenEdge(); if (!next && !taken) continue; auto edge_color = [&] (Edge* edge) { auto const target = edge->to(); return target->isCatch() ? " [color=blue]" : target->isExit() ? " [color=cyan]" : retreating_edges.count(edge) ? " [color=red]" : target->hint() == Block::Hint::Unlikely ? " [color=green]" : ""; }; auto show_edge = [&] (Edge* edge) { os << folly::format( "B{} -> B{}{}", block->id(), edge->to()->id(), edge_color(edge) ); }; if (next) { show_edge(next); if (taken) os << "; "; } if (taken) show_edge(taken); os << "\n"; } os << "}\n"; AreaIndex currentArea = AreaIndex::Main; curMarker = BCMarker(); for (auto it = blocks.begin(); it != blocks.end(); ++it) { if (it == cold) { os << folly::format("\n{:-^60}", "cold blocks"); currentArea = AreaIndex::Cold; } if (it == frozen) { os << folly::format("\n{:-^60}", "frozen blocks"); currentArea = AreaIndex::Frozen; } print(os, *it, currentArea, asmInfo, guards, &curMarker); } }