Changeset 204994 in webkit for trunk/Source/JavaScriptCore/bytecode/BytecodeLivenessAnalysis.cpp
- Timestamp:
- Aug 25, 2016, 3:55:10 PM (9 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/bytecode/BytecodeLivenessAnalysis.cpp
r204912 r204994 32 32 #include "CodeBlock.h" 33 33 #include "FullBytecodeLiveness.h" 34 #include " PreciseJumpTargets.h"34 #include "InterpreterInlines.h" 35 35 36 36 namespace JSC { 37 37 38 38 BytecodeLivenessAnalysis::BytecodeLivenessAnalysis(CodeBlock* codeBlock) 39 : m_ codeBlock(codeBlock)39 : m_graph(codeBlock, codeBlock->instructions()) 40 40 { 41 ASSERT(m_codeBlock);42 41 compute(); 43 42 } 44 43 45 static bool isValidRegisterForLiveness(CodeBlock* codeBlock, int operand) 44 template<typename Functor> 45 void BytecodeLivenessAnalysis::computeDefsForBytecodeOffset(CodeBlock* codeBlock, OpcodeID opcodeID, Instruction* instruction, FastBitVector&, const Functor& functor) 46 46 { 47 if (codeBlock->isConstantRegisterIndex(operand)) 48 return false; 49 50 VirtualRegister virtualReg(operand); 51 return virtualReg.isLocal(); 47 JSC::computeDefsForBytecodeOffset(codeBlock, opcodeID, instruction, functor); 52 48 } 53 49 54 static unsigned getLeaderOffsetForBasicBlock(std::unique_ptr<BytecodeBasicBlock>* basicBlock) 50 template<typename Functor> 51 void BytecodeLivenessAnalysis::computeUsesForBytecodeOffset(CodeBlock* codeBlock, OpcodeID opcodeID, Instruction* instruction, FastBitVector&, const Functor& functor) 55 52 { 56 return (*basicBlock)->leaderBytecodeOffset(); 57 } 58 59 static BytecodeBasicBlock* findBasicBlockWithLeaderOffset(Vector<std::unique_ptr<BytecodeBasicBlock>>& basicBlocks, unsigned leaderOffset) 60 { 61 return (*tryBinarySearch<std::unique_ptr<BytecodeBasicBlock>, unsigned>(basicBlocks, basicBlocks.size(), leaderOffset, getLeaderOffsetForBasicBlock)).get(); 62 } 63 64 static bool blockContainsBytecodeOffset(BytecodeBasicBlock* block, unsigned bytecodeOffset) 65 { 66 unsigned leaderOffset = block->leaderBytecodeOffset(); 67 return bytecodeOffset >= leaderOffset && bytecodeOffset < leaderOffset + block->totalBytecodeLength(); 68 } 69 70 static BytecodeBasicBlock* findBasicBlockForBytecodeOffset(Vector<std::unique_ptr<BytecodeBasicBlock>>& basicBlocks, unsigned bytecodeOffset) 71 { 72 /* 73 for (unsigned i = 0; i < basicBlocks.size(); i++) { 74 if (blockContainsBytecodeOffset(basicBlocks[i].get(), bytecodeOffset)) 75 return basicBlocks[i].get(); 76 } 77 return 0; 78 */ 79 std::unique_ptr<BytecodeBasicBlock>* basicBlock = approximateBinarySearch<std::unique_ptr<BytecodeBasicBlock>, unsigned>( 80 basicBlocks, basicBlocks.size(), bytecodeOffset, getLeaderOffsetForBasicBlock); 81 // We found the block we were looking for. 82 if (blockContainsBytecodeOffset((*basicBlock).get(), bytecodeOffset)) 83 return (*basicBlock).get(); 84 85 // Basic block is to the left of the returned block. 86 if (bytecodeOffset < (*basicBlock)->leaderBytecodeOffset()) { 87 ASSERT(basicBlock - 1 >= basicBlocks.data()); 88 ASSERT(blockContainsBytecodeOffset(basicBlock[-1].get(), bytecodeOffset)); 89 return basicBlock[-1].get(); 90 } 91 92 // Basic block is to the right of the returned block. 93 ASSERT(&basicBlock[1] <= &basicBlocks.last()); 94 ASSERT(blockContainsBytecodeOffset(basicBlock[1].get(), bytecodeOffset)); 95 return basicBlock[1].get(); 96 } 97 98 // Simplified interface to bytecode use/def, which determines defs first and then uses, and includes 99 // exception handlers in the uses. 100 template<typename UseFunctor, typename DefFunctor> 101 static void stepOverInstruction(CodeBlock* codeBlock, BytecodeBasicBlock* block, Vector<std::unique_ptr<BytecodeBasicBlock>>& basicBlocks, unsigned bytecodeOffset, const UseFunctor& use, const DefFunctor& def) 102 { 103 // This abstractly execute the instruction in reverse. Instructions logically first use operands and 104 // then define operands. This logical ordering is necessary for operations that use and def the same 105 // operand, like: 106 // 107 // op_add loc1, loc1, loc2 108 // 109 // The use of loc1 happens before the def of loc1. That's a semantic requirement since the add 110 // operation cannot travel forward in time to read the value that it will produce after reading that 111 // value. Since we are executing in reverse, this means that we must do defs before uses (reverse of 112 // uses before defs). 113 // 114 // Since this is a liveness analysis, this ordering ends up being particularly important: if we did 115 // uses before defs, then the add operation above would appear to not have loc1 live, since we'd 116 // first add it to the out set (the use), and then we'd remove it (the def). 117 118 computeDefsForBytecodeOffset( 119 codeBlock, block, bytecodeOffset, 120 [&] (CodeBlock* codeBlock, Instruction*, OpcodeID, int operand) { 121 if (isValidRegisterForLiveness(codeBlock, operand)) 122 def(VirtualRegister(operand).toLocal()); 123 }); 124 125 computeUsesForBytecodeOffset( 126 codeBlock, block, bytecodeOffset, 127 [&] (CodeBlock* codeBlock, Instruction*, OpcodeID, int operand) { 128 if (isValidRegisterForLiveness(codeBlock, operand)) 129 use(VirtualRegister(operand).toLocal()); 130 }); 131 132 // If we have an exception handler, we want the live-in variables of the 133 // exception handler block to be included in the live-in of this particular bytecode. 134 if (HandlerInfo* handler = codeBlock->handlerForBytecodeOffset(bytecodeOffset)) { 135 // FIXME: This resume check should not be needed. 136 // https://bugs.webkit.org/show_bug.cgi?id=159281 137 Interpreter* interpreter = codeBlock->vm()->interpreter; 138 Instruction* instructionsBegin = codeBlock->instructions().begin(); 139 Instruction* instruction = &instructionsBegin[bytecodeOffset]; 140 OpcodeID opcodeID = interpreter->getOpcodeID(instruction->u.opcode); 141 if (opcodeID != op_resume) { 142 BytecodeBasicBlock* handlerBlock = findBasicBlockWithLeaderOffset(basicBlocks, handler->target); 143 ASSERT(handlerBlock); 144 handlerBlock->in().forEachSetBit(use); 145 } 146 } 147 } 148 149 static void stepOverInstruction(CodeBlock* codeBlock, BytecodeBasicBlock* block, Vector<std::unique_ptr<BytecodeBasicBlock>>& basicBlocks, unsigned bytecodeOffset, FastBitVector& out) 150 { 151 stepOverInstruction( 152 codeBlock, block, basicBlocks, bytecodeOffset, 153 [&] (unsigned bitIndex) { 154 // This is the use functor, so we set the bit. 155 out.set(bitIndex); 156 }, 157 [&] (unsigned bitIndex) { 158 // This is the def functor, so we clear the bit. 159 out.clear(bitIndex); 160 }); 161 } 162 163 static void computeLocalLivenessForBytecodeOffset(CodeBlock* codeBlock, BytecodeBasicBlock* block, Vector<std::unique_ptr<BytecodeBasicBlock>>& basicBlocks, unsigned targetOffset, FastBitVector& result) 164 { 165 ASSERT(!block->isExitBlock()); 166 ASSERT(!block->isEntryBlock()); 167 168 FastBitVector out = block->out(); 169 170 for (int i = block->bytecodeOffsets().size() - 1; i >= 0; i--) { 171 unsigned bytecodeOffset = block->bytecodeOffsets()[i]; 172 if (targetOffset > bytecodeOffset) 173 break; 174 175 stepOverInstruction(codeBlock, block, basicBlocks, bytecodeOffset, out); 176 } 177 178 result.set(out); 179 } 180 181 static void computeLocalLivenessForBlock(CodeBlock* codeBlock, BytecodeBasicBlock* block, Vector<std::unique_ptr<BytecodeBasicBlock>>& basicBlocks) 182 { 183 if (block->isExitBlock() || block->isEntryBlock()) 184 return; 185 computeLocalLivenessForBytecodeOffset(codeBlock, block, basicBlocks, block->leaderBytecodeOffset(), block->in()); 186 } 187 188 void BytecodeLivenessAnalysis::runLivenessFixpoint() 189 { 190 UnlinkedCodeBlock* unlinkedCodeBlock = m_codeBlock->unlinkedCodeBlock(); 191 unsigned numberOfVariables = unlinkedCodeBlock->m_numCalleeLocals; 192 193 for (unsigned i = 0; i < m_basicBlocks.size(); i++) { 194 BytecodeBasicBlock* block = m_basicBlocks[i].get(); 195 block->in().resize(numberOfVariables); 196 block->out().resize(numberOfVariables); 197 } 198 199 bool changed; 200 m_basicBlocks.last()->in().clearAll(); 201 m_basicBlocks.last()->out().clearAll(); 202 FastBitVector newOut; 203 newOut.resize(m_basicBlocks.last()->out().numBits()); 204 do { 205 changed = false; 206 for (unsigned i = m_basicBlocks.size() - 1; i--;) { 207 BytecodeBasicBlock* block = m_basicBlocks[i].get(); 208 newOut.clearAll(); 209 for (unsigned j = 0; j < block->successors().size(); j++) 210 newOut.merge(block->successors()[j]->in()); 211 bool outDidChange = block->out().setAndCheck(newOut); 212 computeLocalLivenessForBlock(m_codeBlock, block, m_basicBlocks); 213 changed |= outDidChange; 214 } 215 } while (changed); 53 JSC::computeUsesForBytecodeOffset(codeBlock, opcodeID, instruction, functor); 216 54 } 217 55 218 56 void BytecodeLivenessAnalysis::getLivenessInfoAtBytecodeOffset(unsigned bytecodeOffset, FastBitVector& result) 219 57 { 220 BytecodeBasicBlock* block = findBasicBlockForBytecodeOffset(m_basicBlocks,bytecodeOffset);58 BytecodeBasicBlock* block = m_graph.findBasicBlockForBytecodeOffset(bytecodeOffset); 221 59 ASSERT(block); 222 60 ASSERT(!block->isEntryBlock()); 223 61 ASSERT(!block->isExitBlock()); 224 62 result.resize(block->out().numBits()); 225 computeLocalLivenessForBytecodeOffset(m_ codeBlock, block, m_basicBlocks, bytecodeOffset, result);63 computeLocalLivenessForBytecodeOffset(m_graph, block, bytecodeOffset, result); 226 64 } 227 65 … … 245 83 { 246 84 FastBitVector out; 85 CodeBlock* codeBlock = m_graph.codeBlock(); 247 86 248 result.m_map.resize( m_codeBlock->instructions().size());87 result.m_map.resize(codeBlock->instructions().size()); 249 88 250 for (unsigned i = m_basicBlocks.size(); i--;) { 251 BytecodeBasicBlock* block = m_basicBlocks[i].get(); 89 for (std::unique_ptr<BytecodeBasicBlock>& block : m_graph.basicBlocksInReverseOrder()) { 252 90 if (block->isEntryBlock() || block->isExitBlock()) 253 91 continue; … … 255 93 out = block->out(); 256 94 257 for (unsigned i = block-> bytecodeOffsets().size(); i--;) {258 unsigned bytecodeOffset = block-> bytecodeOffsets()[i];259 stepOverInstruction(m_ codeBlock, block, m_basicBlocks, bytecodeOffset, out);95 for (unsigned i = block->offsets().size(); i--;) { 96 unsigned bytecodeOffset = block->offsets()[i]; 97 stepOverInstruction(m_graph, bytecodeOffset, out); 260 98 result.m_map[bytecodeOffset] = out; 261 99 } … … 267 105 FastBitVector out; 268 106 269 result.m_codeBlock = m_codeBlock; 270 result.m_killSets = std::make_unique<BytecodeKills::KillSet[]>(m_codeBlock->instructions().size()); 107 CodeBlock* codeBlock = m_graph.codeBlock(); 108 result.m_codeBlock = codeBlock; 109 result.m_killSets = std::make_unique<BytecodeKills::KillSet[]>(codeBlock->instructions().size()); 271 110 272 for (unsigned i = m_basicBlocks.size(); i--;) { 273 BytecodeBasicBlock* block = m_basicBlocks[i].get(); 111 for (std::unique_ptr<BytecodeBasicBlock>& block : m_graph.basicBlocksInReverseOrder()) { 274 112 if (block->isEntryBlock() || block->isExitBlock()) 275 113 continue; … … 277 115 out = block->out(); 278 116 279 for (unsigned i = block-> bytecodeOffsets().size(); i--;) {280 unsigned bytecodeOffset = block-> bytecodeOffsets()[i];117 for (unsigned i = block->offsets().size(); i--;) { 118 unsigned bytecodeOffset = block->offsets()[i]; 281 119 stepOverInstruction( 282 m_ codeBlock, block, m_basicBlocks, bytecodeOffset,120 m_graph, bytecodeOffset, out, 283 121 [&] (unsigned index) { 284 122 // This is for uses. … … 298 136 void BytecodeLivenessAnalysis::dumpResults() 299 137 { 300 dataLog("\nDumping bytecode liveness for ", *m_codeBlock, ":\n"); 301 Interpreter* interpreter = m_codeBlock->vm()->interpreter; 302 Instruction* instructionsBegin = m_codeBlock->instructions().begin(); 303 for (unsigned i = 0; i < m_basicBlocks.size(); i++) { 304 BytecodeBasicBlock* block = m_basicBlocks[i].get(); 305 dataLogF("\nBytecode basic block %u: %p (offset: %u, length: %u)\n", i, block, block->leaderBytecodeOffset(), block->totalBytecodeLength()); 138 CodeBlock* codeBlock = m_graph.codeBlock(); 139 dataLog("\nDumping bytecode liveness for ", *codeBlock, ":\n"); 140 Interpreter* interpreter = codeBlock->vm()->interpreter; 141 Instruction* instructionsBegin = codeBlock->instructions().begin(); 142 unsigned i = 0; 143 for (BytecodeBasicBlock* block : m_graph) { 144 dataLogF("\nBytecode basic block %u: %p (offset: %u, length: %u)\n", i++, block, block->leaderOffset(), block->totalLength()); 306 145 dataLogF("Successors: "); 307 146 for (unsigned j = 0; j < block->successors().size(); j++) { … … 318 157 continue; 319 158 } 320 for (unsigned bytecodeOffset = block->leader BytecodeOffset(); bytecodeOffset < block->leaderBytecodeOffset() + block->totalBytecodeLength();) {159 for (unsigned bytecodeOffset = block->leaderOffset(); bytecodeOffset < block->leaderOffset() + block->totalLength();) { 321 160 const Instruction* currentInstruction = &instructionsBegin[bytecodeOffset]; 322 161 … … 328 167 } 329 168 dataLogF("\n"); 330 m_codeBlock->dumpBytecode(WTF::dataFile(), m_codeBlock->globalObject()->globalExec(), instructionsBegin, currentInstruction);169 codeBlock->dumpBytecode(WTF::dataFile(), codeBlock->globalObject()->globalExec(), instructionsBegin, currentInstruction); 331 170 332 171 OpcodeID opcodeID = interpreter->getOpcodeID(instructionsBegin[bytecodeOffset].u.opcode); … … 347 186 void BytecodeLivenessAnalysis::compute() 348 187 { 349 computeBytecodeBasicBlocks(m_codeBlock, m_basicBlocks); 350 ASSERT(m_basicBlocks.size()); 351 runLivenessFixpoint(); 188 runLivenessFixpoint(m_graph); 352 189 353 190 if (Options::dumpBytecodeLivenessResults())
Note:
See TracChangeset
for help on using the changeset viewer.