static void stepOverInstruction(CodeBlock* codeBlock, BytecodeBasicBlock* block, Vector<std::unique_ptr<BytecodeBasicBlock>>& basicBlocks, unsigned bytecodeOffset, const UseFunctor& use, const DefFunctor& def) { // This abstractly execute the instruction in reverse. Instructions logically first use operands and // then define operands. This logical ordering is necessary for operations that use and def the same // operand, like: // // op_add loc1, loc1, loc2 // // The use of loc1 happens before the def of loc1. That's a semantic requirement since the add // operation cannot travel forward in time to read the value that it will produce after reading that // value. Since we are executing in reverse, this means that we must do defs before uses (reverse of // uses before defs). // // Since this is a liveness analysis, this ordering ends up being particularly important: if we did // uses before defs, then the add operation above would appear to not have loc1 live, since we'd // first add it to the out set (the use), and then we'd remove it (the def). computeDefsForBytecodeOffset( codeBlock, block, bytecodeOffset, [&] (CodeBlock* codeBlock, Instruction*, OpcodeID, int operand) { if (isValidRegisterForLiveness(codeBlock, operand)) def(VirtualRegister(operand).toLocal()); }); computeUsesForBytecodeOffset( codeBlock, block, bytecodeOffset, [&] (CodeBlock* codeBlock, Instruction*, OpcodeID, int operand) { if (isValidRegisterForLiveness(codeBlock, operand)) use(VirtualRegister(operand).toLocal()); }); // If we have an exception handler, we want the live-in variables of the // exception handler block to be included in the live-in of this particular bytecode. if (HandlerInfo* handler = codeBlock->handlerForBytecodeOffset(bytecodeOffset)) { // FIXME: This resume check should not be needed. // https://bugs.webkit.org/show_bug.cgi?id=159281 Interpreter* interpreter = codeBlock->vm()->interpreter; Instruction* instructionsBegin = codeBlock->instructions().begin(); Instruction* instruction = &instructionsBegin[bytecodeOffset]; OpcodeID opcodeID = interpreter->getOpcodeID(instruction->u.opcode); if (opcodeID != op_resume) { BytecodeBasicBlock* handlerBlock = findBasicBlockWithLeaderOffset(basicBlocks, handler->target); ASSERT(handlerBlock); handlerBlock->in().forEachSetBit(use); } } }
static void computeLocalLivenessForBytecodeOffset(CodeBlock* codeBlock, BytecodeBasicBlock* block, Vector<RefPtr<BytecodeBasicBlock> >& basicBlocks, unsigned targetOffset, FastBitVector& result) { ASSERT(!block->isExitBlock()); ASSERT(!block->isEntryBlock()); FastBitVector out = block->out(); HandlerInfo* handler = 0; FastBitVector uses; FastBitVector defs; uses.resize(out.numBits()); defs.resize(out.numBits()); for (int i = block->bytecodeOffsets().size() - 1; i >= 0; i--) { unsigned bytecodeOffset = block->bytecodeOffsets()[i]; if (targetOffset > bytecodeOffset) break; uses.clearAll(); defs.clearAll(); computeUsesForBytecodeOffset(codeBlock, bytecodeOffset, uses); computeDefsForBytecodeOffset(codeBlock, bytecodeOffset, defs); out.exclude(defs); out.merge(uses); // If we have an exception handler, we want the live-in variables of the // exception handler block to be included in the live-in of this particular bytecode. if ((handler = codeBlock->handlerForBytecodeOffset(bytecodeOffset))) { BytecodeBasicBlock* handlerBlock = findBasicBlockWithLeaderOffset(basicBlocks, handler->target); ASSERT(handlerBlock); out.merge(handlerBlock->in()); } } result.set(out); }