1 | /*
|
---|
2 | * Copyright (C) 2011-2020 Apple Inc. All rights reserved.
|
---|
3 | *
|
---|
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. ``AS IS'' AND ANY
|
---|
14 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
---|
15 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
---|
16 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
|
---|
17 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
---|
18 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
---|
19 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
---|
20 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
---|
21 | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
---|
22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
---|
23 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
---|
24 | */
|
---|
25 |
|
---|
26 | #include "config.h"
|
---|
27 | #include "DFGCapabilities.h"
|
---|
28 |
|
---|
29 | #if ENABLE(DFG_JIT)
|
---|
30 |
|
---|
31 | #include "CodeBlock.h"
|
---|
32 | #include "DFGCommon.h"
|
---|
33 | #include "JSCellInlines.h"
|
---|
34 | #include "Options.h"
|
---|
35 |
|
---|
36 | namespace JSC { namespace DFG {
|
---|
37 |
|
---|
38 | bool isSupported()
|
---|
39 | {
|
---|
40 | return Options::useDFGJIT() && MacroAssembler::supportsFloatingPoint();
|
---|
41 | }
|
---|
42 |
|
---|
43 | bool isSupportedForInlining(CodeBlock* codeBlock)
|
---|
44 | {
|
---|
45 | return codeBlock->ownerExecutable()->isInliningCandidate();
|
---|
46 | }
|
---|
47 |
|
---|
48 | bool mightCompileEval(CodeBlock* codeBlock)
|
---|
49 | {
|
---|
50 | return isSupported()
|
---|
51 | && codeBlock->bytecodeCost() <= Options::maximumOptimizationCandidateBytecodeCost()
|
---|
52 | && codeBlock->ownerExecutable()->isOkToOptimize();
|
---|
53 | }
|
---|
54 | bool mightCompileProgram(CodeBlock* codeBlock)
|
---|
55 | {
|
---|
56 | return isSupported()
|
---|
57 | && codeBlock->bytecodeCost() <= Options::maximumOptimizationCandidateBytecodeCost()
|
---|
58 | && codeBlock->ownerExecutable()->isOkToOptimize();
|
---|
59 | }
|
---|
60 | bool mightCompileFunctionForCall(CodeBlock* codeBlock)
|
---|
61 | {
|
---|
62 | return isSupported()
|
---|
63 | && codeBlock->bytecodeCost() <= Options::maximumOptimizationCandidateBytecodeCost()
|
---|
64 | && codeBlock->ownerExecutable()->isOkToOptimize();
|
---|
65 | }
|
---|
66 | bool mightCompileFunctionForConstruct(CodeBlock* codeBlock)
|
---|
67 | {
|
---|
68 | return isSupported()
|
---|
69 | && codeBlock->bytecodeCost() <= Options::maximumOptimizationCandidateBytecodeCost()
|
---|
70 | && codeBlock->ownerExecutable()->isOkToOptimize();
|
---|
71 | }
|
---|
72 |
|
---|
73 | bool mightInlineFunctionForCall(CodeBlock* codeBlock)
|
---|
74 | {
|
---|
75 | return codeBlock->bytecodeCost() <= Options::maximumFunctionForCallInlineCandidateBytecodeCost()
|
---|
76 | && isSupportedForInlining(codeBlock);
|
---|
77 | }
|
---|
78 | bool mightInlineFunctionForClosureCall(CodeBlock* codeBlock)
|
---|
79 | {
|
---|
80 | return codeBlock->bytecodeCost() <= Options::maximumFunctionForClosureCallInlineCandidateBytecodeCost()
|
---|
81 | && isSupportedForInlining(codeBlock);
|
---|
82 | }
|
---|
83 | bool mightInlineFunctionForConstruct(CodeBlock* codeBlock)
|
---|
84 | {
|
---|
85 | return codeBlock->bytecodeCost() <= Options::maximumFunctionForConstructInlineCandidateBytecoodeCost()
|
---|
86 | && isSupportedForInlining(codeBlock);
|
---|
87 | }
|
---|
88 | bool canUseOSRExitFuzzing(CodeBlock* codeBlock)
|
---|
89 | {
|
---|
90 | return codeBlock->ownerExecutable()->canUseOSRExitFuzzing();
|
---|
91 | }
|
---|
92 |
|
---|
93 | static bool verboseCapabilities()
|
---|
94 | {
|
---|
95 | return verboseCompilationEnabled() || Options::verboseDFGFailure();
|
---|
96 | }
|
---|
97 |
|
---|
98 | inline void debugFail(CodeBlock* codeBlock, OpcodeID opcodeID, CapabilityLevel result)
|
---|
99 | {
|
---|
100 | if (verboseCapabilities() && !canCompile(result))
|
---|
101 | dataLog("DFG rejecting opcode in ", *codeBlock, " because of opcode ", opcodeNames[opcodeID], "\n");
|
---|
102 | }
|
---|
103 |
|
---|
104 | CapabilityLevel capabilityLevel(OpcodeID opcodeID, CodeBlock* codeBlock, const JSInstruction* pc)
|
---|
105 | {
|
---|
106 | UNUSED_PARAM(codeBlock); // This function does some bytecode parsing. Ordinarily bytecode parsing requires the owning CodeBlock. It's sort of strange that we don't use it here right now.
|
---|
107 | UNUSED_PARAM(pc);
|
---|
108 |
|
---|
109 | switch (opcodeID) {
|
---|
110 | case op_wide16:
|
---|
111 | case op_wide32:
|
---|
112 | RELEASE_ASSERT_NOT_REACHED();
|
---|
113 | case op_enter:
|
---|
114 | case op_to_this:
|
---|
115 | case op_argument_count:
|
---|
116 | case op_check_tdz:
|
---|
117 | case op_create_this:
|
---|
118 | case op_create_promise:
|
---|
119 | case op_create_generator:
|
---|
120 | case op_create_async_generator:
|
---|
121 | case op_bitnot:
|
---|
122 | case op_bitand:
|
---|
123 | case op_bitor:
|
---|
124 | case op_bitxor:
|
---|
125 | case op_rshift:
|
---|
126 | case op_lshift:
|
---|
127 | case op_urshift:
|
---|
128 | case op_unsigned:
|
---|
129 | case op_inc:
|
---|
130 | case op_dec:
|
---|
131 | case op_add:
|
---|
132 | case op_sub:
|
---|
133 | case op_negate:
|
---|
134 | case op_mul:
|
---|
135 | case op_mod:
|
---|
136 | case op_pow:
|
---|
137 | case op_div:
|
---|
138 | case op_debug:
|
---|
139 | case op_profile_type:
|
---|
140 | case op_profile_control_flow:
|
---|
141 | case op_mov:
|
---|
142 | case op_overrides_has_instance:
|
---|
143 | case op_identity_with_profile:
|
---|
144 | case op_instanceof:
|
---|
145 | case op_instanceof_custom:
|
---|
146 | case op_is_empty:
|
---|
147 | case op_typeof_is_undefined:
|
---|
148 | case op_typeof_is_object:
|
---|
149 | case op_typeof_is_function:
|
---|
150 | case op_is_undefined_or_null:
|
---|
151 | case op_is_boolean:
|
---|
152 | case op_is_number:
|
---|
153 | case op_is_big_int:
|
---|
154 | case op_is_object:
|
---|
155 | case op_is_cell_with_type:
|
---|
156 | case op_is_callable:
|
---|
157 | case op_is_constructor:
|
---|
158 | case op_not:
|
---|
159 | case op_less:
|
---|
160 | case op_lesseq:
|
---|
161 | case op_greater:
|
---|
162 | case op_greatereq:
|
---|
163 | case op_below:
|
---|
164 | case op_beloweq:
|
---|
165 | case op_eq:
|
---|
166 | case op_eq_null:
|
---|
167 | case op_stricteq:
|
---|
168 | case op_neq:
|
---|
169 | case op_neq_null:
|
---|
170 | case op_nstricteq:
|
---|
171 | case op_get_by_val:
|
---|
172 | case op_put_by_val:
|
---|
173 | case op_put_by_val_direct:
|
---|
174 | case op_try_get_by_id:
|
---|
175 | case op_get_by_id:
|
---|
176 | case op_get_by_id_with_this:
|
---|
177 | case op_get_by_id_direct:
|
---|
178 | case op_get_by_val_with_this:
|
---|
179 | case op_get_prototype_of:
|
---|
180 | case op_put_by_id:
|
---|
181 | case op_put_by_id_with_this:
|
---|
182 | case op_put_by_val_with_this:
|
---|
183 | case op_put_getter_by_id:
|
---|
184 | case op_put_setter_by_id:
|
---|
185 | case op_put_getter_setter_by_id:
|
---|
186 | case op_put_getter_by_val:
|
---|
187 | case op_put_setter_by_val:
|
---|
188 | case op_define_data_property:
|
---|
189 | case op_define_accessor_property:
|
---|
190 | case op_del_by_id:
|
---|
191 | case op_del_by_val:
|
---|
192 | case op_jmp:
|
---|
193 | case op_jtrue:
|
---|
194 | case op_jfalse:
|
---|
195 | case op_jeq_null:
|
---|
196 | case op_jneq_null:
|
---|
197 | case op_jundefined_or_null:
|
---|
198 | case op_jnundefined_or_null:
|
---|
199 | case op_jless:
|
---|
200 | case op_jlesseq:
|
---|
201 | case op_jgreater:
|
---|
202 | case op_jgreatereq:
|
---|
203 | case op_jnless:
|
---|
204 | case op_jnlesseq:
|
---|
205 | case op_jngreater:
|
---|
206 | case op_jngreatereq:
|
---|
207 | case op_jeq:
|
---|
208 | case op_jneq:
|
---|
209 | case op_jstricteq:
|
---|
210 | case op_jnstricteq:
|
---|
211 | case op_jbelow:
|
---|
212 | case op_jbeloweq:
|
---|
213 | case op_loop_hint:
|
---|
214 | case op_check_traps:
|
---|
215 | case op_nop:
|
---|
216 | case op_ret:
|
---|
217 | case op_end:
|
---|
218 | case op_new_object:
|
---|
219 | case op_new_promise:
|
---|
220 | case op_new_generator:
|
---|
221 | case op_new_array:
|
---|
222 | case op_new_array_with_size:
|
---|
223 | case op_new_array_buffer:
|
---|
224 | case op_new_array_with_spread:
|
---|
225 | case op_spread:
|
---|
226 | case op_strcat:
|
---|
227 | case op_to_primitive:
|
---|
228 | case op_throw:
|
---|
229 | case op_throw_static_error:
|
---|
230 | case op_call:
|
---|
231 | case op_tail_call:
|
---|
232 | case op_construct:
|
---|
233 | case op_call_varargs:
|
---|
234 | case op_tail_call_varargs:
|
---|
235 | case op_tail_call_forward_arguments:
|
---|
236 | case op_construct_varargs:
|
---|
237 | case op_create_direct_arguments:
|
---|
238 | case op_create_scoped_arguments:
|
---|
239 | case op_create_cloned_arguments:
|
---|
240 | case op_create_arguments_butterfly:
|
---|
241 | case op_get_from_arguments:
|
---|
242 | case op_put_to_arguments:
|
---|
243 | case op_get_argument:
|
---|
244 | case op_jeq_ptr:
|
---|
245 | case op_jneq_ptr:
|
---|
246 | case op_typeof:
|
---|
247 | case op_to_number:
|
---|
248 | case op_to_numeric:
|
---|
249 | case op_to_string:
|
---|
250 | case op_to_object:
|
---|
251 | case op_switch_imm:
|
---|
252 | case op_switch_char:
|
---|
253 | case op_in_by_val:
|
---|
254 | case op_in_by_id:
|
---|
255 | case op_has_private_name:
|
---|
256 | case op_has_private_brand:
|
---|
257 | case op_get_scope:
|
---|
258 | case op_get_from_scope:
|
---|
259 | case op_get_property_enumerator:
|
---|
260 | case op_new_func:
|
---|
261 | case op_new_func_exp:
|
---|
262 | case op_new_generator_func:
|
---|
263 | case op_new_generator_func_exp:
|
---|
264 | case op_new_async_generator_func:
|
---|
265 | case op_new_async_generator_func_exp:
|
---|
266 | case op_new_async_func:
|
---|
267 | case op_new_async_func_exp:
|
---|
268 | case op_set_function_name:
|
---|
269 | case op_create_lexical_environment:
|
---|
270 | case op_push_with_scope:
|
---|
271 | case op_get_parent_scope:
|
---|
272 | case op_catch:
|
---|
273 | case op_create_rest:
|
---|
274 | case op_get_rest_length:
|
---|
275 | case op_iterator_open:
|
---|
276 | case op_iterator_next:
|
---|
277 | case op_log_shadow_chicken_prologue:
|
---|
278 | case op_log_shadow_chicken_tail:
|
---|
279 | case op_put_to_scope:
|
---|
280 | case op_resolve_scope:
|
---|
281 | case op_resolve_scope_for_hoisting_func_decl_in_eval:
|
---|
282 | case op_new_regexp:
|
---|
283 | case op_get_internal_field:
|
---|
284 | case op_put_internal_field:
|
---|
285 | case op_to_property_key:
|
---|
286 | case op_unreachable:
|
---|
287 | case op_super_sampler_begin:
|
---|
288 | case op_super_sampler_end:
|
---|
289 | case op_get_private_name:
|
---|
290 | case op_put_private_name:
|
---|
291 | case op_set_private_brand:
|
---|
292 | case op_check_private_brand:
|
---|
293 | case op_switch_string:
|
---|
294 | case op_enumerator_next:
|
---|
295 | case op_enumerator_get_by_val:
|
---|
296 | case op_enumerator_in_by_val:
|
---|
297 | case op_enumerator_has_own_property:
|
---|
298 | return CanCompileAndInline;
|
---|
299 |
|
---|
300 | case op_call_eval:
|
---|
301 | return CanCompile;
|
---|
302 |
|
---|
303 | case op_yield:
|
---|
304 | case op_create_generator_frame_environment:
|
---|
305 | case llint_program_prologue:
|
---|
306 | case llint_eval_prologue:
|
---|
307 | case llint_module_program_prologue:
|
---|
308 | case llint_function_for_call_prologue:
|
---|
309 | case llint_function_for_construct_prologue:
|
---|
310 | case llint_function_for_call_arity_check:
|
---|
311 | case llint_function_for_construct_arity_check:
|
---|
312 | case llint_generic_return_point:
|
---|
313 | case llint_throw_from_slow_path_trampoline:
|
---|
314 | case llint_throw_during_call_trampoline:
|
---|
315 | case llint_native_call_trampoline:
|
---|
316 | case llint_native_construct_trampoline:
|
---|
317 | case llint_internal_function_call_trampoline:
|
---|
318 | case llint_internal_function_construct_trampoline:
|
---|
319 | case llint_link_call_trampoline:
|
---|
320 | case llint_virtual_call_trampoline:
|
---|
321 | case llint_virtual_construct_trampoline:
|
---|
322 | case llint_virtual_tail_call_trampoline:
|
---|
323 | case llint_get_host_call_return_value:
|
---|
324 | case llint_handle_uncaught_exception:
|
---|
325 | case checkpoint_osr_exit_from_inlined_call_trampoline:
|
---|
326 | case checkpoint_osr_exit_trampoline:
|
---|
327 | case normal_osr_exit_trampoline:
|
---|
328 | case fuzzer_return_early_from_loop_hint:
|
---|
329 | case op_iterator_open_return_location:
|
---|
330 | case op_iterator_next_return_location:
|
---|
331 | case op_call_return_location:
|
---|
332 | case op_construct_return_location:
|
---|
333 | case op_call_varargs_return_location:
|
---|
334 | case op_construct_varargs_return_location:
|
---|
335 | case op_call_varargs_slow_return_location:
|
---|
336 | case op_construct_varargs_slow_return_location:
|
---|
337 | case op_get_by_id_return_location:
|
---|
338 | case op_get_by_val_return_location:
|
---|
339 | case op_put_by_id_return_location:
|
---|
340 | case op_put_by_val_return_location:
|
---|
341 | case op_call_slow_return_location:
|
---|
342 | case op_construct_slow_return_location:
|
---|
343 | case op_iterator_open_slow_return_location:
|
---|
344 | case op_iterator_next_slow_return_location:
|
---|
345 | case op_tail_call_slow_return_location:
|
---|
346 | case op_tail_call_forward_arguments_slow_return_location:
|
---|
347 | case op_tail_call_varargs_slow_return_location:
|
---|
348 | case op_call_eval_slow_return_location:
|
---|
349 | case wasm_function_prologue:
|
---|
350 | case wasm_function_prologue_no_tls:
|
---|
351 | case js_trampoline_op_call:
|
---|
352 | case js_trampoline_op_construct:
|
---|
353 | case js_trampoline_op_call_varargs:
|
---|
354 | case js_trampoline_op_construct_varargs:
|
---|
355 | case js_trampoline_op_iterator_next:
|
---|
356 | case js_trampoline_op_iterator_open:
|
---|
357 | case js_trampoline_op_call_slow:
|
---|
358 | case js_trampoline_op_tail_call_slow:
|
---|
359 | case js_trampoline_op_construct_slow:
|
---|
360 | case js_trampoline_op_call_varargs_slow:
|
---|
361 | case js_trampoline_op_tail_call_varargs_slow:
|
---|
362 | case js_trampoline_op_tail_call_forward_arguments_slow:
|
---|
363 | case js_trampoline_op_construct_varargs_slow:
|
---|
364 | case js_trampoline_op_call_eval_slow:
|
---|
365 | case js_trampoline_op_iterator_next_slow:
|
---|
366 | case js_trampoline_op_iterator_open_slow:
|
---|
367 | case js_trampoline_llint_function_for_call_arity_check_untag:
|
---|
368 | case js_trampoline_llint_function_for_call_arity_check_tag:
|
---|
369 | case js_trampoline_llint_function_for_construct_arity_check_untag:
|
---|
370 | case js_trampoline_llint_function_for_construct_arity_check_tag:
|
---|
371 | case wasm_trampoline_wasm_call:
|
---|
372 | case wasm_trampoline_wasm_call_no_tls:
|
---|
373 | case wasm_trampoline_wasm_call_indirect:
|
---|
374 | case wasm_trampoline_wasm_call_indirect_no_tls:
|
---|
375 | case wasm_trampoline_wasm_call_ref:
|
---|
376 | case wasm_trampoline_wasm_call_ref_no_tls:
|
---|
377 | return CannotCompile;
|
---|
378 | }
|
---|
379 | return CannotCompile;
|
---|
380 | }
|
---|
381 |
|
---|
382 | CapabilityLevel capabilityLevel(CodeBlock* codeBlock)
|
---|
383 | {
|
---|
384 | CapabilityLevel result = CanCompileAndInline;
|
---|
385 |
|
---|
386 | for (const auto& instruction : codeBlock->instructions()) {
|
---|
387 | switch (instruction->opcodeID()) {
|
---|
388 | #define DEFINE_OP(opcode, length) \
|
---|
389 | case opcode: { \
|
---|
390 | CapabilityLevel newResult = leastUpperBound(result, capabilityLevel(opcode, codeBlock, instruction.ptr())); \
|
---|
391 | if (newResult != result) { \
|
---|
392 | debugFail(codeBlock, opcode, newResult); \
|
---|
393 | result = newResult; \
|
---|
394 | } \
|
---|
395 | break; \
|
---|
396 | }
|
---|
397 | FOR_EACH_OPCODE_ID(DEFINE_OP)
|
---|
398 | #undef DEFINE_OP
|
---|
399 | default:
|
---|
400 | RELEASE_ASSERT_NOT_REACHED();
|
---|
401 | break;
|
---|
402 | }
|
---|
403 | }
|
---|
404 |
|
---|
405 | return result;
|
---|
406 | }
|
---|
407 |
|
---|
408 | } } // namespace JSC::DFG
|
---|
409 |
|
---|
410 | #endif
|
---|