diff options
Diffstat (limited to 'Source/JavaScriptCore/bytecode/BytecodeBasicBlock.cpp')
-rw-r--r-- | Source/JavaScriptCore/bytecode/BytecodeBasicBlock.cpp | 170 |
1 files changed, 70 insertions, 100 deletions
diff --git a/Source/JavaScriptCore/bytecode/BytecodeBasicBlock.cpp b/Source/JavaScriptCore/bytecode/BytecodeBasicBlock.cpp index d7489d31a..47c481d5d 100644 --- a/Source/JavaScriptCore/bytecode/BytecodeBasicBlock.cpp +++ b/Source/JavaScriptCore/bytecode/BytecodeBasicBlock.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Apple Inc. All rights reserved. + * Copyright (C) 2013, 2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -27,120 +27,67 @@ #include "BytecodeBasicBlock.h" #include "CodeBlock.h" +#include "InterpreterInlines.h" +#include "JSCInlines.h" #include "PreciseJumpTargets.h" namespace JSC { -static bool isBranch(OpcodeID opcodeID) +void BytecodeBasicBlock::shrinkToFit() { - switch (opcodeID) { - case op_jmp: - case op_jtrue: - case op_jfalse: - case op_jeq_null: - case op_jneq_null: - case op_jneq_ptr: - case op_jless: - case op_jlesseq: - case op_jgreater: - case op_jgreatereq: - case op_jnless: - case op_jnlesseq: - case op_jngreater: - case op_jngreatereq: - case op_switch_imm: - case op_switch_char: - case op_switch_string: - case op_get_pnames: - case op_next_pname: - case op_check_has_instance: - return true; - default: - return false; - } + m_offsets.shrinkToFit(); + m_successors.shrinkToFit(); } -static bool isUnconditionalBranch(OpcodeID opcodeID) +static bool isJumpTarget(OpcodeID opcodeID, const Vector<unsigned, 32>& jumpTargets, unsigned bytecodeOffset) { - switch (opcodeID) { - case op_jmp: + if (opcodeID == op_catch) return true; - default: - return false; - } -} -static bool isTerminal(OpcodeID opcodeID) -{ - switch (opcodeID) { - case op_ret: - case op_ret_object_or_this: - case op_end: - return true; - default: - return false; - } + return std::binary_search(jumpTargets.begin(), jumpTargets.end(), bytecodeOffset); } -static bool isThrow(OpcodeID opcodeID) +template<typename Block, typename Instruction> +void BytecodeBasicBlock::computeImpl(Block* codeBlock, Instruction* instructionsBegin, unsigned instructionCount, Vector<std::unique_ptr<BytecodeBasicBlock>>& basicBlocks) { - switch (opcodeID) { - case op_throw: - case op_throw_static_error: - return true; - default: - return false; - } -} + Vector<unsigned, 32> jumpTargets; + computePreciseJumpTargets(codeBlock, instructionsBegin, instructionCount, jumpTargets); -static bool isJumpTarget(OpcodeID opcodeID, Vector<unsigned, 32>& jumpTargets, unsigned bytecodeOffset) -{ - if (opcodeID == op_catch) - return true; + auto appendBlock = [&] (std::unique_ptr<BytecodeBasicBlock>&& block) { + block->m_index = basicBlocks.size(); + basicBlocks.append(WTFMove(block)); + }; - for (unsigned i = 0; i < jumpTargets.size(); i++) { - if (bytecodeOffset == jumpTargets[i]) - return true; - } - return false; -} + auto linkBlocks = [&] (BytecodeBasicBlock* from, BytecodeBasicBlock* to) { + from->addSuccessor(to); + }; -static void linkBlocks(BytecodeBasicBlock* predecessor, BytecodeBasicBlock* successor) -{ - predecessor->addSuccessor(successor); - successor->addPredecessor(predecessor); -} + // Create the entry and exit basic blocks. + basicBlocks.reserveCapacity(jumpTargets.size() + 2); -void computeBytecodeBasicBlocks(CodeBlock* codeBlock, Vector<RefPtr<BytecodeBasicBlock> >& basicBlocks) -{ - Vector<unsigned, 32> jumpTargets; - computePreciseJumpTargets(codeBlock, jumpTargets); + auto entry = std::make_unique<BytecodeBasicBlock>(BytecodeBasicBlock::EntryBlock); + auto firstBlock = std::make_unique<BytecodeBasicBlock>(0, 0); + linkBlocks(entry.get(), firstBlock.get()); - // Create the entry and exit basic blocks. - BytecodeBasicBlock* entry = new BytecodeBasicBlock(BytecodeBasicBlock::EntryBlock); - basicBlocks.append(adoptRef(entry)); - BytecodeBasicBlock* exit = new BytecodeBasicBlock(BytecodeBasicBlock::ExitBlock); + appendBlock(WTFMove(entry)); + BytecodeBasicBlock* current = firstBlock.get(); + appendBlock(WTFMove(firstBlock)); - // Find basic block boundaries. - BytecodeBasicBlock* current = new BytecodeBasicBlock(0, 0); - linkBlocks(entry, current); - basicBlocks.append(adoptRef(current)); + auto exit = std::make_unique<BytecodeBasicBlock>(BytecodeBasicBlock::ExitBlock); bool nextInstructionIsLeader = false; Interpreter* interpreter = codeBlock->vm()->interpreter; - Instruction* instructionsBegin = codeBlock->instructions().begin(); - unsigned instructionCount = codeBlock->instructions().size(); for (unsigned bytecodeOffset = 0; bytecodeOffset < instructionCount;) { - OpcodeID opcodeID = interpreter->getOpcodeID(instructionsBegin[bytecodeOffset].u.opcode); + OpcodeID opcodeID = interpreter->getOpcodeID(instructionsBegin[bytecodeOffset]); unsigned opcodeLength = opcodeLengths[opcodeID]; bool createdBlock = false; // If the current bytecode is a jump target, then it's the leader of its own basic block. if (isJumpTarget(opcodeID, jumpTargets, bytecodeOffset) || nextInstructionIsLeader) { - BytecodeBasicBlock* block = new BytecodeBasicBlock(bytecodeOffset, opcodeLength); - basicBlocks.append(adoptRef(block)); - current = block; + auto newBlock = std::make_unique<BytecodeBasicBlock>(bytecodeOffset, opcodeLength); + current = newBlock.get(); + appendBlock(WTFMove(newBlock)); createdBlock = true; nextInstructionIsLeader = false; bytecodeOffset += opcodeLength; @@ -154,7 +101,7 @@ void computeBytecodeBasicBlocks(CodeBlock* codeBlock, Vector<RefPtr<BytecodeBasi continue; // Otherwise, just add to the length of the current block. - current->addBytecodeLength(opcodeLength); + current->addLength(opcodeLength); bytecodeOffset += opcodeLength; } @@ -166,14 +113,13 @@ void computeBytecodeBasicBlocks(CodeBlock* codeBlock, Vector<RefPtr<BytecodeBasi continue; bool fallsThrough = true; - for (unsigned bytecodeOffset = block->leaderBytecodeOffset(); bytecodeOffset < block->leaderBytecodeOffset() + block->totalBytecodeLength();) { - const Instruction& currentInstruction = instructionsBegin[bytecodeOffset]; - OpcodeID opcodeID = interpreter->getOpcodeID(currentInstruction.u.opcode); + for (unsigned bytecodeOffset = block->leaderOffset(); bytecodeOffset < block->leaderOffset() + block->totalLength();) { + OpcodeID opcodeID = interpreter->getOpcodeID(instructionsBegin[bytecodeOffset]); unsigned opcodeLength = opcodeLengths[opcodeID]; // If we found a terminal bytecode, link to the exit block. if (isTerminal(opcodeID)) { - ASSERT(bytecodeOffset + opcodeLength == block->leaderBytecodeOffset() + block->totalBytecodeLength()); - linkBlocks(block, exit); + ASSERT(bytecodeOffset + opcodeLength == block->leaderOffset() + block->totalLength()); + linkBlocks(block, exit.get()); fallsThrough = false; break; } @@ -182,16 +128,16 @@ void computeBytecodeBasicBlocks(CodeBlock* codeBlock, Vector<RefPtr<BytecodeBasi // If there isn't one, treat this throw as a terminal. This is true even if we have a finally // block because the finally block will create its own catch, which will generate a HandlerInfo. if (isThrow(opcodeID)) { - ASSERT(bytecodeOffset + opcodeLength == block->leaderBytecodeOffset() + block->totalBytecodeLength()); - HandlerInfo* handler = codeBlock->handlerForBytecodeOffset(bytecodeOffset); + ASSERT(bytecodeOffset + opcodeLength == block->leaderOffset() + block->totalLength()); + auto* handler = codeBlock->handlerForBytecodeOffset(bytecodeOffset); fallsThrough = false; if (!handler) { - linkBlocks(block, exit); + linkBlocks(block, exit.get()); break; } for (unsigned i = 0; i < basicBlocks.size(); i++) { BytecodeBasicBlock* otherBlock = basicBlocks[i].get(); - if (handler->target == otherBlock->leaderBytecodeOffset()) { + if (handler->target == otherBlock->leaderOffset()) { linkBlocks(block, otherBlock); break; } @@ -201,15 +147,26 @@ void computeBytecodeBasicBlocks(CodeBlock* codeBlock, Vector<RefPtr<BytecodeBasi // If we found a branch, link to the block(s) that we jump to. if (isBranch(opcodeID)) { - ASSERT(bytecodeOffset + opcodeLength == block->leaderBytecodeOffset() + block->totalBytecodeLength()); + ASSERT(bytecodeOffset + opcodeLength == block->leaderOffset() + block->totalLength()); Vector<unsigned, 1> bytecodeOffsetsJumpedTo; - findJumpTargetsForBytecodeOffset(codeBlock, bytecodeOffset, bytecodeOffsetsJumpedTo); + findJumpTargetsForBytecodeOffset(codeBlock, instructionsBegin, bytecodeOffset, bytecodeOffsetsJumpedTo); + size_t numberOfJumpTargets = bytecodeOffsetsJumpedTo.size(); + ASSERT(numberOfJumpTargets); for (unsigned i = 0; i < basicBlocks.size(); i++) { BytecodeBasicBlock* otherBlock = basicBlocks[i].get(); - if (bytecodeOffsetsJumpedTo.contains(otherBlock->leaderBytecodeOffset())) + if (bytecodeOffsetsJumpedTo.contains(otherBlock->leaderOffset())) { linkBlocks(block, otherBlock); + --numberOfJumpTargets; + if (!numberOfJumpTargets) + break; + } } + // numberOfJumpTargets may not be 0 here if there are multiple jumps targeting the same + // basic blocks (e.g. in a switch type opcode). Since we only decrement numberOfJumpTargets + // once per basic block, the duplicates are not accounted for. For our purpose here, + // that doesn't matter because we only need to link to the target block once regardless + // of how many ways this block can jump there. if (isUnconditionalBranch(opcodeID)) fallsThrough = false; @@ -227,7 +184,20 @@ void computeBytecodeBasicBlocks(CodeBlock* codeBlock, Vector<RefPtr<BytecodeBasi } } - basicBlocks.append(adoptRef(exit)); + appendBlock(WTFMove(exit)); + + for (auto& basicBlock : basicBlocks) + basicBlock->shrinkToFit(); +} + +void BytecodeBasicBlock::compute(CodeBlock* codeBlock, Instruction* instructionsBegin, unsigned instructionCount, Vector<std::unique_ptr<BytecodeBasicBlock>>& basicBlocks) +{ + computeImpl(codeBlock, instructionsBegin, instructionCount, basicBlocks); +} + +void BytecodeBasicBlock::compute(UnlinkedCodeBlock* codeBlock, UnlinkedInstruction* instructionsBegin, unsigned instructionCount, Vector<std::unique_ptr<BytecodeBasicBlock>>& basicBlocks) +{ + BytecodeBasicBlock::computeImpl(codeBlock, instructionsBegin, instructionCount, basicBlocks); } } // namespace JSC |