void jettisonBlock(BasicBlock* block, BasicBlock* jettisonedBlock, CodeOrigin boundaryCodeOrigin) { for (size_t i = 0; i < jettisonedBlock->variablesAtHead.numberOfArguments(); ++i) keepOperandAlive(block, jettisonedBlock, boundaryCodeOrigin, argumentToOperand(i)); for (size_t i = 0; i < jettisonedBlock->variablesAtHead.numberOfLocals(); ++i) keepOperandAlive(block, jettisonedBlock, boundaryCodeOrigin, localToOperand(i)); fixJettisonedPredecessors(block, jettisonedBlock); }
void jettisonBlock(BlockIndex blockIndex, BlockIndex jettisonedBlockIndex, CodeOrigin boundaryCodeOrigin) { BasicBlock* block = m_graph.m_blocks[blockIndex].get(); BasicBlock* jettisonedBlock = m_graph.m_blocks[jettisonedBlockIndex].get(); for (size_t i = 0; i < jettisonedBlock->variablesAtHead.numberOfArguments(); ++i) keepOperandAlive(block, jettisonedBlock, boundaryCodeOrigin, argumentToOperand(i)); for (size_t i = 0; i < jettisonedBlock->variablesAtHead.numberOfLocals(); ++i) keepOperandAlive(block, jettisonedBlock, boundaryCodeOrigin, i); fixJettisonedPredecessors(blockIndex, jettisonedBlockIndex); }
BytecodeSequence::BytecodeSequence(CodeBlock* codeBlock) { StringPrintStream out; #if ENABLE(VALUE_PROFILER) for (unsigned i = 0; i < codeBlock->numberOfArgumentValueProfiles(); ++i) { CString description = codeBlock->valueProfileForArgument(i)->briefDescription(); if (!description.length()) continue; out.reset(); out.print("arg", i, " (r", argumentToOperand(i), "): ", description); m_header.append(out.toCString()); } #endif // ENABLE(VALUE_PROFILER) for (unsigned bytecodeIndex = 0; bytecodeIndex < codeBlock->instructions().size();) { out.reset(); codeBlock->dumpBytecode(out, bytecodeIndex); m_sequence.append(Bytecode(bytecodeIndex, codeBlock->globalData()->interpreter->getOpcodeID(codeBlock->instructions()[bytecodeIndex].u.opcode), out.toCString())); bytecodeIndex += opcodeLength( codeBlock->globalData()->interpreter->getOpcodeID( codeBlock->instructions()[bytecodeIndex].u.opcode)); } }
void mergeBlocks( BasicBlock* firstBlock, BasicBlock* secondBlock, Vector<BasicBlock*, 1> jettisonedBlocks) { // This will add all of the nodes in secondBlock to firstBlock, but in so doing // it will also ensure that any GetLocals from the second block that refer to // SetLocals in the first block are relinked. If jettisonedBlock is not NoBlock, // then Phantoms are inserted for anything that the jettisonedBlock would have // kept alive. // Remove the terminal of firstBlock since we don't need it anymore. Well, we don't // really remove it; we actually turn it into a Phantom. ASSERT(firstBlock->last()->isTerminal()); CodeOrigin boundaryCodeOrigin = firstBlock->last()->codeOrigin; firstBlock->last()->convertToPhantom(); ASSERT(firstBlock->last()->refCount() == 1); for (unsigned i = jettisonedBlocks.size(); i--;) { BasicBlock* jettisonedBlock = jettisonedBlocks[i]; // Time to insert ghosties for things that need to be kept alive in case we OSR // exit prior to hitting the firstBlock's terminal, and end up going down a // different path than secondBlock. for (size_t i = 0; i < jettisonedBlock->variablesAtHead.numberOfArguments(); ++i) keepOperandAlive(firstBlock, jettisonedBlock, boundaryCodeOrigin, argumentToOperand(i)); for (size_t i = 0; i < jettisonedBlock->variablesAtHead.numberOfLocals(); ++i) keepOperandAlive(firstBlock, jettisonedBlock, boundaryCodeOrigin, localToOperand(i)); } for (size_t i = 0; i < secondBlock->phis.size(); ++i) firstBlock->phis.append(secondBlock->phis[i]); for (size_t i = 0; i < secondBlock->size(); ++i) firstBlock->append(secondBlock->at(i)); ASSERT(firstBlock->last()->isTerminal()); // Fix the predecessors of my new successors. This is tricky, since we are going to reset // all predecessors anyway due to reachability analysis. But we need to fix the // predecessors eagerly to ensure that we know what they are in case the next block we // consider in this phase wishes to query the predecessors of one of the blocks we // affected. for (unsigned i = firstBlock->numSuccessors(); i--;) { BasicBlock* successor = firstBlock->successor(i); for (unsigned j = 0; j < successor->predecessors.size(); ++j) { if (successor->predecessors[j] == secondBlock) successor->predecessors[j] = firstBlock; } } // Fix the predecessors of my former successors. Again, we'd rather not do this, but it's // an unfortunate necessity. See above comment. for (unsigned i = jettisonedBlocks.size(); i--;) fixJettisonedPredecessors(firstBlock, jettisonedBlocks[i]); firstBlock->valuesAtTail = secondBlock->valuesAtTail; firstBlock->cfaBranchDirection = secondBlock->cfaBranchDirection; m_graph.killBlock(secondBlock); }
void validate() { // NB. This code is not written for performance, since it is not intended to run // in release builds. // Validate that all local variables at the head of the root block are dead. BasicBlock* root = m_graph.m_blocks[0].get(); for (unsigned i = 0; i < root->variablesAtHead.numberOfLocals(); ++i) V_EQUAL((static_cast<VirtualRegister>(i), 0), static_cast<Node*>(0), root->variablesAtHead.local(i)); // Validate ref counts and uses. HashMap<Node*, unsigned> myRefCounts; for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) { BasicBlock* block = m_graph.m_blocks[blockIndex].get(); if (!block || !block->isReachable) continue; for (size_t i = 0; i < block->numNodes(); ++i) myRefCounts.add(block->node(i), 0); } HashSet<Node*> acceptableNodes; for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) { BasicBlock* block = m_graph.m_blocks[blockIndex].get(); if (!block || !block->isReachable) continue; for (size_t i = 0; i < block->numNodes(); ++i) { Node* node = block->node(i); acceptableNodes.add(node); if (!node->shouldGenerate()) continue; for (unsigned j = 0; j < m_graph.numChildren(node); ++j) { // Phi children in LoadStore form are invalid. if (m_graph.m_form == LoadStore && block->isPhiIndex(i)) continue; Edge edge = m_graph.child(node, j); if (!edge) continue; myRefCounts.find(edge.node())->value++; // Unless I'm a Flush, Phantom, GetLocal, or Phi, my children should hasResult(). switch (node->op()) { case Flush: case GetLocal: case PhantomLocal: VALIDATE((node, edge), edge->hasVariableAccessData()); VALIDATE((node, edge), edge->variableAccessData() == node->variableAccessData()); break; case Phi: VALIDATE((node, edge), edge->hasVariableAccessData()); if (m_graph.m_unificationState == LocallyUnified) break; VALIDATE((node, edge), edge->variableAccessData() == node->variableAccessData()); break; case Phantom: if (m_graph.m_form == LoadStore && !j) break; default: VALIDATE((node, edge), edge->hasResult()); break; } } } } for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) { BasicBlock* block = m_graph.m_blocks[blockIndex].get(); if (!block || !block->isReachable) continue; HashSet<Node*> phisInThisBlock; HashSet<Node*> nodesInThisBlock; for (size_t i = 0; i < block->numNodes(); ++i) { Node* node = block->node(i); nodesInThisBlock.add(node); if (block->isPhiIndex(i)) phisInThisBlock.add(node); if (m_graph.m_form == ThreadedCPS || !node->hasVariableAccessData()) V_EQUAL((node), myRefCounts.get(node), node->adjustedRefCount()); else VALIDATE((node), myRefCounts.get(node) ? node->adjustedRefCount() : true); for (unsigned j = 0; j < m_graph.numChildren(node); ++j) { Edge edge = m_graph.child(node, j); if (!edge) continue; VALIDATE((node, edge), acceptableNodes.contains(edge.node())); } } for (size_t i = 0; i < block->phis.size(); ++i) { Node* node = block->phis[i]; ASSERT(phisInThisBlock.contains(node)); VALIDATE((node), node->op() == Phi); VirtualRegister local = node->local(); for (unsigned j = 0; j < m_graph.numChildren(node); ++j) { // Phi children in LoadStore form are invalid. if (m_graph.m_form == LoadStore && block->isPhiIndex(i)) continue; Edge edge = m_graph.child(node, j); if (!edge) continue; VALIDATE( (node, edge), edge->op() == SetLocal || edge->op() == SetArgument || edge->op() == Flush || edge->op() == Phi); if (phisInThisBlock.contains(edge.node())) continue; if (nodesInThisBlock.contains(edge.node())) { VALIDATE( (node, edge), edge->op() == SetLocal || edge->op() == SetArgument || edge->op() == Flush); continue; } // There must exist a predecessor block that has this node index in // its tail variables. bool found = false; for (unsigned k = 0; k < block->m_predecessors.size(); ++k) { BasicBlock* prevBlock = m_graph.m_blocks[block->m_predecessors[k]].get(); VALIDATE((Block, block->m_predecessors[k]), prevBlock); VALIDATE((Block, block->m_predecessors[k]), prevBlock->isReachable); Node* prevNode = prevBlock->variablesAtTail.operand(local); // If we have a Phi that is not referring to *this* block then all predecessors // must have that local available. VALIDATE((local, blockIndex, Block, block->m_predecessors[k]), prevNode); switch (prevNode->op()) { case GetLocal: case Flush: case PhantomLocal: prevNode = prevNode->child1().node(); break; default: break; } if (node->shouldGenerate()) { VALIDATE((local, block->m_predecessors[k], prevNode), prevNode->shouldGenerate()); } VALIDATE( (local, block->m_predecessors[k], prevNode), prevNode->op() == SetLocal || prevNode->op() == SetArgument || prevNode->op() == Phi); if (prevNode == edge.node()) { found = true; break; } // At this point it cannot refer into this block. VALIDATE((local, block->m_predecessors[k], prevNode), !prevBlock->isInBlock(edge.node())); } VALIDATE((node, edge), found); } } Operands<size_t> getLocalPositions( block->variablesAtHead.numberOfArguments(), block->variablesAtHead.numberOfLocals()); Operands<size_t> setLocalPositions( block->variablesAtHead.numberOfArguments(), block->variablesAtHead.numberOfLocals()); for (size_t i = 0; i < block->variablesAtHead.numberOfArguments(); ++i) { VALIDATE((static_cast<VirtualRegister>(argumentToOperand(i)), blockIndex), !block->variablesAtHead.argument(i) || block->variablesAtHead.argument(i)->hasVariableAccessData()); if (m_graph.m_form == ThreadedCPS) VALIDATE((static_cast<VirtualRegister>(argumentToOperand(i)), blockIndex), !block->variablesAtTail.argument(i) || block->variablesAtTail.argument(i)->hasVariableAccessData()); getLocalPositions.argument(i) = notSet; setLocalPositions.argument(i) = notSet; } for (size_t i = 0; i < block->variablesAtHead.numberOfLocals(); ++i) { VALIDATE((static_cast<VirtualRegister>(i), blockIndex), !block->variablesAtHead.local(i) || block->variablesAtHead.local(i)->hasVariableAccessData()); if (m_graph.m_form == ThreadedCPS) VALIDATE((static_cast<VirtualRegister>(i), blockIndex), !block->variablesAtTail.local(i) || block->variablesAtTail.local(i)->hasVariableAccessData()); getLocalPositions.local(i) = notSet; setLocalPositions.local(i) = notSet; } for (size_t i = 0; i < block->size(); ++i) { Node* node = block->at(i); ASSERT(nodesInThisBlock.contains(node)); VALIDATE((node), node->op() != Phi); for (unsigned j = 0; j < m_graph.numChildren(node); ++j) { Edge edge = m_graph.child(node, j); if (!edge) continue; VALIDATE((node, edge), nodesInThisBlock.contains(edge.node())); switch (node->op()) { case PhantomLocal: case GetLocal: case Flush: break; case Phantom: if (m_graph.m_form == LoadStore && !j) break; default: VALIDATE((node, edge), !phisInThisBlock.contains(edge.node())); break; } } if (!node->shouldGenerate()) continue; switch (node->op()) { case GetLocal: if (node->variableAccessData()->isCaptured()) break; if (m_graph.m_form == ThreadedCPS) VALIDATE((node, blockIndex), getLocalPositions.operand(node->local()) == notSet); getLocalPositions.operand(node->local()) = i; break; case SetLocal: if (node->variableAccessData()->isCaptured()) break; // Only record the first SetLocal. There may be multiple SetLocals // because of flushing. if (setLocalPositions.operand(node->local()) != notSet) break; setLocalPositions.operand(node->local()) = i; break; default: break; } } if (m_graph.m_form == LoadStore) continue; for (size_t i = 0; i < block->variablesAtHead.numberOfArguments(); ++i) { checkOperand( blockIndex, getLocalPositions, setLocalPositions, argumentToOperand(i)); } for (size_t i = 0; i < block->variablesAtHead.numberOfLocals(); ++i) { checkOperand( blockIndex, getLocalPositions, setLocalPositions, i); } } }