1 | /* |
2 | * Copyright (C) 2008, 2009, 2013, 2014 Apple Inc. All rights reserved. |
3 | * Copyright (C) 2008 Cameron Zwarich <[email protected]> |
4 | * |
5 | * Redistribution and use in source and binary forms, with or without |
6 | * modification, are permitted provided that the following conditions |
7 | * are met: |
8 | * |
9 | * 1. Redistributions of source code must retain the above copyright |
10 | * notice, this list of conditions and the following disclaimer. |
11 | * 2. Redistributions in binary form must reproduce the above copyright |
12 | * notice, this list of conditions and the following disclaimer in the |
13 | * documentation and/or other materials provided with the distribution. |
14 | * 3. Neither the name of Apple Inc. ("Apple") nor the names of |
15 | * its contributors may be used to endorse or promote products derived |
16 | * from this software without specific prior written permission. |
17 | * |
18 | * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY |
19 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
20 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
21 | * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY |
22 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
23 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
24 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
25 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
26 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
27 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
28 | */ |
29 | |
30 | #pragma once |
31 | |
32 | #include "Bytecodes.h" |
33 | #include "LLIntOpcode.h" |
34 | |
35 | #include <algorithm> |
36 | #include <string.h> |
37 | |
38 | #include <wtf/Assertions.h> |
39 | |
40 | namespace JSC { |
41 | |
42 | #define FOR_EACH_CORE_OPCODE_ID_WITH_EXTENSION(macro, extension__) \ |
43 | FOR_EACH_BYTECODE_ID(macro) \ |
44 | extension__ |
45 | |
46 | #define FOR_EACH_CORE_OPCODE_ID(macro) \ |
47 | FOR_EACH_CORE_OPCODE_ID_WITH_EXTENSION(macro, /* No extension */ ) |
48 | |
49 | #define FOR_EACH_OPCODE_ID(macro) \ |
50 | FOR_EACH_CORE_OPCODE_ID_WITH_EXTENSION( \ |
51 | macro, \ |
52 | FOR_EACH_LLINT_OPCODE_EXTENSION(macro) \ |
53 | ) |
54 | |
55 | |
56 | const int maxOpcodeLength = 40; |
57 | #if ENABLE(C_LOOP) |
58 | const int numOpcodeIDs = NUMBER_OF_BYTECODE_IDS + NUMBER_OF_CLOOP_BYTECODE_HELPER_IDS + NUMBER_OF_BYTECODE_HELPER_IDS; |
59 | #else |
60 | const int numOpcodeIDs = NUMBER_OF_BYTECODE_IDS + NUMBER_OF_BYTECODE_HELPER_IDS; |
61 | #endif |
62 | |
63 | constexpr int numWasmOpcodeIDs = NUMBER_OF_WASM_IDS + NUMBER_OF_BYTECODE_HELPER_IDS; |
64 | |
65 | #define OPCODE_ID_ENUM(opcode, length) opcode, |
66 | enum OpcodeID : unsigned { FOR_EACH_OPCODE_ID(OPCODE_ID_ENUM) }; |
67 | enum WasmOpcodeID : unsigned { FOR_EACH_WASM_ID(OPCODE_ID_ENUM) }; |
68 | #undef OPCODE_ID_ENUM |
69 | |
70 | #if ENABLE(C_LOOP) && !HAVE(COMPUTED_GOTO) |
71 | |
72 | #define OPCODE_ID_ENUM(opcode, length) opcode##_wide16 = numOpcodeIDs + opcode, |
73 | enum OpcodeIDWide16 : unsigned { FOR_EACH_OPCODE_ID(OPCODE_ID_ENUM) }; |
74 | enum WasmOpcodeIDWide16 : unsigned { FOR_EACH_WASM_ID(OPCODE_ID_ENUM) }; |
75 | #undef OPCODE_ID_ENUM |
76 | |
77 | #define OPCODE_ID_ENUM(opcode, length) opcode##_wide32 = numOpcodeIDs * 2 + opcode, |
78 | enum OpcodeIDWide32 : unsigned { FOR_EACH_OPCODE_ID(OPCODE_ID_ENUM) }; |
79 | enum WasmOpcodeIDWide32 : unsigned { FOR_EACH_WASM_ID(OPCODE_ID_ENUM) }; |
80 | #undef OPCODE_ID_ENUM |
81 | #endif |
82 | |
83 | extern const unsigned opcodeLengths[]; |
84 | extern const unsigned wasmOpcodeLengths[]; |
85 | |
86 | #define OPCODE_ID_LENGTHS(id, length) const int id##_length = length; |
87 | FOR_EACH_OPCODE_ID(OPCODE_ID_LENGTHS); |
88 | FOR_EACH_WASM_ID(OPCODE_ID_LENGTHS); |
89 | #undef OPCODE_ID_LENGTHS |
90 | |
91 | #define FOR_EACH_OPCODE_WITH_VALUE_PROFILE(macro) \ |
92 | macro(OpCallVarargs) \ |
93 | macro(OpTailCallVarargs) \ |
94 | macro(OpTailCallForwardArguments) \ |
95 | macro(OpConstructVarargs) \ |
96 | macro(OpGetByVal) \ |
97 | macro(OpGetDirectPname) \ |
98 | macro(OpGetById) \ |
99 | macro(OpGetByIdWithThis) \ |
100 | macro(OpTryGetById) \ |
101 | macro(OpGetByIdDirect) \ |
102 | macro(OpGetByValWithThis) \ |
103 | macro(OpGetFromArguments) \ |
104 | macro(OpToNumber) \ |
105 | macro(OpToNumeric) \ |
106 | macro(OpToObject) \ |
107 | macro(OpGetArgument) \ |
108 | macro(OpGetInternalField) \ |
109 | macro(OpToThis) \ |
110 | macro(OpCall) \ |
111 | macro(OpTailCall) \ |
112 | macro(OpCallEval) \ |
113 | macro(OpConstruct) \ |
114 | macro(OpGetFromScope) \ |
115 | macro(OpBitand) \ |
116 | macro(OpBitor) \ |
117 | macro(OpBitnot) \ |
118 | macro(OpBitxor) \ |
119 | macro(OpLshift) \ |
120 | macro(OpRshift) \ |
121 | |
122 | #define FOR_EACH_OPCODE_WITH_ARRAY_PROFILE(macro) \ |
123 | macro(OpHasIndexedProperty) \ |
124 | macro(OpCallVarargs) \ |
125 | macro(OpTailCallVarargs) \ |
126 | macro(OpTailCallForwardArguments) \ |
127 | macro(OpConstructVarargs) \ |
128 | macro(OpGetByVal) \ |
129 | macro(OpInByVal) \ |
130 | macro(OpPutByVal) \ |
131 | macro(OpPutByValDirect) \ |
132 | |
133 | #define FOR_EACH_OPCODE_WITH_ARRAY_ALLOCATION_PROFILE(macro) \ |
134 | macro(OpNewArray) \ |
135 | macro(OpNewArrayWithSize) \ |
136 | macro(OpNewArrayBuffer) \ |
137 | |
138 | #define FOR_EACH_OPCODE_WITH_OBJECT_ALLOCATION_PROFILE(macro) \ |
139 | macro(OpNewObject) \ |
140 | |
141 | #define FOR_EACH_OPCODE_WITH_LLINT_CALL_LINK_INFO(macro) \ |
142 | macro(OpCall) \ |
143 | macro(OpTailCall) \ |
144 | macro(OpCallEval) \ |
145 | macro(OpConstruct) \ |
146 | |
147 | IGNORE_WARNINGS_BEGIN("type-limits" ) |
148 | |
149 | #define VERIFY_OPCODE_ID(id, size) COMPILE_ASSERT(id <= numOpcodeIDs, ASSERT_THAT_JS_OPCODE_IDS_ARE_VALID); |
150 | FOR_EACH_OPCODE_ID(VERIFY_OPCODE_ID); |
151 | #undef VERIFY_OPCODE_ID |
152 | |
153 | IGNORE_WARNINGS_END |
154 | |
155 | #if ENABLE(COMPUTED_GOTO_OPCODES) |
156 | typedef void* Opcode; |
157 | #else |
158 | typedef OpcodeID Opcode; |
159 | #endif |
160 | |
161 | extern const char* const opcodeNames[]; |
162 | extern const char* const wasmOpcodeNames[]; |
163 | |
164 | #if ENABLE(OPCODE_STATS) |
165 | |
166 | struct OpcodeStats { |
167 | OpcodeStats(); |
168 | ~OpcodeStats(); |
169 | static long long opcodeCounts[numOpcodeIDs]; |
170 | static long long opcodePairCounts[numOpcodeIDs][numOpcodeIDs]; |
171 | static int lastOpcode; |
172 | |
173 | static void recordInstruction(int opcode); |
174 | static void resetLastInstruction(); |
175 | }; |
176 | |
177 | #endif |
178 | |
179 | inline bool isBranch(OpcodeID opcodeID) |
180 | { |
181 | switch (opcodeID) { |
182 | case op_jmp: |
183 | case op_jtrue: |
184 | case op_jfalse: |
185 | case op_jeq_null: |
186 | case op_jneq_null: |
187 | case op_jundefined_or_null: |
188 | case op_jnundefined_or_null: |
189 | case op_jneq_ptr: |
190 | case op_jless: |
191 | case op_jlesseq: |
192 | case op_jgreater: |
193 | case op_jgreatereq: |
194 | case op_jnless: |
195 | case op_jnlesseq: |
196 | case op_jngreater: |
197 | case op_jngreatereq: |
198 | case op_jeq: |
199 | case op_jneq: |
200 | case op_jstricteq: |
201 | case op_jnstricteq: |
202 | case op_jbelow: |
203 | case op_jbeloweq: |
204 | case op_switch_imm: |
205 | case op_switch_char: |
206 | case op_switch_string: |
207 | return true; |
208 | default: |
209 | return false; |
210 | } |
211 | } |
212 | |
213 | inline bool isUnconditionalBranch(OpcodeID opcodeID) |
214 | { |
215 | switch (opcodeID) { |
216 | case op_jmp: |
217 | return true; |
218 | default: |
219 | return false; |
220 | } |
221 | } |
222 | |
223 | inline bool isTerminal(OpcodeID opcodeID) |
224 | { |
225 | switch (opcodeID) { |
226 | case op_ret: |
227 | case op_end: |
228 | case op_unreachable: |
229 | return true; |
230 | default: |
231 | return false; |
232 | } |
233 | } |
234 | |
235 | inline bool isThrow(OpcodeID opcodeID) |
236 | { |
237 | switch (opcodeID) { |
238 | case op_throw: |
239 | case op_throw_static_error: |
240 | return true; |
241 | default: |
242 | return false; |
243 | } |
244 | } |
245 | |
246 | unsigned metadataSize(OpcodeID); |
247 | unsigned metadataAlignment(OpcodeID); |
248 | |
249 | } // namespace JSC |
250 | |
251 | namespace WTF { |
252 | |
253 | class PrintStream; |
254 | |
255 | void printInternal(PrintStream&, JSC::OpcodeID); |
256 | |
257 | } // namespace WTF |
258 | |