// OSR fixups serve the purpose of representing the non-OSR entry into a loop
// when the only real entry is an OSR entry into the middle. However, if the
// entry into the middle is subsequently folded away, the loop may actually
// have become unreachable. Mark-and-sweep all blocks to remove all such code.
bool ValueNumberer::cleanupOSRFixups()
{
    // Mark.
    Vector<MBasicBlock*, 0, JitAllocPolicy> worklist(graph_.alloc());
    unsigned numMarked = 2;
    graph_.entryBlock()->mark();
    graph_.osrBlock()->mark();
    if (!worklist.append(graph_.entryBlock()) || !worklist.append(graph_.osrBlock()))
        return false;
    while (!worklist.empty()) {
        MBasicBlock* block = worklist.popCopy();
        for (size_t i = 0, e = block->numSuccessors(); i != e; ++i) {
            MBasicBlock* succ = block->getSuccessor(i);
            if (!succ->isMarked()) {
                ++numMarked;
                succ->mark();
                if (!worklist.append(succ))
                    return false;
            } else if (succ->isLoopHeader() &&
                       succ->loopPredecessor() == block &&
                       succ->numPredecessors() == 3)
            {
                // Unmark fixup blocks if the loop predecessor is marked after
                // the loop header.
                succ->getPredecessor(1)->unmarkUnchecked();
            }
        }

        // OSR fixup blocks are needed if and only if the loop header is
        // reachable from its backedge (via the OSR block) and not from its
        // original loop predecessor.
        //
        // Thus OSR fixup blocks are removed if the loop header is not
        // reachable, or if the loop header is reachable from both its backedge
        // and its original loop predecessor.
        if (block->isLoopHeader()) {
            MBasicBlock* maybeFixupBlock = nullptr;
            if (block->numPredecessors() == 2) {
                maybeFixupBlock = block->getPredecessor(0);
            } else {
                MOZ_ASSERT(block->numPredecessors() == 3);
                if (!block->loopPredecessor()->isMarked())
                    maybeFixupBlock = block->getPredecessor(1);
            }

            if (maybeFixupBlock &&
                !maybeFixupBlock->isMarked() &&
                maybeFixupBlock->numPredecessors() == 0)
            {
                MOZ_ASSERT(maybeFixupBlock->numSuccessors() == 1,
                           "OSR fixup block should have exactly one successor");
                MOZ_ASSERT(maybeFixupBlock != graph_.entryBlock(),
                           "OSR fixup block shouldn't be the entry block");
                MOZ_ASSERT(maybeFixupBlock != graph_.osrBlock(),
                           "OSR fixup block shouldn't be the OSR entry block");
                maybeFixupBlock->mark();
            }
        }
    }

    // And sweep.
    return RemoveUnmarkedBlocks(mir_, graph_, numMarked);
}