1/*
2 * Copyright (C) 2011, 2012 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#ifndef DFGCapabilities_h
27#define DFGCapabilities_h
28
29#include "Intrinsic.h"
30#include "DFGCommon.h"
31#include "DFGNode.h"
32#include "Executable.h"
33#include "Options.h"
34#include "Interpreter.h"
35#include <wtf/Platform.h>
36
37namespace JSC { namespace DFG {
38
39#if ENABLE(DFG_JIT)
40// Fast check functions; if they return true it is still necessary to
41// check opcodes.
42bool mightCompileEval(CodeBlock*);
43bool mightCompileProgram(CodeBlock*);
44bool mightCompileFunctionForCall(CodeBlock*);
45bool mightCompileFunctionForConstruct(CodeBlock*);
46bool mightInlineFunctionForCall(CodeBlock*);
47bool mightInlineFunctionForClosureCall(CodeBlock*);
48bool mightInlineFunctionForConstruct(CodeBlock*);
49
50// Opcode checking.
51inline bool canInlineResolveOperations(ResolveOperations* operations)
52{
53    for (unsigned i = 0; i < operations->size(); i++) {
54        switch (operations->data()[i].m_operation) {
55        case ResolveOperation::ReturnGlobalObjectAsBase:
56        case ResolveOperation::SetBaseToGlobal:
57        case ResolveOperation::SetBaseToUndefined:
58        case ResolveOperation::GetAndReturnGlobalProperty:
59        case ResolveOperation::GetAndReturnGlobalVar:
60        case ResolveOperation::GetAndReturnGlobalVarWatchable:
61        case ResolveOperation::SkipScopes:
62        case ResolveOperation::SetBaseToScope:
63        case ResolveOperation::ReturnScopeAsBase:
64        case ResolveOperation::GetAndReturnScopedVar:
65            continue;
66
67        case ResolveOperation::Fail:
68            // Fall-back resolves don't know how to deal with the ExecState* having a different
69            // global object (and scope) than the inlined code that is invoking that resolve.
70            return false;
71
72        case ResolveOperation::SkipTopScopeNode:
73            // We don't inline code blocks that create activations. Creation of
74            // activations is the only thing that leads to SkipTopScopeNode.
75            return false;
76
77        case ResolveOperation::CheckForDynamicEntriesBeforeGlobalScope:
78            // This would be easy to support in all cases.
79            return false;
80        }
81    }
82    return true;
83}
84
85inline CapabilityLevel canCompileOpcode(OpcodeID opcodeID, CodeBlock*, Instruction*)
86{
87    switch (opcodeID) {
88    case op_enter:
89    case op_convert_this:
90    case op_create_this:
91    case op_get_callee:
92    case op_bitand:
93    case op_bitor:
94    case op_bitxor:
95    case op_rshift:
96    case op_lshift:
97    case op_urshift:
98    case op_inc:
99    case op_dec:
100    case op_add:
101    case op_sub:
102    case op_negate:
103    case op_mul:
104    case op_mod:
105    case op_div:
106#if ENABLE(DEBUG_WITH_BREAKPOINT)
107    case op_debug:
108#endif
109    case op_mov:
110    case op_check_has_instance:
111    case op_instanceof:
112    case op_is_undefined:
113    case op_is_boolean:
114    case op_is_number:
115    case op_is_string:
116    case op_is_object:
117    case op_is_function:
118    case op_not:
119    case op_less:
120    case op_lesseq:
121    case op_greater:
122    case op_greatereq:
123    case op_eq:
124    case op_eq_null:
125    case op_stricteq:
126    case op_neq:
127    case op_neq_null:
128    case op_nstricteq:
129    case op_get_by_val:
130    case op_put_by_val:
131    case op_get_by_id:
132    case op_get_by_id_out_of_line:
133    case op_get_array_length:
134    case op_put_by_id:
135    case op_put_by_id_out_of_line:
136    case op_put_by_id_transition_direct:
137    case op_put_by_id_transition_direct_out_of_line:
138    case op_put_by_id_transition_normal:
139    case op_put_by_id_transition_normal_out_of_line:
140    case op_init_global_const_nop:
141    case op_init_global_const:
142    case op_init_global_const_check:
143    case op_jmp:
144    case op_jtrue:
145    case op_jfalse:
146    case op_jeq_null:
147    case op_jneq_null:
148    case op_jless:
149    case op_jlesseq:
150    case op_jgreater:
151    case op_jgreatereq:
152    case op_jnless:
153    case op_jnlesseq:
154    case op_jngreater:
155    case op_jngreatereq:
156    case op_loop_hint:
157    case op_ret:
158    case op_end:
159    case op_call_put_result:
160    case op_new_object:
161    case op_new_array:
162    case op_new_array_with_size:
163    case op_new_array_buffer:
164    case op_strcat:
165    case op_to_primitive:
166    case op_throw:
167    case op_throw_static_error:
168    case op_call:
169    case op_construct:
170    case op_new_regexp:
171    case op_init_lazy_reg:
172    case op_create_activation:
173    case op_tear_off_activation:
174    case op_create_arguments:
175    case op_tear_off_arguments:
176    case op_new_func:
177    case op_new_func_exp:
178    case op_get_argument_by_val:
179    case op_get_arguments_length:
180    case op_jneq_ptr:
181    case op_put_to_base_variable:
182    case op_put_to_base:
183    case op_typeof:
184    case op_to_number:
185        return CanCompile;
186
187    case op_call_varargs:
188        return MayInline;
189
190    case op_resolve:
191    case op_resolve_global_property:
192    case op_resolve_global_var:
193    case op_resolve_scoped_var:
194    case op_resolve_scoped_var_on_top_scope:
195    case op_resolve_scoped_var_with_top_scope_check:
196        return CanCompile;
197
198    case op_get_scoped_var:
199    case op_put_scoped_var:
200        return CanCompile;
201
202    case op_resolve_base_to_global:
203    case op_resolve_base_to_global_dynamic:
204    case op_resolve_base_to_scope:
205    case op_resolve_base_to_scope_with_top_scope_check:
206    case op_resolve_base:
207    case op_resolve_with_base:
208    case op_resolve_with_this:
209        return CanCompile;
210
211    default:
212        return CannotCompile;
213    }
214}
215
216inline bool canInlineOpcode(OpcodeID opcodeID, CodeBlock* codeBlock, Instruction* pc)
217{
218    switch (opcodeID) {
219    case op_resolve:
220    case op_resolve_global_property:
221    case op_resolve_global_var:
222    case op_resolve_scoped_var:
223    case op_resolve_scoped_var_on_top_scope:
224    case op_resolve_scoped_var_with_top_scope_check:
225        return canInlineResolveOperations(pc[3].u.resolveOperations);
226
227    case op_resolve_base_to_global:
228    case op_resolve_base_to_global_dynamic:
229    case op_resolve_base_to_scope:
230    case op_resolve_base_to_scope_with_top_scope_check:
231    case op_resolve_base:
232    case op_resolve_with_base:
233    case op_resolve_with_this:
234        return canInlineResolveOperations(pc[4].u.resolveOperations);
235
236    case op_get_scoped_var:
237    case op_put_scoped_var:
238        return !codeBlock->needsFullScopeChain();
239
240    // Inlining doesn't correctly remap regular expression operands.
241    case op_new_regexp:
242
243    // We don't support inlining code that creates activations or has nested functions.
244    case op_create_activation:
245    case op_tear_off_activation:
246    case op_new_func:
247    case op_new_func_exp:
248        return false;
249
250    // Inlining supports op_call_varargs if it's a call that just forwards the caller's
251    // arguments.
252    case op_call_varargs:
253        return codeBlock->usesArguments() && pc[3].u.operand == codeBlock->argumentsRegister();
254
255    default:
256        return canCompileOpcode(opcodeID, codeBlock, pc) == CanCompile;
257    }
258}
259
260CapabilityLevel canCompileOpcodes(CodeBlock*);
261bool canInlineOpcodes(CodeBlock*);
262#else // ENABLE(DFG_JIT)
263inline bool mightCompileEval(CodeBlock*) { return false; }
264inline bool mightCompileProgram(CodeBlock*) { return false; }
265inline bool mightCompileFunctionForCall(CodeBlock*) { return false; }
266inline bool mightCompileFunctionForConstruct(CodeBlock*) { return false; }
267inline bool mightInlineFunctionForCall(CodeBlock*) { return false; }
268inline bool mightInlineFunctionForClosureCall(CodeBlock*) { return false; }
269inline bool mightInlineFunctionForConstruct(CodeBlock*) { return false; }
270
271inline CapabilityLevel canCompileOpcode(OpcodeID, CodeBlock*, Instruction*) { return CannotCompile; }
272inline bool canInlineOpcode(OpcodeID, CodeBlock*, Instruction*) { return false; }
273inline CapabilityLevel canCompileOpcodes(CodeBlock*) { return CannotCompile; }
274inline bool canInlineOpcodes(CodeBlock*) { return false; }
275#endif // ENABLE(DFG_JIT)
276
277inline CapabilityLevel canCompileEval(CodeBlock* codeBlock)
278{
279    if (!mightCompileEval(codeBlock))
280        return CannotCompile;
281
282    return canCompileOpcodes(codeBlock);
283}
284
285inline CapabilityLevel canCompileProgram(CodeBlock* codeBlock)
286{
287    if (!mightCompileProgram(codeBlock))
288        return CannotCompile;
289
290    return canCompileOpcodes(codeBlock);
291}
292
293inline CapabilityLevel canCompileFunctionForCall(CodeBlock* codeBlock)
294{
295    if (!mightCompileFunctionForCall(codeBlock))
296        return CannotCompile;
297
298    return canCompileOpcodes(codeBlock);
299}
300
301inline CapabilityLevel canCompileFunctionForConstruct(CodeBlock* codeBlock)
302{
303    if (!mightCompileFunctionForConstruct(codeBlock))
304        return CannotCompile;
305
306    return canCompileOpcodes(codeBlock);
307}
308
309inline bool canInlineFunctionForCall(CodeBlock* codeBlock)
310{
311    return mightInlineFunctionForCall(codeBlock) && canInlineOpcodes(codeBlock);
312}
313
314inline bool canInlineFunctionForClosureCall(CodeBlock* codeBlock)
315{
316    return mightInlineFunctionForClosureCall(codeBlock) && canInlineOpcodes(codeBlock);
317}
318
319inline bool canInlineFunctionForConstruct(CodeBlock* codeBlock)
320{
321    return mightInlineFunctionForConstruct(codeBlock) && canInlineOpcodes(codeBlock);
322}
323
324inline bool mightInlineFunctionFor(CodeBlock* codeBlock, CodeSpecializationKind kind)
325{
326    if (kind == CodeForCall)
327        return mightInlineFunctionForCall(codeBlock);
328    ASSERT(kind == CodeForConstruct);
329    return mightInlineFunctionForConstruct(codeBlock);
330}
331
332inline bool canInlineFunctionFor(CodeBlock* codeBlock, CodeSpecializationKind kind, bool isClosureCall)
333{
334    if (isClosureCall) {
335        ASSERT(kind == CodeForCall);
336        return canInlineFunctionForClosureCall(codeBlock);
337    }
338    if (kind == CodeForCall)
339        return canInlineFunctionForCall(codeBlock);
340    ASSERT(kind == CodeForConstruct);
341    return canInlineFunctionForConstruct(codeBlock);
342}
343
344} } // namespace JSC::DFG
345
346#endif // DFGCapabilities_h
347
348