blob: b822bb4ef8f16f3ad7a9bf4b7e96cc187f77127f [file] [log] [blame]
mhahnenberg@apple.com3811e212013-11-12 20:35:34 +00001/*
mark.lam@apple.com9b5601a2017-06-16 21:02:37 +00002 * Copyright (C) 2013-2017 Apple Inc. All rights reserved.
mhahnenberg@apple.com3811e212013-11-12 20:35:34 +00003 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
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.
12 *
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.
24 */
25
26#include "config.h"
27#include "BytecodeBasicBlock.h"
28
29#include "CodeBlock.h"
mhahnenberg@apple.com3811e212013-11-12 20:35:34 +000030#include "PreciseJumpTargets.h"
ysuzuki@apple.com193bf7b2020-02-04 19:05:17 +000031#include "UnlinkedCodeBlockGenerator.h"
mhahnenberg@apple.com3811e212013-11-12 20:35:34 +000032
33namespace JSC {
34
ysuzuki@apple.com4642e112020-01-03 02:36:43 +000035DEFINE_ALLOCATOR_WITH_HEAP_IDENTIFIER(BytecodeBasicBlock);
36
justin_michaud@apple.comc488df62022-03-03 06:49:38 +000037template<typename OpcodeTraits>
38BytecodeBasicBlock<OpcodeTraits>::BytecodeBasicBlock(const typename InstructionStreamType::Ref& instruction, unsigned blockIndex)
ysuzuki@apple.com3e7cae22020-01-30 22:32:43 +000039 : m_leaderOffset(instruction.offset())
40 , m_totalLength(0)
41 , m_index(blockIndex)
42{
43 addLength(instruction->size());
44}
45
justin_michaud@apple.comc488df62022-03-03 06:49:38 +000046template<typename OpcodeTraits>
47BytecodeBasicBlock<OpcodeTraits>::BytecodeBasicBlock(typename BytecodeBasicBlock<OpcodeTraits>::SpecialBlockType blockType, unsigned blockIndex)
48 : m_leaderOffset(blockType == BytecodeBasicBlock<OpcodeTraits>::EntryBlock ? 0 : UINT_MAX)
49 , m_totalLength(blockType == BytecodeBasicBlock<OpcodeTraits>::EntryBlock ? 0 : UINT_MAX)
ysuzuki@apple.com3e7cae22020-01-30 22:32:43 +000050 , m_index(blockIndex)
51{
52}
53
justin_michaud@apple.comc488df62022-03-03 06:49:38 +000054template<typename OpcodeTraits>
55void BytecodeBasicBlock<OpcodeTraits>::addLength(unsigned bytecodeLength)
ysuzuki@apple.com3e7cae22020-01-30 22:32:43 +000056{
57 m_delta.append(bytecodeLength);
58 m_totalLength += bytecodeLength;
59}
60
justin_michaud@apple.comc488df62022-03-03 06:49:38 +000061template<typename OpcodeTraits>
62void BytecodeBasicBlock<OpcodeTraits>::shrinkToFit()
benjamin@webkit.org66220c72015-08-24 06:18:42 +000063{
ysuzuki@apple.com3e7cae22020-01-30 22:32:43 +000064 m_delta.shrinkToFit();
benjamin@webkit.org66220c72015-08-24 06:18:42 +000065 m_successors.shrinkToFit();
66}
67
justin_michaud@apple.comc488df62022-03-03 06:49:38 +000068template<typename OpcodeTraits>
69static bool isJumpTarget(typename OpcodeTraits::OpcodeID opcodeID, const Vector<typename BytecodeBasicBlock<OpcodeTraits>::InstructionStreamType::Offset, 32>& jumpTargets, unsigned bytecodeOffset)
mhahnenberg@apple.com3811e212013-11-12 20:35:34 +000070{
71 if (opcodeID == op_catch)
72 return true;
73
benjamin@webkit.org66220c72015-08-24 06:18:42 +000074 return std::binary_search(jumpTargets.begin(), jumpTargets.end(), bytecodeOffset);
mhahnenberg@apple.com3811e212013-11-12 20:35:34 +000075}
76
justin_michaud@apple.comc488df62022-03-03 06:49:38 +000077template<typename OpcodeTraits>
tzagallo@apple.com3474dd02018-10-29 13:16:03 +000078template<typename Block>
justin_michaud@apple.comc488df62022-03-03 06:49:38 +000079auto BytecodeBasicBlock<OpcodeTraits>::computeImpl(Block* codeBlock, const InstructionStreamType& instructions) -> BasicBlockVector
mhahnenberg@apple.com3811e212013-11-12 20:35:34 +000080{
ysuzuki@apple.com3e7cae22020-01-30 22:32:43 +000081 BasicBlockVector basicBlocks;
justin_michaud@apple.comc488df62022-03-03 06:49:38 +000082 Vector<typename InstructionStreamType::Offset, 32> jumpTargets;
tzagallo@apple.com3474dd02018-10-29 13:16:03 +000083 computePreciseJumpTargets(codeBlock, instructions, jumpTargets);
utatane.tea@gmail.comc2585192016-08-25 22:55:10 +000084
justin_michaud@apple.comc488df62022-03-03 06:49:38 +000085 auto linkBlocks = [&] (BytecodeBasicBlock<OpcodeTraits>& from, BytecodeBasicBlock<OpcodeTraits>& to) {
ysuzuki@apple.com3e7cae22020-01-30 22:32:43 +000086 from.addSuccessor(to);
utatane.tea@gmail.comc2585192016-08-25 22:55:10 +000087 };
88
ysuzuki@apple.com3e7cae22020-01-30 22:32:43 +000089 {
90 // Create the entry and exit basic blocks.
91 basicBlocks.reserveCapacity(jumpTargets.size() + 2);
92 {
93 // Entry block.
justin_michaud@apple.comc488df62022-03-03 06:49:38 +000094 basicBlocks.constructAndAppend(BytecodeBasicBlock<OpcodeTraits>::EntryBlock, basicBlocks.size());
ysuzuki@apple.com3e7cae22020-01-30 22:32:43 +000095 // First block.
justin_michaud@apple.comc488df62022-03-03 06:49:38 +000096 basicBlocks.constructAndAppend(BytecodeBasicBlock<OpcodeTraits>::EntryBlock, basicBlocks.size());
ysuzuki@apple.com3e7cae22020-01-30 22:32:43 +000097 linkBlocks(basicBlocks[0], basicBlocks[1]);
mhahnenberg@apple.com3811e212013-11-12 20:35:34 +000098 }
99
justin_michaud@apple.comc488df62022-03-03 06:49:38 +0000100 auto* current = &basicBlocks.last();
101 auto appendBlock = [&] (const typename InstructionStreamType::Ref& instruction) -> BytecodeBasicBlock<OpcodeTraits>* {
ysuzuki@apple.com3e7cae22020-01-30 22:32:43 +0000102 basicBlocks.constructAndAppend(instruction, basicBlocks.size());
103 return &basicBlocks.last();
104 };
105 bool nextInstructionIsLeader = false;
106 for (const auto& instruction : instructions) {
107 auto bytecodeOffset = instruction.offset();
justin_michaud@apple.comc488df62022-03-03 06:49:38 +0000108 auto opcodeID = instruction->opcodeID();
mhahnenberg@apple.com3811e212013-11-12 20:35:34 +0000109
ysuzuki@apple.com3e7cae22020-01-30 22:32:43 +0000110 bool createdBlock = false;
111 // If the current bytecode is a jump target, then it's the leader of its own basic block.
justin_michaud@apple.comc488df62022-03-03 06:49:38 +0000112 if (nextInstructionIsLeader || isJumpTarget<OpcodeTraits>(opcodeID, jumpTargets, bytecodeOffset)) {
ysuzuki@apple.com3e7cae22020-01-30 22:32:43 +0000113 current = appendBlock(instruction);
114 createdBlock = true;
115 nextInstructionIsLeader = false;
116 }
mhahnenberg@apple.com3811e212013-11-12 20:35:34 +0000117
ysuzuki@apple.com3e7cae22020-01-30 22:32:43 +0000118 // If the current bytecode is a branch or a return, then the next instruction is the leader of its own basic block.
119 if (isBranch(opcodeID) || isTerminal(opcodeID) || isThrow(opcodeID))
120 nextInstructionIsLeader = true;
121
122 if (createdBlock)
123 continue;
124
125 // Otherwise, just add to the length of the current block.
126 current->addLength(instruction->size());
127 }
128 // Exit block.
justin_michaud@apple.comc488df62022-03-03 06:49:38 +0000129 basicBlocks.constructAndAppend(BytecodeBasicBlock<OpcodeTraits>::ExitBlock, basicBlocks.size());
ysuzuki@apple.com3e7cae22020-01-30 22:32:43 +0000130 basicBlocks.shrinkToFit();
131 ASSERT(basicBlocks.last().isExitBlock());
mhahnenberg@apple.com3811e212013-11-12 20:35:34 +0000132 }
ysuzuki@apple.com3e7cae22020-01-30 22:32:43 +0000133 // After this point, we never change basicBlocks.
mhahnenberg@apple.com3811e212013-11-12 20:35:34 +0000134
135 // Link basic blocks together.
136 for (unsigned i = 0; i < basicBlocks.size(); i++) {
justin_michaud@apple.comc488df62022-03-03 06:49:38 +0000137 auto& block = basicBlocks[i];
mhahnenberg@apple.com3811e212013-11-12 20:35:34 +0000138
ysuzuki@apple.com3e7cae22020-01-30 22:32:43 +0000139 if (block.isEntryBlock() || block.isExitBlock())
mhahnenberg@apple.com3811e212013-11-12 20:35:34 +0000140 continue;
141
tzagallo@apple.com3474dd02018-10-29 13:16:03 +0000142 bool fallsThrough = true;
ysuzuki@apple.com3e7cae22020-01-30 22:32:43 +0000143 for (unsigned visitedLength = 0; visitedLength < block.totalLength();) {
justin_michaud@apple.comc488df62022-03-03 06:49:38 +0000144 auto instruction = instructions.at(block.leaderOffset() + visitedLength);
145 auto opcodeID = instruction->opcodeID();
tzagallo@apple.com3474dd02018-10-29 13:16:03 +0000146
ysuzuki@apple.com3e7cae22020-01-30 22:32:43 +0000147 visitedLength += instruction->size();
148
mhahnenberg@apple.com3811e212013-11-12 20:35:34 +0000149 // If we found a terminal bytecode, link to the exit block.
150 if (isTerminal(opcodeID)) {
ysuzuki@apple.com3e7cae22020-01-30 22:32:43 +0000151 ASSERT(instruction.offset() + instruction->size() == block.leaderOffset() + block.totalLength());
152 linkBlocks(block, basicBlocks.last());
mhahnenberg@apple.com3811e212013-11-12 20:35:34 +0000153 fallsThrough = false;
154 break;
155 }
156
tzagallo@apple.com3474dd02018-10-29 13:16:03 +0000157 // If we found a throw, get the HandlerInfo for this instruction to see where we will jump.
mhahnenberg@apple.com3811e212013-11-12 20:35:34 +0000158 // If there isn't one, treat this throw as a terminal. This is true even if we have a finally
159 // block because the finally block will create its own catch, which will generate a HandlerInfo.
160 if (isThrow(opcodeID)) {
ysuzuki@apple.com3e7cae22020-01-30 22:32:43 +0000161 ASSERT(instruction.offset() + instruction->size() == block.leaderOffset() + block.totalLength());
keith_miller@apple.com0f985ec2019-10-23 00:55:38 +0000162 auto* handler = codeBlock->handlerForBytecodeIndex(BytecodeIndex(instruction.offset()));
mhahnenberg@apple.com3811e212013-11-12 20:35:34 +0000163 fallsThrough = false;
164 if (!handler) {
ysuzuki@apple.com3e7cae22020-01-30 22:32:43 +0000165 linkBlocks(block, basicBlocks.last());
mhahnenberg@apple.com3811e212013-11-12 20:35:34 +0000166 break;
167 }
ysuzuki@apple.com3e7cae22020-01-30 22:32:43 +0000168 for (auto& otherBlock : basicBlocks) {
169 if (handler->target == otherBlock.leaderOffset()) {
mhahnenberg@apple.com3811e212013-11-12 20:35:34 +0000170 linkBlocks(block, otherBlock);
171 break;
172 }
173 }
174 break;
175 }
176
177 // If we found a branch, link to the block(s) that we jump to.
178 if (isBranch(opcodeID)) {
ysuzuki@apple.com3e7cae22020-01-30 22:32:43 +0000179 ASSERT(instruction.offset() + instruction->size() == block.leaderOffset() + block.totalLength());
justin_michaud@apple.comc488df62022-03-03 06:49:38 +0000180 Vector<typename InstructionStreamType::Offset, 1> bytecodeOffsetsJumpedTo;
tzagallo@apple.com3474dd02018-10-29 13:16:03 +0000181 findJumpTargetsForInstruction(codeBlock, instruction, bytecodeOffsetsJumpedTo);
mhahnenberg@apple.com3811e212013-11-12 20:35:34 +0000182
mark.lam@apple.coma08e5852016-12-14 19:58:27 +0000183 size_t numberOfJumpTargets = bytecodeOffsetsJumpedTo.size();
184 ASSERT(numberOfJumpTargets);
ysuzuki@apple.com3e7cae22020-01-30 22:32:43 +0000185 for (auto& otherBlock : basicBlocks) {
186 if (bytecodeOffsetsJumpedTo.contains(otherBlock.leaderOffset())) {
mhahnenberg@apple.com3811e212013-11-12 20:35:34 +0000187 linkBlocks(block, otherBlock);
mark.lam@apple.coma08e5852016-12-14 19:58:27 +0000188 --numberOfJumpTargets;
189 if (!numberOfJumpTargets)
190 break;
191 }
mhahnenberg@apple.com3811e212013-11-12 20:35:34 +0000192 }
mark.lam@apple.coma08e5852016-12-14 19:58:27 +0000193 // numberOfJumpTargets may not be 0 here if there are multiple jumps targeting the same
194 // basic blocks (e.g. in a switch type opcode). Since we only decrement numberOfJumpTargets
195 // once per basic block, the duplicates are not accounted for. For our purpose here,
196 // that doesn't matter because we only need to link to the target block once regardless
197 // of how many ways this block can jump there.
mhahnenberg@apple.com3811e212013-11-12 20:35:34 +0000198
199 if (isUnconditionalBranch(opcodeID))
200 fallsThrough = false;
201
202 break;
203 }
mhahnenberg@apple.com3811e212013-11-12 20:35:34 +0000204 }
205
206 // If we fall through then link to the next block in program order.
207 if (fallsThrough) {
208 ASSERT(i + 1 < basicBlocks.size());
justin_michaud@apple.comc488df62022-03-03 06:49:38 +0000209 auto& nextBlock = basicBlocks[i + 1];
mhahnenberg@apple.com3811e212013-11-12 20:35:34 +0000210 linkBlocks(block, nextBlock);
211 }
212 }
213
ysuzuki@apple.com3e7cae22020-01-30 22:32:43 +0000214 unsigned index = 0;
215 for (auto& basicBlock : basicBlocks) {
216 basicBlock.shrinkToFit();
217 ASSERT_UNUSED(index, basicBlock.index() == index++);
218 }
tzagallo@apple.com3474dd02018-10-29 13:16:03 +0000219
ysuzuki@apple.com3e7cae22020-01-30 22:32:43 +0000220 return basicBlocks;
mhahnenberg@apple.com3811e212013-11-12 20:35:34 +0000221}
222
justin_michaud@apple.comc488df62022-03-03 06:49:38 +0000223template<>
224auto BytecodeBasicBlock<JSOpcodeTraits>::compute(CodeBlock* codeBlock, const JSInstructionStream& instructions) -> BasicBlockVector
utatane.tea@gmail.comc2585192016-08-25 22:55:10 +0000225{
ysuzuki@apple.com3e7cae22020-01-30 22:32:43 +0000226 return computeImpl(codeBlock, instructions);
utatane.tea@gmail.comc2585192016-08-25 22:55:10 +0000227}
228
justin_michaud@apple.comc488df62022-03-03 06:49:38 +0000229template<>
230auto BytecodeBasicBlock<JSOpcodeTraits>::compute(UnlinkedCodeBlockGenerator* codeBlock, const JSInstructionStream& instructions) -> BasicBlockVector
utatane.tea@gmail.comc2585192016-08-25 22:55:10 +0000231{
ysuzuki@apple.com3e7cae22020-01-30 22:32:43 +0000232 return computeImpl(codeBlock, instructions);
utatane.tea@gmail.comc2585192016-08-25 22:55:10 +0000233}
234
mhahnenberg@apple.com3811e212013-11-12 20:35:34 +0000235} // namespace JSC