void treatRegularBlock(BasicBlock* block, InsertionSet& insertionSet)
    {
        Operands<VariableAccessData*> currentBlockAccessData(block->variablesAtTail.numberOfArguments(), block->variablesAtTail.numberOfLocals(), nullptr);
        // Insert a Flush before every SetLocal to properly pattern the graph such that 
        // any range between SetLocal and Flush has access to the local on the stack.
        {
            for (unsigned i = 0; i < block->size(); i++) {
                Node* node = block->at(i);
                bool isPrimordialSetArgument = node->op() == SetArgument && node->local().isArgument() && node == m_graph.m_arguments[node->local().toArgument()];
                if (node->op() == SetLocal || (node->op() == SetArgument && !isPrimordialSetArgument)) {
                    VirtualRegister operand = node->local();
                    VariableAccessData* flushAccessData = currentBlockAccessData.operand(operand);
                    if (!flushAccessData)
                        flushAccessData = newVariableAccessData(operand);

                    insertionSet.insertNode(i, SpecNone, 
                        Flush, node->origin, OpInfo(flushAccessData));
                }

                if (node->hasVariableAccessData(m_graph))
                    currentBlockAccessData.operand(node->local()) = node->variableAccessData();
            }
        }

        // Flush everything at the end of the block.
        {
            NodeOrigin origin = block->at(block->size() - 1)->origin;
            auto insertFlushAtEnd = [&] (VirtualRegister operand) {
                VariableAccessData* accessData = currentBlockAccessData.operand(operand);
                if (!accessData)
                    accessData = newVariableAccessData(operand);

                currentBlockAccessData.operand(operand) = accessData;

                insertionSet.insertNode(block->size(), SpecNone, 
                    Flush, origin, OpInfo(accessData));
            };

            for (unsigned i = 0; i < block->variablesAtTail.numberOfLocals(); i++)
                insertFlushAtEnd(virtualRegisterForLocal(i));
            for (unsigned i = 0; i < block->variablesAtTail.numberOfArguments(); i++)
                insertFlushAtEnd(virtualRegisterForArgument(i));
        }
    }
    void handleBlockForTryCatch(BasicBlock* block, InsertionSet& insertionSet)
    {
        HandlerInfo* currentExceptionHandler = nullptr;
        FastBitVector liveAtCatchHead;
        liveAtCatchHead.resize(m_graph.block(0)->variablesAtTail.numberOfLocals());

        HandlerInfo* cachedHandlerResult;
        CodeOrigin cachedCodeOrigin;
        auto catchHandler = [&] (CodeOrigin origin) -> HandlerInfo* {
            ASSERT(origin);
            if (origin == cachedCodeOrigin)
                return cachedHandlerResult;

            unsigned bytecodeIndexToCheck = origin.bytecodeIndex;

            cachedCodeOrigin = origin;

            while (1) {
                InlineCallFrame* inlineCallFrame = origin.inlineCallFrame;
                CodeBlock* codeBlock = m_graph.baselineCodeBlockFor(inlineCallFrame);
                if (HandlerInfo* handler = codeBlock->handlerForBytecodeOffset(bytecodeIndexToCheck)) {
                    liveAtCatchHead.clearAll();

                    unsigned catchBytecodeIndex = handler->target;
                    m_graph.forAllLocalsLiveInBytecode(CodeOrigin(catchBytecodeIndex, inlineCallFrame), [&] (VirtualRegister operand) {
                        liveAtCatchHead[operand.toLocal()] = true;
                    });

                    cachedHandlerResult = handler;
                    break;
                }

                if (!inlineCallFrame) {
                    cachedHandlerResult = nullptr;
                    break;
                }

                bytecodeIndexToCheck = inlineCallFrame->directCaller.bytecodeIndex;
                origin = inlineCallFrame->directCaller;
            }

            return cachedHandlerResult;
        };

        Operands<VariableAccessData*> currentBlockAccessData(block->variablesAtTail.numberOfArguments(), block->variablesAtTail.numberOfLocals(), nullptr);
        HashSet<InlineCallFrame*> seenInlineCallFrames;

        auto flushEverything = [&] (NodeOrigin origin, unsigned index) {
            RELEASE_ASSERT(currentExceptionHandler);
            auto flush = [&] (VirtualRegister operand, bool alwaysInsert) {
                if ((operand.isLocal() && liveAtCatchHead[operand.toLocal()]) 
                    || operand.isArgument()
                    || alwaysInsert) {

                    ASSERT(isValidFlushLocation(block, index, operand));

                    VariableAccessData* accessData = currentBlockAccessData.operand(operand);
                    if (!accessData)
                        accessData = newVariableAccessData(operand);

                    currentBlockAccessData.operand(operand) = accessData;

                    insertionSet.insertNode(index, SpecNone, 
                        Flush, origin, OpInfo(accessData));
                }
            };

            for (unsigned local = 0; local < block->variablesAtTail.numberOfLocals(); local++)
                flush(virtualRegisterForLocal(local), false);
            for (InlineCallFrame* inlineCallFrame : seenInlineCallFrames)
                flush(VirtualRegister(inlineCallFrame->stackOffset + CallFrame::thisArgumentOffset()), true);
            flush(VirtualRegister(CallFrame::thisArgumentOffset()), true);

            seenInlineCallFrames.clear();
        };

        for (unsigned nodeIndex = 0; nodeIndex < block->size(); nodeIndex++) {
            Node* node = block->at(nodeIndex);

            {
                HandlerInfo* newHandler = catchHandler(node->origin.semantic);
                if (newHandler != currentExceptionHandler && currentExceptionHandler)
                    flushEverything(node->origin, nodeIndex);
                currentExceptionHandler = newHandler;
            }

            if (currentExceptionHandler && (node->op() == SetLocal || node->op() == SetArgument)) {
                InlineCallFrame* inlineCallFrame = node->origin.semantic.inlineCallFrame;
                if (inlineCallFrame)
                    seenInlineCallFrames.add(inlineCallFrame);
                VirtualRegister operand = node->local();

                int stackOffset = inlineCallFrame ? inlineCallFrame->stackOffset : 0;
                if ((operand.isLocal() && liveAtCatchHead[operand.toLocal()])
                    || operand.isArgument()
                    || (operand.offset() == stackOffset + CallFrame::thisArgumentOffset())) {

                    ASSERT(isValidFlushLocation(block, nodeIndex, operand));

                    VariableAccessData* variableAccessData = currentBlockAccessData.operand(operand);
                    if (!variableAccessData)
                        variableAccessData = newVariableAccessData(operand);

                    insertionSet.insertNode(nodeIndex, SpecNone, 
                        Flush, node->origin, OpInfo(variableAccessData));
                }
            }

            if (node->accessesStack(m_graph))
                currentBlockAccessData.operand(node->local()) = node->variableAccessData();
        }

        if (currentExceptionHandler) {
            NodeOrigin origin = block->at(block->size() - 1)->origin;
            flushEverything(origin, block->size());
        }
    }