BytecodeSequence::BytecodeSequence(CodeBlock* codeBlock) { StringPrintStream out; for (unsigned i = 0; i < codeBlock->numberOfArgumentValueProfiles(); ++i) { ConcurrentJSLocker locker(codeBlock->m_lock); CString description = codeBlock->valueProfileForArgument(i)->briefDescription(locker); if (!description.length()) continue; out.reset(); out.print("arg", i, ": ", description); m_header.append(out.toCString()); } StubInfoMap stubInfos; codeBlock->getStubInfoMap(stubInfos); for (unsigned bytecodeIndex = 0; bytecodeIndex < codeBlock->instructions().size();) { out.reset(); codeBlock->dumpBytecode(out, bytecodeIndex, stubInfos); m_sequence.append(Bytecode(bytecodeIndex, codeBlock->vm()->interpreter->getOpcodeID(codeBlock->instructions()[bytecodeIndex].u.opcode), out.toCString())); bytecodeIndex += opcodeLength( codeBlock->vm()->interpreter->getOpcodeID( codeBlock->instructions()[bytecodeIndex].u.opcode)); } }
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 BytecodeGeneratorification::run() { // We calculate the liveness at each merge point. This gives us the information which registers should be saved and resumed conservatively. { GeneratorLivenessAnalysis pass(*this); pass.run(); } UnlinkedCodeBlock* codeBlock = m_graph.codeBlock(); BytecodeRewriter rewriter(m_graph); // Setup the global switch for the generator. { unsigned nextToEnterPoint = enterPoint() + opcodeLength(op_enter); unsigned switchTableIndex = m_graph.codeBlock()->numberOfSwitchJumpTables(); VirtualRegister state = virtualRegisterForArgument(static_cast<int32_t>(JSGeneratorFunction::GeneratorArgument::State)); auto& jumpTable = m_graph.codeBlock()->addSwitchJumpTable(); jumpTable.min = 0; jumpTable.branchOffsets.resize(m_yields.size() + 1); jumpTable.branchOffsets.fill(0); jumpTable.add(0, nextToEnterPoint); for (unsigned i = 0; i < m_yields.size(); ++i) jumpTable.add(i + 1, m_yields[i].point); rewriter.insertFragmentBefore(nextToEnterPoint, [&](BytecodeRewriter::Fragment& fragment) { fragment.appendInstruction(op_switch_imm, switchTableIndex, nextToEnterPoint, state.offset()); }); } for (const YieldData& data : m_yields) { VirtualRegister scope = virtualRegisterForArgument(static_cast<int32_t>(JSGeneratorFunction::GeneratorArgument::Frame)); // Emit save sequence. rewriter.insertFragmentBefore(data.point, [&](BytecodeRewriter::Fragment& fragment) { data.liveness.forEachSetBit([&](size_t index) { VirtualRegister operand = virtualRegisterForLocal(index); Storage storage = storageForGeneratorLocal(index); fragment.appendInstruction( op_put_to_scope, scope.offset(), // scope storage.identifierIndex, // identifier operand.offset(), // value GetPutInfo(DoNotThrowIfNotFound, LocalClosureVar, InitializationMode::NotInitialization).operand(), // info m_generatorFrameSymbolTableIndex, // symbol table constant index storage.scopeOffset.offset() // scope offset ); }); // Insert op_ret just after save sequence. fragment.appendInstruction(op_ret, data.argument); }); // Emit resume sequence. rewriter.insertFragmentAfter(data.point, [&](BytecodeRewriter::Fragment& fragment) { data.liveness.forEachSetBit([&](size_t index) { VirtualRegister operand = virtualRegisterForLocal(index); Storage storage = storageForGeneratorLocal(index); UnlinkedValueProfile profile = codeBlock->addValueProfile(); fragment.appendInstruction( op_get_from_scope, operand.offset(), // dst scope.offset(), // scope storage.identifierIndex, // identifier GetPutInfo(DoNotThrowIfNotFound, LocalClosureVar, InitializationMode::NotInitialization).operand(), // info 0, // local scope depth storage.scopeOffset.offset(), // scope offset profile // profile ); }); }); // Clip the unnecessary bytecodes. rewriter.removeBytecode(data.point); } rewriter.execute(); }
void run() { // Perform modified liveness analysis to determine which locals are live at the merge points. // This produces the conservative results for the question, "which variables should be saved and resumed?". runLivenessFixpoint(m_generatorification.graph()); for (YieldData& data : m_generatorification.yields()) data.liveness = getLivenessInfoAtBytecodeOffset(m_generatorification.graph(), data.point + opcodeLength(op_yield)); }