+
+ result.append(block);
+ worklist.append(block);
+ seen.add(block);
+}
+
+void Graph::getBlocksInDepthFirstOrder(Vector<BasicBlock*>& result)
+{
+ Vector<BasicBlock*, 16> worklist;
+ HashSet<BasicBlock*> seen;
+ addForDepthFirstSort(result, worklist, seen, block(0));
+ while (!worklist.isEmpty()) {
+ BasicBlock* block = worklist.takeLast();
+ for (unsigned i = block->numSuccessors(); i--;)
+ addForDepthFirstSort(result, worklist, seen, block->successor(i));
+ }
+}
+
+void Graph::clearReplacements()
+{
+ for (BlockIndex blockIndex = numBlocks(); blockIndex--;) {
+ BasicBlock* block = m_blocks[blockIndex].get();
+ if (!block)
+ continue;
+ for (unsigned phiIndex = block->phis.size(); phiIndex--;)
+ block->phis[phiIndex]->misc.replacement = 0;
+ for (unsigned nodeIndex = block->size(); nodeIndex--;)
+ block->at(nodeIndex)->misc.replacement = 0;
+ }
+}
+
+void Graph::initializeNodeOwners()
+{
+ for (BlockIndex blockIndex = numBlocks(); blockIndex--;) {
+ BasicBlock* block = m_blocks[blockIndex].get();
+ if (!block)
+ continue;
+ for (unsigned phiIndex = block->phis.size(); phiIndex--;)
+ block->phis[phiIndex]->misc.owner = block;
+ for (unsigned nodeIndex = block->size(); nodeIndex--;)
+ block->at(nodeIndex)->misc.owner = block;
+ }
+}
+
+void Graph::clearFlagsOnAllNodes(NodeFlags flags)
+{
+ for (BlockIndex blockIndex = numBlocks(); blockIndex--;) {
+ BasicBlock* block = m_blocks[blockIndex].get();
+ if (!block)
+ continue;
+ for (unsigned phiIndex = block->phis.size(); phiIndex--;)
+ block->phis[phiIndex]->clearFlags(flags);
+ for (unsigned nodeIndex = block->size(); nodeIndex--;)
+ block->at(nodeIndex)->clearFlags(flags);
+ }
+}
+
+FullBytecodeLiveness& Graph::livenessFor(CodeBlock* codeBlock)
+{
+ HashMap<CodeBlock*, std::unique_ptr<FullBytecodeLiveness>>::iterator iter = m_bytecodeLiveness.find(codeBlock);
+ if (iter != m_bytecodeLiveness.end())
+ return *iter->value;
+
+ std::unique_ptr<FullBytecodeLiveness> liveness = std::make_unique<FullBytecodeLiveness>();
+ codeBlock->livenessAnalysis().computeFullLiveness(*liveness);
+ FullBytecodeLiveness& result = *liveness;
+ m_bytecodeLiveness.add(codeBlock, WTF::move(liveness));
+ return result;
+}
+
+FullBytecodeLiveness& Graph::livenessFor(InlineCallFrame* inlineCallFrame)
+{
+ return livenessFor(baselineCodeBlockFor(inlineCallFrame));
+}
+
+bool Graph::isLiveInBytecode(VirtualRegister operand, CodeOrigin codeOrigin)
+{
+ for (;;) {
+ VirtualRegister reg = VirtualRegister(
+ operand.offset() - codeOrigin.stackOffset());
+
+ if (operand.offset() < codeOrigin.stackOffset() + JSStack::CallFrameHeaderSize) {
+ if (reg.isArgument()) {
+ RELEASE_ASSERT(reg.offset() < JSStack::CallFrameHeaderSize);
+
+ if (!codeOrigin.inlineCallFrame->isClosureCall)
+ return false;
+
+ if (reg.offset() == JSStack::Callee)
+ return true;
+ if (reg.offset() == JSStack::ScopeChain)
+ return true;
+
+ return false;
+ }
+
+ return livenessFor(codeOrigin.inlineCallFrame).operandIsLive(
+ reg.offset(), codeOrigin.bytecodeIndex);
+ }
+
+ InlineCallFrame* inlineCallFrame = codeOrigin.inlineCallFrame;
+ if (!inlineCallFrame)
+ break;
+
+ // Arguments are always live. This would be redundant if it wasn't for our
+ // op_call_varargs inlining.
+ // FIXME: 'this' might not be live, but we don't have a way of knowing.
+ // https://bugs.webkit.org/show_bug.cgi?id=128519
+ if (reg.isArgument()
+ && static_cast<size_t>(reg.toArgument()) < inlineCallFrame->arguments.size())
+ return true;
+
+ codeOrigin = inlineCallFrame->caller;
+ }
+
+ return true;
+}
+
+unsigned Graph::frameRegisterCount()
+{
+ unsigned result = m_nextMachineLocal + std::max(m_parameterSlots, static_cast<unsigned>(maxFrameExtentForSlowPathCallInRegisters));
+ return roundLocalRegisterCountForFramePointerOffset(result);
+}
+
+unsigned Graph::stackPointerOffset()
+{
+ return virtualRegisterForLocal(frameRegisterCount() - 1).offset();
+}
+
+unsigned Graph::requiredRegisterCountForExit()
+{
+ unsigned count = JIT::frameRegisterCountFor(m_profiledBlock);
+ for (InlineCallFrameSet::iterator iter = m_plan.inlineCallFrames->begin(); !!iter; ++iter) {
+ InlineCallFrame* inlineCallFrame = *iter;
+ CodeBlock* codeBlock = baselineCodeBlockForInlineCallFrame(inlineCallFrame);
+ unsigned requiredCount = VirtualRegister(inlineCallFrame->stackOffset).toLocal() + 1 + JIT::frameRegisterCountFor(codeBlock);
+ count = std::max(count, requiredCount);
+ }
+ return count;
+}
+
+unsigned Graph::requiredRegisterCountForExecutionAndExit()
+{
+ return std::max(frameRegisterCount(), requiredRegisterCountForExit());
+}
+
+JSActivation* Graph::tryGetActivation(Node* node)
+{
+ if (!node->hasConstant())
+ return 0;
+ return jsDynamicCast<JSActivation*>(valueOfJSConstant(node));
+}
+
+WriteBarrierBase<Unknown>* Graph::tryGetRegisters(Node* node)
+{
+ JSActivation* activation = tryGetActivation(node);
+ if (!activation)
+ return 0;
+ if (!activation->isTornOff())
+ return 0;
+ return activation->registers();
+}
+
+JSArrayBufferView* Graph::tryGetFoldableView(Node* node)
+{
+ if (!node->hasConstant())
+ return 0;
+ JSArrayBufferView* view = jsDynamicCast<JSArrayBufferView*>(valueOfJSConstant(node));
+ if (!view)
+ return 0;
+ if (!watchpoints().isStillValid(view))
+ return 0;
+ return view;
+}
+
+JSArrayBufferView* Graph::tryGetFoldableView(Node* node, ArrayMode arrayMode)
+{
+ if (arrayMode.typedArrayType() == NotTypedArray)
+ return 0;
+ return tryGetFoldableView(node);
+}
+
+JSArrayBufferView* Graph::tryGetFoldableViewForChild1(Node* node)
+{
+ return tryGetFoldableView(child(node, 0).node(), node->arrayMode());
+}
+
+void Graph::visitChildren(SlotVisitor& visitor)
+{
+ for (BlockIndex blockIndex = numBlocks(); blockIndex--;) {
+ BasicBlock* block = this->block(blockIndex);
+ if (!block)
+ continue;
+
+ for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) {
+ Node* node = block->at(nodeIndex);
+
+ switch (node->op()) {
+ case JSConstant:
+ case WeakJSConstant:
+ visitor.appendUnbarrieredReadOnlyValue(valueOfJSConstant(node));
+ break;
+
+ case CheckFunction:
+ visitor.appendUnbarrieredReadOnlyPointer(node->function());
+ break;
+
+ case CheckExecutable:
+ visitor.appendUnbarrieredReadOnlyPointer(node->executable());
+ break;
+
+ case CheckStructure:
+ for (unsigned i = node->structureSet().size(); i--;)
+ visitor.appendUnbarrieredReadOnlyPointer(node->structureSet()[i]);
+ break;
+
+ case StructureTransitionWatchpoint:
+ case NewObject:
+ case ArrayifyToStructure:
+ case NewStringObject:
+ visitor.appendUnbarrieredReadOnlyPointer(node->structure());
+ break;
+
+ case PutStructure:
+ case PhantomPutStructure:
+ case AllocatePropertyStorage:
+ case ReallocatePropertyStorage:
+ visitor.appendUnbarrieredReadOnlyPointer(
+ node->structureTransitionData().previousStructure);
+ visitor.appendUnbarrieredReadOnlyPointer(
+ node->structureTransitionData().newStructure);
+ break;
+
+ default:
+ break;
+ }
+ }
+ }