]>
git.saurik.com Git - apple/javascriptcore.git/blob - bytecode/BytecodeBasicBlock.cpp
961eadb6a7d661b1b5e57c575691f230e2dae988
2 * Copyright (C) 2013 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
27 #include "BytecodeBasicBlock.h"
29 #include "CodeBlock.h"
30 #include "JSCInlines.h"
31 #include "PreciseJumpTargets.h"
35 static bool isBranch(OpcodeID opcodeID
)
54 case op_switch_string
:
55 case op_check_has_instance
:
62 static bool isUnconditionalBranch(OpcodeID opcodeID
)
72 static bool isTerminal(OpcodeID opcodeID
)
83 static bool isThrow(OpcodeID opcodeID
)
87 case op_throw_static_error
:
94 static bool isJumpTarget(OpcodeID opcodeID
, Vector
<unsigned, 32>& jumpTargets
, unsigned bytecodeOffset
)
96 if (opcodeID
== op_catch
)
99 for (unsigned i
= 0; i
< jumpTargets
.size(); i
++) {
100 if (bytecodeOffset
== jumpTargets
[i
])
106 static void linkBlocks(BytecodeBasicBlock
* predecessor
, BytecodeBasicBlock
* successor
)
108 predecessor
->addSuccessor(successor
);
109 successor
->addPredecessor(predecessor
);
112 void computeBytecodeBasicBlocks(CodeBlock
* codeBlock
, Vector
<RefPtr
<BytecodeBasicBlock
> >& basicBlocks
)
114 Vector
<unsigned, 32> jumpTargets
;
115 computePreciseJumpTargets(codeBlock
, jumpTargets
);
117 // Create the entry and exit basic blocks.
118 BytecodeBasicBlock
* entry
= new BytecodeBasicBlock(BytecodeBasicBlock::EntryBlock
);
119 basicBlocks
.append(adoptRef(entry
));
120 BytecodeBasicBlock
* exit
= new BytecodeBasicBlock(BytecodeBasicBlock::ExitBlock
);
122 // Find basic block boundaries.
123 BytecodeBasicBlock
* current
= new BytecodeBasicBlock(0, 0);
124 linkBlocks(entry
, current
);
125 basicBlocks
.append(adoptRef(current
));
127 bool nextInstructionIsLeader
= false;
129 Interpreter
* interpreter
= codeBlock
->vm()->interpreter
;
130 Instruction
* instructionsBegin
= codeBlock
->instructions().begin();
131 unsigned instructionCount
= codeBlock
->instructions().size();
132 for (unsigned bytecodeOffset
= 0; bytecodeOffset
< instructionCount
;) {
133 OpcodeID opcodeID
= interpreter
->getOpcodeID(instructionsBegin
[bytecodeOffset
].u
.opcode
);
134 unsigned opcodeLength
= opcodeLengths
[opcodeID
];
136 bool createdBlock
= false;
137 // If the current bytecode is a jump target, then it's the leader of its own basic block.
138 if (isJumpTarget(opcodeID
, jumpTargets
, bytecodeOffset
) || nextInstructionIsLeader
) {
139 BytecodeBasicBlock
* block
= new BytecodeBasicBlock(bytecodeOffset
, opcodeLength
);
140 basicBlocks
.append(adoptRef(block
));
143 nextInstructionIsLeader
= false;
144 bytecodeOffset
+= opcodeLength
;
147 // If the current bytecode is a branch or a return, then the next instruction is the leader of its own basic block.
148 if (isBranch(opcodeID
) || isTerminal(opcodeID
) || isThrow(opcodeID
))
149 nextInstructionIsLeader
= true;
154 // Otherwise, just add to the length of the current block.
155 current
->addBytecodeLength(opcodeLength
);
156 bytecodeOffset
+= opcodeLength
;
159 // Link basic blocks together.
160 for (unsigned i
= 0; i
< basicBlocks
.size(); i
++) {
161 BytecodeBasicBlock
* block
= basicBlocks
[i
].get();
163 if (block
->isEntryBlock() || block
->isExitBlock())
166 bool fallsThrough
= true;
167 for (unsigned bytecodeOffset
= block
->leaderBytecodeOffset(); bytecodeOffset
< block
->leaderBytecodeOffset() + block
->totalBytecodeLength();) {
168 const Instruction
& currentInstruction
= instructionsBegin
[bytecodeOffset
];
169 OpcodeID opcodeID
= interpreter
->getOpcodeID(currentInstruction
.u
.opcode
);
170 unsigned opcodeLength
= opcodeLengths
[opcodeID
];
171 // If we found a terminal bytecode, link to the exit block.
172 if (isTerminal(opcodeID
)) {
173 ASSERT(bytecodeOffset
+ opcodeLength
== block
->leaderBytecodeOffset() + block
->totalBytecodeLength());
174 linkBlocks(block
, exit
);
175 fallsThrough
= false;
179 // If we found a throw, get the HandlerInfo for this instruction to see where we will jump.
180 // If there isn't one, treat this throw as a terminal. This is true even if we have a finally
181 // block because the finally block will create its own catch, which will generate a HandlerInfo.
182 if (isThrow(opcodeID
)) {
183 ASSERT(bytecodeOffset
+ opcodeLength
== block
->leaderBytecodeOffset() + block
->totalBytecodeLength());
184 HandlerInfo
* handler
= codeBlock
->handlerForBytecodeOffset(bytecodeOffset
);
185 fallsThrough
= false;
187 linkBlocks(block
, exit
);
190 for (unsigned i
= 0; i
< basicBlocks
.size(); i
++) {
191 BytecodeBasicBlock
* otherBlock
= basicBlocks
[i
].get();
192 if (handler
->target
== otherBlock
->leaderBytecodeOffset()) {
193 linkBlocks(block
, otherBlock
);
200 // If we found a branch, link to the block(s) that we jump to.
201 if (isBranch(opcodeID
)) {
202 ASSERT(bytecodeOffset
+ opcodeLength
== block
->leaderBytecodeOffset() + block
->totalBytecodeLength());
203 Vector
<unsigned, 1> bytecodeOffsetsJumpedTo
;
204 findJumpTargetsForBytecodeOffset(codeBlock
, bytecodeOffset
, bytecodeOffsetsJumpedTo
);
206 for (unsigned i
= 0; i
< basicBlocks
.size(); i
++) {
207 BytecodeBasicBlock
* otherBlock
= basicBlocks
[i
].get();
208 if (bytecodeOffsetsJumpedTo
.contains(otherBlock
->leaderBytecodeOffset()))
209 linkBlocks(block
, otherBlock
);
212 if (isUnconditionalBranch(opcodeID
))
213 fallsThrough
= false;
217 bytecodeOffset
+= opcodeLength
;
220 // If we fall through then link to the next block in program order.
222 ASSERT(i
+ 1 < basicBlocks
.size());
223 BytecodeBasicBlock
* nextBlock
= basicBlocks
[i
+ 1].get();
224 linkBlocks(block
, nextBlock
);
228 basicBlocks
.append(adoptRef(exit
));