]>
git.saurik.com Git - apple/javascriptcore.git/blob - bytecode/BytecodeBasicBlock.cpp
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
:
57 case op_check_has_instance
:
64 static bool isUnconditionalBranch(OpcodeID opcodeID
)
74 static bool isTerminal(OpcodeID opcodeID
)
78 case op_ret_object_or_this
:
86 static bool isThrow(OpcodeID opcodeID
)
90 case op_throw_static_error
:
97 static bool isJumpTarget(OpcodeID opcodeID
, Vector
<unsigned, 32>& jumpTargets
, unsigned bytecodeOffset
)
99 if (opcodeID
== op_catch
)
102 for (unsigned i
= 0; i
< jumpTargets
.size(); i
++) {
103 if (bytecodeOffset
== jumpTargets
[i
])
109 static void linkBlocks(BytecodeBasicBlock
* predecessor
, BytecodeBasicBlock
* successor
)
111 predecessor
->addSuccessor(successor
);
112 successor
->addPredecessor(predecessor
);
115 void computeBytecodeBasicBlocks(CodeBlock
* codeBlock
, Vector
<RefPtr
<BytecodeBasicBlock
> >& basicBlocks
)
117 Vector
<unsigned, 32> jumpTargets
;
118 computePreciseJumpTargets(codeBlock
, jumpTargets
);
120 // Create the entry and exit basic blocks.
121 BytecodeBasicBlock
* entry
= new BytecodeBasicBlock(BytecodeBasicBlock::EntryBlock
);
122 basicBlocks
.append(adoptRef(entry
));
123 BytecodeBasicBlock
* exit
= new BytecodeBasicBlock(BytecodeBasicBlock::ExitBlock
);
125 // Find basic block boundaries.
126 BytecodeBasicBlock
* current
= new BytecodeBasicBlock(0, 0);
127 linkBlocks(entry
, current
);
128 basicBlocks
.append(adoptRef(current
));
130 bool nextInstructionIsLeader
= false;
132 Interpreter
* interpreter
= codeBlock
->vm()->interpreter
;
133 Instruction
* instructionsBegin
= codeBlock
->instructions().begin();
134 unsigned instructionCount
= codeBlock
->instructions().size();
135 for (unsigned bytecodeOffset
= 0; bytecodeOffset
< instructionCount
;) {
136 OpcodeID opcodeID
= interpreter
->getOpcodeID(instructionsBegin
[bytecodeOffset
].u
.opcode
);
137 unsigned opcodeLength
= opcodeLengths
[opcodeID
];
139 bool createdBlock
= false;
140 // If the current bytecode is a jump target, then it's the leader of its own basic block.
141 if (isJumpTarget(opcodeID
, jumpTargets
, bytecodeOffset
) || nextInstructionIsLeader
) {
142 BytecodeBasicBlock
* block
= new BytecodeBasicBlock(bytecodeOffset
, opcodeLength
);
143 basicBlocks
.append(adoptRef(block
));
146 nextInstructionIsLeader
= false;
147 bytecodeOffset
+= opcodeLength
;
150 // If the current bytecode is a branch or a return, then the next instruction is the leader of its own basic block.
151 if (isBranch(opcodeID
) || isTerminal(opcodeID
) || isThrow(opcodeID
))
152 nextInstructionIsLeader
= true;
157 // Otherwise, just add to the length of the current block.
158 current
->addBytecodeLength(opcodeLength
);
159 bytecodeOffset
+= opcodeLength
;
162 // Link basic blocks together.
163 for (unsigned i
= 0; i
< basicBlocks
.size(); i
++) {
164 BytecodeBasicBlock
* block
= basicBlocks
[i
].get();
166 if (block
->isEntryBlock() || block
->isExitBlock())
169 bool fallsThrough
= true;
170 for (unsigned bytecodeOffset
= block
->leaderBytecodeOffset(); bytecodeOffset
< block
->leaderBytecodeOffset() + block
->totalBytecodeLength();) {
171 const Instruction
& currentInstruction
= instructionsBegin
[bytecodeOffset
];
172 OpcodeID opcodeID
= interpreter
->getOpcodeID(currentInstruction
.u
.opcode
);
173 unsigned opcodeLength
= opcodeLengths
[opcodeID
];
174 // If we found a terminal bytecode, link to the exit block.
175 if (isTerminal(opcodeID
)) {
176 ASSERT(bytecodeOffset
+ opcodeLength
== block
->leaderBytecodeOffset() + block
->totalBytecodeLength());
177 linkBlocks(block
, exit
);
178 fallsThrough
= false;
182 // If we found a throw, get the HandlerInfo for this instruction to see where we will jump.
183 // If there isn't one, treat this throw as a terminal. This is true even if we have a finally
184 // block because the finally block will create its own catch, which will generate a HandlerInfo.
185 if (isThrow(opcodeID
)) {
186 ASSERT(bytecodeOffset
+ opcodeLength
== block
->leaderBytecodeOffset() + block
->totalBytecodeLength());
187 HandlerInfo
* handler
= codeBlock
->handlerForBytecodeOffset(bytecodeOffset
);
188 fallsThrough
= false;
190 linkBlocks(block
, exit
);
193 for (unsigned i
= 0; i
< basicBlocks
.size(); i
++) {
194 BytecodeBasicBlock
* otherBlock
= basicBlocks
[i
].get();
195 if (handler
->target
== otherBlock
->leaderBytecodeOffset()) {
196 linkBlocks(block
, otherBlock
);
203 // If we found a branch, link to the block(s) that we jump to.
204 if (isBranch(opcodeID
)) {
205 ASSERT(bytecodeOffset
+ opcodeLength
== block
->leaderBytecodeOffset() + block
->totalBytecodeLength());
206 Vector
<unsigned, 1> bytecodeOffsetsJumpedTo
;
207 findJumpTargetsForBytecodeOffset(codeBlock
, bytecodeOffset
, bytecodeOffsetsJumpedTo
);
209 for (unsigned i
= 0; i
< basicBlocks
.size(); i
++) {
210 BytecodeBasicBlock
* otherBlock
= basicBlocks
[i
].get();
211 if (bytecodeOffsetsJumpedTo
.contains(otherBlock
->leaderBytecodeOffset()))
212 linkBlocks(block
, otherBlock
);
215 if (isUnconditionalBranch(opcodeID
))
216 fallsThrough
= false;
220 bytecodeOffset
+= opcodeLength
;
223 // If we fall through then link to the next block in program order.
225 ASSERT(i
+ 1 < basicBlocks
.size());
226 BytecodeBasicBlock
* nextBlock
= basicBlocks
[i
+ 1].get();
227 linkBlocks(block
, nextBlock
);
231 basicBlocks
.append(adoptRef(exit
));