1/*
2 * Copyright (C) 2011-2017 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 "InterpreterInlines.h"
34#include "JSCInlines.h"
35#include "Options.h"
36
37namespace JSC { namespace DFG {
38
39bool isSupported()
40{
41 return VM::canUseJIT() && Options::useDFGJIT() && MacroAssembler::supportsFloatingPoint();
42}
43
44bool isSupportedForInlining(CodeBlock* codeBlock)
45{
46 return codeBlock->ownerExecutable()->isInliningCandidate();
47}
48
49bool mightCompileEval(CodeBlock* codeBlock)
50{
51 return isSupported()
52 && codeBlock->bytecodeCost() <= Options::maximumOptimizationCandidateBytecodeCost()
53 && codeBlock->ownerExecutable()->isOkToOptimize();
54}
55bool mightCompileProgram(CodeBlock* codeBlock)
56{
57 return isSupported()
58 && codeBlock->bytecodeCost() <= Options::maximumOptimizationCandidateBytecodeCost()
59 && codeBlock->ownerExecutable()->isOkToOptimize();
60}
61bool mightCompileFunctionForCall(CodeBlock* codeBlock)
62{
63 return isSupported()
64 && codeBlock->bytecodeCost() <= Options::maximumOptimizationCandidateBytecodeCost()
65 && codeBlock->ownerExecutable()->isOkToOptimize();
66}
67bool mightCompileFunctionForConstruct(CodeBlock* codeBlock)
68{
69 return isSupported()
70 && codeBlock->bytecodeCost() <= Options::maximumOptimizationCandidateBytecodeCost()
71 && codeBlock->ownerExecutable()->isOkToOptimize();
72}
73
74bool mightInlineFunctionForCall(CodeBlock* codeBlock)
75{
76 return codeBlock->bytecodeCost() <= Options::maximumFunctionForCallInlineCandidateBytecodeCost()
77 && isSupportedForInlining(codeBlock);
78}
79bool mightInlineFunctionForClosureCall(CodeBlock* codeBlock)
80{
81 return codeBlock->bytecodeCost() <= Options::maximumFunctionForClosureCallInlineCandidateBytecodeCost()
82 && isSupportedForInlining(codeBlock);
83}
84bool mightInlineFunctionForConstruct(CodeBlock* codeBlock)
85{
86 return codeBlock->bytecodeCost() <= Options::maximumFunctionForConstructInlineCandidateBytecoodeCost()
87 && isSupportedForInlining(codeBlock);
88}
89bool canUseOSRExitFuzzing(CodeBlock* codeBlock)
90{
91 return codeBlock->ownerExecutable()->canUseOSRExitFuzzing();
92}
93
94static bool verboseCapabilities()
95{
96 return verboseCompilationEnabled() || Options::verboseDFGFailure();
97}
98
99inline void debugFail(CodeBlock* codeBlock, OpcodeID opcodeID, CapabilityLevel result)
100{
101 if (verboseCapabilities() && !canCompile(result))
102 dataLog("DFG rejecting opcode in ", *codeBlock, " because of opcode ", opcodeNames[opcodeID], "\n");
103}
104
105CapabilityLevel capabilityLevel(OpcodeID opcodeID, CodeBlock* codeBlock, const Instruction* pc)
106{
107 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.
108 UNUSED_PARAM(pc);
109
110 switch (opcodeID) {
111 case op_wide16:
112 case op_wide32:
113 RELEASE_ASSERT_NOT_REACHED();
114 case op_enter:
115 case op_to_this:
116 case op_argument_count:
117 case op_check_tdz:
118 case op_create_this:
119 case op_create_promise:
120 case op_create_generator:
121 case op_create_async_generator:
122 case op_bitnot:
123 case op_bitand:
124 case op_bitor:
125 case op_bitxor:
126 case op_rshift:
127 case op_lshift:
128 case op_urshift:
129 case op_unsigned:
130 case op_inc:
131 case op_dec:
132 case op_add:
133 case op_sub:
134 case op_negate:
135 case op_mul:
136 case op_mod:
137 case op_pow:
138 case op_div:
139 case op_debug:
140 case op_profile_type:
141 case op_profile_control_flow:
142 case op_mov:
143 case op_overrides_has_instance:
144 case op_identity_with_profile:
145 case op_instanceof:
146 case op_instanceof_custom:
147 case op_is_empty:
148 case op_is_undefined:
149 case op_is_undefined_or_null:
150 case op_is_boolean:
151 case op_is_number:
152 case op_is_object:
153 case op_is_object_or_null:
154 case op_is_cell_with_type:
155 case op_is_function:
156 case op_not:
157 case op_less:
158 case op_lesseq:
159 case op_greater:
160 case op_greatereq:
161 case op_below:
162 case op_beloweq:
163 case op_eq:
164 case op_eq_null:
165 case op_stricteq:
166 case op_neq:
167 case op_neq_null:
168 case op_nstricteq:
169 case op_get_by_val:
170 case op_put_by_val:
171 case op_put_by_val_direct:
172 case op_try_get_by_id:
173 case op_get_by_id:
174 case op_get_by_id_with_this:
175 case op_get_by_id_direct:
176 case op_get_by_val_with_this:
177 case op_put_by_id:
178 case op_put_by_id_with_this:
179 case op_put_by_val_with_this:
180 case op_put_getter_by_id:
181 case op_put_setter_by_id:
182 case op_put_getter_setter_by_id:
183 case op_put_getter_by_val:
184 case op_put_setter_by_val:
185 case op_define_data_property:
186 case op_define_accessor_property:
187 case op_del_by_id:
188 case op_del_by_val:
189 case op_jmp:
190 case op_jtrue:
191 case op_jfalse:
192 case op_jeq_null:
193 case op_jneq_null:
194 case op_jundefined_or_null:
195 case op_jnundefined_or_null:
196 case op_jless:
197 case op_jlesseq:
198 case op_jgreater:
199 case op_jgreatereq:
200 case op_jnless:
201 case op_jnlesseq:
202 case op_jngreater:
203 case op_jngreatereq:
204 case op_jeq:
205 case op_jneq:
206 case op_jstricteq:
207 case op_jnstricteq:
208 case op_jbelow:
209 case op_jbeloweq:
210 case op_loop_hint:
211 case op_check_traps:
212 case op_nop:
213 case op_ret:
214 case op_end:
215 case op_new_object:
216 case op_new_promise:
217 case op_new_generator:
218 case op_new_array:
219 case op_new_array_with_size:
220 case op_new_array_buffer:
221 case op_new_array_with_spread:
222 case op_spread:
223 case op_strcat:
224 case op_to_primitive:
225 case op_throw:
226 case op_throw_static_error:
227 case op_call:
228 case op_tail_call:
229 case op_construct:
230 case op_call_varargs:
231 case op_tail_call_varargs:
232 case op_tail_call_forward_arguments:
233 case op_construct_varargs:
234 case op_create_direct_arguments:
235 case op_create_scoped_arguments:
236 case op_create_cloned_arguments:
237 case op_get_from_arguments:
238 case op_put_to_arguments:
239 case op_get_argument:
240 case op_jneq_ptr:
241 case op_typeof:
242 case op_to_number:
243 case op_to_numeric:
244 case op_to_string:
245 case op_to_object:
246 case op_switch_imm:
247 case op_switch_char:
248 case op_in_by_val:
249 case op_in_by_id:
250 case op_get_scope:
251 case op_get_from_scope:
252 case op_get_enumerable_length:
253 case op_has_generic_property:
254 case op_has_structure_property:
255 case op_has_indexed_property:
256 case op_get_direct_pname:
257 case op_get_property_enumerator:
258 case op_enumerator_structure_pname:
259 case op_enumerator_generic_pname:
260 case op_to_index_string:
261 case op_new_func:
262 case op_new_func_exp:
263 case op_new_generator_func:
264 case op_new_generator_func_exp:
265 case op_new_async_generator_func:
266 case op_new_async_generator_func_exp:
267 case op_new_async_func:
268 case op_new_async_func_exp:
269 case op_set_function_name:
270 case op_create_lexical_environment:
271 case op_push_with_scope:
272 case op_get_parent_scope:
273 case op_catch:
274 case op_create_rest:
275 case op_get_rest_length:
276 case op_log_shadow_chicken_prologue:
277 case op_log_shadow_chicken_tail:
278 case op_put_to_scope:
279 case op_resolve_scope:
280 case op_resolve_scope_for_hoisting_func_decl_in_eval:
281 case op_new_regexp:
282 case op_get_internal_field:
283 case op_put_internal_field:
284 case op_unreachable:
285 case op_super_sampler_begin:
286 case op_super_sampler_end:
287 return CanCompileAndInline;
288
289 case op_switch_string: // Don't inline because we don't want to copy string tables in the concurrent JIT.
290 case op_call_eval:
291 return CanCompile;
292
293 case op_yield:
294 case op_create_generator_frame_environment:
295 case llint_program_prologue:
296 case llint_eval_prologue:
297 case llint_module_program_prologue:
298 case llint_function_for_call_prologue:
299 case llint_function_for_construct_prologue:
300 case llint_function_for_call_arity_check:
301 case llint_function_for_construct_arity_check:
302 case llint_generic_return_point:
303 case llint_throw_from_slow_path_trampoline:
304 case llint_throw_during_call_trampoline:
305 case llint_native_call_trampoline:
306 case llint_native_construct_trampoline:
307 case llint_internal_function_call_trampoline:
308 case llint_internal_function_construct_trampoline:
309 case handleUncaughtException:
310 case op_call_return_location:
311 case op_construct_return_location:
312 case op_call_varargs_slow_return_location:
313 case op_construct_varargs_slow_return_location:
314 case op_get_by_id_return_location:
315 case op_get_by_val_return_location:
316 case op_put_by_id_return_location:
317 case op_put_by_val_return_location:
318 case wasm_function_prologue:
319 case wasm_function_prologue_no_tls:
320 return CannotCompile;
321 }
322 return CannotCompile;
323}
324
325CapabilityLevel capabilityLevel(CodeBlock* codeBlock)
326{
327 CapabilityLevel result = CanCompileAndInline;
328
329 for (const auto& instruction : codeBlock->instructions()) {
330 switch (instruction->opcodeID()) {
331#define DEFINE_OP(opcode, length) \
332 case opcode: { \
333 CapabilityLevel newResult = leastUpperBound(result, capabilityLevel(opcode, codeBlock, instruction.ptr())); \
334 if (newResult != result) { \
335 debugFail(codeBlock, opcode, newResult); \
336 result = newResult; \
337 } \
338 break; \
339 }
340 FOR_EACH_OPCODE_ID(DEFINE_OP)
341#undef DEFINE_OP
342 default:
343 RELEASE_ASSERT_NOT_REACHED();
344 break;
345 }
346 }
347
348 return result;
349}
350
351} } // namespace JSC::DFG
352
353#endif
354