]> git.saurik.com Git - apple/javascriptcore.git/blob - dfg/DFGCapabilities.cpp
ab0fd2504138ea2724b2636087d4632b27ec6451
[apple/javascriptcore.git] / dfg / DFGCapabilities.cpp
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
38 namespace JSC { namespace DFG {
39
40 bool isSupported(CodeBlock* codeBlock)
41 {
42 return Options::useDFGJIT()
43 && MacroAssembler::supportsFloatingPoint()
44 && Options::bytecodeRangeToDFGCompile().isInRange(codeBlock->instructionCount())
45 && FunctionWhitelist::ensureGlobalWhitelist().contains(codeBlock);
46 }
47
48 bool mightCompileEval(CodeBlock* codeBlock)
49 {
50 return isSupported(codeBlock)
51 && codeBlock->instructionCount() <= Options::maximumOptimizationCandidateInstructionCount();
52 }
53 bool mightCompileProgram(CodeBlock* codeBlock)
54 {
55 return isSupported(codeBlock)
56 && codeBlock->instructionCount() <= Options::maximumOptimizationCandidateInstructionCount();
57 }
58 bool mightCompileFunctionForCall(CodeBlock* codeBlock)
59 {
60 return isSupported(codeBlock)
61 && codeBlock->instructionCount() <= Options::maximumOptimizationCandidateInstructionCount();
62 }
63 bool mightCompileFunctionForConstruct(CodeBlock* codeBlock)
64 {
65 return isSupported(codeBlock)
66 && codeBlock->instructionCount() <= Options::maximumOptimizationCandidateInstructionCount();
67 }
68
69 bool mightInlineFunctionForCall(CodeBlock* codeBlock)
70 {
71 return codeBlock->instructionCount() <= Options::maximumFunctionForCallInlineCandidateInstructionCount()
72 && !codeBlock->ownerExecutable()->needsActivation()
73 && codeBlock->ownerExecutable()->isInliningCandidate();
74 }
75 bool mightInlineFunctionForClosureCall(CodeBlock* codeBlock)
76 {
77 return codeBlock->instructionCount() <= Options::maximumFunctionForClosureCallInlineCandidateInstructionCount()
78 && !codeBlock->ownerExecutable()->needsActivation()
79 && codeBlock->ownerExecutable()->isInliningCandidate();
80 }
81 bool mightInlineFunctionForConstruct(CodeBlock* codeBlock)
82 {
83 return codeBlock->instructionCount() <= Options::maximumFunctionForConstructInlineCandidateInstructionCount()
84 && !codeBlock->ownerExecutable()->needsActivation()
85 && codeBlock->ownerExecutable()->isInliningCandidate();
86 }
87
88 inline 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
94 CapabilityLevel 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
234 CapabilityLevel 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