1/*
2 * Copyright (C) 2011, 2013, 2014 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 "DFGFunctionWhitelist.h"
34#include "Interpreter.h"
35#include "JSCInlines.h"
36#include "Options.h"
37
38namespace JSC { namespace DFG {
39
40bool isSupported(CodeBlock* codeBlock)
41{
42    return Options::useDFGJIT()
43        && MacroAssembler::supportsFloatingPoint()
44        && Options::bytecodeRangeToDFGCompile().isInRange(codeBlock->instructionCount())
45        && FunctionWhitelist::ensureGlobalWhitelist().contains(codeBlock);
46}
47
48bool mightCompileEval(CodeBlock* codeBlock)
49{
50    return isSupported(codeBlock)
51        && codeBlock->instructionCount() <= Options::maximumOptimizationCandidateInstructionCount();
52}
53bool mightCompileProgram(CodeBlock* codeBlock)
54{
55    return isSupported(codeBlock)
56        && codeBlock->instructionCount() <= Options::maximumOptimizationCandidateInstructionCount();
57}
58bool mightCompileFunctionForCall(CodeBlock* codeBlock)
59{
60    return isSupported(codeBlock)
61        && codeBlock->instructionCount() <= Options::maximumOptimizationCandidateInstructionCount();
62}
63bool mightCompileFunctionForConstruct(CodeBlock* codeBlock)
64{
65    return isSupported(codeBlock)
66        && codeBlock->instructionCount() <= Options::maximumOptimizationCandidateInstructionCount();
67}
68
69bool mightInlineFunctionForCall(CodeBlock* codeBlock)
70{
71    return codeBlock->instructionCount() <= Options::maximumFunctionForCallInlineCandidateInstructionCount()
72        && !codeBlock->ownerExecutable()->needsActivation()
73        && codeBlock->ownerExecutable()->isInliningCandidate();
74}
75bool mightInlineFunctionForClosureCall(CodeBlock* codeBlock)
76{
77    return codeBlock->instructionCount() <= Options::maximumFunctionForClosureCallInlineCandidateInstructionCount()
78        && !codeBlock->ownerExecutable()->needsActivation()
79        && codeBlock->ownerExecutable()->isInliningCandidate();
80}
81bool mightInlineFunctionForConstruct(CodeBlock* codeBlock)
82{
83    return codeBlock->instructionCount() <= Options::maximumFunctionForConstructInlineCandidateInstructionCount()
84        && !codeBlock->ownerExecutable()->needsActivation()
85        && codeBlock->ownerExecutable()->isInliningCandidate();
86}
87
88inline void debugFail(CodeBlock* codeBlock, OpcodeID opcodeID, CapabilityLevel result)
89{
90    if (Options::verboseCompilation() && !canCompile(result))
91        dataLog("Cannot compile code block ", *codeBlock, " because of opcode ", opcodeNames[opcodeID], "\n");
92}
93
94CapabilityLevel capabilityLevel(OpcodeID opcodeID, CodeBlock* codeBlock, Instruction* pc)
95{
96    switch (opcodeID) {
97    case op_enter:
98    case op_touch_entry:
99    case op_to_this:
100    case op_create_this:
101    case op_get_callee:
102    case op_bitand:
103    case op_bitor:
104    case op_bitxor:
105    case op_rshift:
106    case op_lshift:
107    case op_urshift:
108    case op_unsigned:
109    case op_inc:
110    case op_dec:
111    case op_add:
112    case op_sub:
113    case op_negate:
114    case op_mul:
115    case op_mod:
116    case op_div:
117    case op_debug:
118    case op_profile_will_call:
119    case op_profile_did_call:
120    case op_mov:
121    case op_captured_mov:
122    case op_check_has_instance:
123    case op_instanceof:
124    case op_is_undefined:
125    case op_is_boolean:
126    case op_is_number:
127    case op_is_string:
128    case op_is_object:
129    case op_is_function:
130    case op_not:
131    case op_less:
132    case op_lesseq:
133    case op_greater:
134    case op_greatereq:
135    case op_eq:
136    case op_eq_null:
137    case op_stricteq:
138    case op_neq:
139    case op_neq_null:
140    case op_nstricteq:
141    case op_get_by_val:
142    case op_put_by_val:
143    case op_put_by_val_direct:
144    case op_get_by_id:
145    case op_get_by_id_out_of_line:
146    case op_get_array_length:
147    case op_put_by_id:
148    case op_put_by_id_out_of_line:
149    case op_put_by_id_transition_direct:
150    case op_put_by_id_transition_direct_out_of_line:
151    case op_put_by_id_transition_normal:
152    case op_put_by_id_transition_normal_out_of_line:
153    case op_init_global_const_nop:
154    case op_init_global_const:
155    case op_jmp:
156    case op_jtrue:
157    case op_jfalse:
158    case op_jeq_null:
159    case op_jneq_null:
160    case op_jless:
161    case op_jlesseq:
162    case op_jgreater:
163    case op_jgreatereq:
164    case op_jnless:
165    case op_jnlesseq:
166    case op_jngreater:
167    case op_jngreatereq:
168    case op_loop_hint:
169    case op_ret:
170    case op_end:
171    case op_new_object:
172    case op_new_array:
173    case op_new_array_with_size:
174    case op_new_array_buffer:
175    case op_strcat:
176    case op_to_primitive:
177    case op_throw:
178    case op_throw_static_error:
179    case op_call:
180    case op_construct:
181    case op_init_lazy_reg:
182    case op_create_arguments:
183    case op_tear_off_arguments:
184    case op_get_argument_by_val:
185    case op_get_arguments_length:
186    case op_jneq_ptr:
187    case op_typeof:
188    case op_to_number:
189    case op_switch_imm:
190    case op_switch_char:
191    case op_in:
192    case op_get_from_scope:
193        return CanCompileAndInline;
194
195    case op_put_to_scope: {
196        ResolveType resolveType = ResolveModeAndType(pc[4].u.operand).type();
197        // If we're writing to a readonly property we emit a Dynamic put that
198        // the DFG can't currently handle.
199        if (resolveType == Dynamic)
200            return CannotCompile;
201        return CanCompileAndInline;
202    }
203
204    case op_resolve_scope: {
205        // We don't compile 'catch' or 'with', so there's no point in compiling variable resolution within them.
206        ResolveType resolveType = ResolveModeAndType(pc[3].u.operand).type();
207        if (resolveType == Dynamic)
208            return CannotCompile;
209        return CanCompileAndInline;
210    }
211
212    case op_call_varargs:
213        if (codeBlock->usesArguments() && pc[4].u.operand == codeBlock->argumentsRegister().offset()
214            && !pc[6].u.operand)
215            return CanInline;
216        // FIXME: We should handle this.
217        // https://bugs.webkit.org/show_bug.cgi?id=127626
218        return CannotCompile;
219
220    case op_new_regexp:
221    case op_create_activation:
222    case op_tear_off_activation:
223    case op_new_func:
224    case op_new_captured_func:
225    case op_new_func_exp:
226    case op_switch_string: // Don't inline because we don't want to copy string tables in the concurrent JIT.
227        return CanCompile;
228
229    default:
230        return CannotCompile;
231    }
232}
233
234CapabilityLevel capabilityLevel(CodeBlock* codeBlock)
235{
236    Interpreter* interpreter = codeBlock->vm()->interpreter;
237    Instruction* instructionsBegin = codeBlock->instructions().begin();
238    unsigned instructionCount = codeBlock->instructions().size();
239    CapabilityLevel result = CanCompileAndInline;
240
241    for (unsigned bytecodeOffset = 0; bytecodeOffset < instructionCount; ) {
242        switch (interpreter->getOpcodeID(instructionsBegin[bytecodeOffset].u.opcode)) {
243#define DEFINE_OP(opcode, length) \
244        case opcode: { \
245            CapabilityLevel newResult = leastUpperBound(result, capabilityLevel(opcode, codeBlock, instructionsBegin + bytecodeOffset)); \
246            if (newResult != result) { \
247                debugFail(codeBlock, opcode, newResult); \
248                result = newResult; \
249            } \
250            bytecodeOffset += length; \
251            break; \
252        }
253            FOR_EACH_OPCODE_ID(DEFINE_OP)
254#undef DEFINE_OP
255        default:
256            RELEASE_ASSERT_NOT_REACHED();
257            break;
258        }
259    }
260
261    return result;
262}
263
264} } // namespace JSC::DFG
265
266#endif
267