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