2 * Copyright (C) 2011, 2013, 2014 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #include "DFGCapabilities.h"
31 #include "CodeBlock.h"
32 #include "DFGCommon.h"
33 #include "DFGFunctionWhitelist.h"
34 #include "Interpreter.h"
35 #include "JSCInlines.h"
38 namespace JSC
{ namespace DFG
{
40 bool isSupported(CodeBlock
* codeBlock
)
42 return Options::useDFGJIT()
43 && MacroAssembler::supportsFloatingPoint()
44 && Options::bytecodeRangeToDFGCompile().isInRange(codeBlock
->instructionCount())
45 && FunctionWhitelist::ensureGlobalWhitelist().contains(codeBlock
);
48 bool mightCompileEval(CodeBlock
* codeBlock
)
50 return isSupported(codeBlock
)
51 && codeBlock
->instructionCount() <= Options::maximumOptimizationCandidateInstructionCount();
53 bool mightCompileProgram(CodeBlock
* codeBlock
)
55 return isSupported(codeBlock
)
56 && codeBlock
->instructionCount() <= Options::maximumOptimizationCandidateInstructionCount();
58 bool mightCompileFunctionForCall(CodeBlock
* codeBlock
)
60 return isSupported(codeBlock
)
61 && codeBlock
->instructionCount() <= Options::maximumOptimizationCandidateInstructionCount();
63 bool mightCompileFunctionForConstruct(CodeBlock
* codeBlock
)
65 return isSupported(codeBlock
)
66 && codeBlock
->instructionCount() <= Options::maximumOptimizationCandidateInstructionCount();
69 bool mightInlineFunctionForCall(CodeBlock
* codeBlock
)
71 return codeBlock
->instructionCount() <= Options::maximumFunctionForCallInlineCandidateInstructionCount()
72 && !codeBlock
->ownerExecutable()->needsActivation()
73 && codeBlock
->ownerExecutable()->isInliningCandidate();
75 bool mightInlineFunctionForClosureCall(CodeBlock
* codeBlock
)
77 return codeBlock
->instructionCount() <= Options::maximumFunctionForClosureCallInlineCandidateInstructionCount()
78 && !codeBlock
->ownerExecutable()->needsActivation()
79 && codeBlock
->ownerExecutable()->isInliningCandidate();
81 bool mightInlineFunctionForConstruct(CodeBlock
* codeBlock
)
83 return codeBlock
->instructionCount() <= Options::maximumFunctionForConstructInlineCandidateInstructionCount()
84 && !codeBlock
->ownerExecutable()->needsActivation()
85 && codeBlock
->ownerExecutable()->isInliningCandidate();
88 inline void debugFail(CodeBlock
* codeBlock
, OpcodeID opcodeID
, CapabilityLevel result
)
90 if (Options::verboseCompilation() && !canCompile(result
))
91 dataLog("Cannot compile code block ", *codeBlock
, " because of opcode ", opcodeNames
[opcodeID
], "\n");
94 CapabilityLevel
capabilityLevel(OpcodeID opcodeID
, CodeBlock
* codeBlock
, Instruction
* pc
)
118 case op_profile_will_call
:
119 case op_profile_did_call
:
121 case op_captured_mov
:
122 case op_check_has_instance
:
124 case op_is_undefined
:
143 case op_put_by_val_direct
:
145 case op_get_by_id_out_of_line
:
146 case op_get_array_length
:
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
:
173 case op_new_array_with_size
:
174 case op_new_array_buffer
:
176 case op_to_primitive
:
178 case op_throw_static_error
:
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
:
192 case op_get_from_scope
:
193 return CanCompileAndInline
;
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
;
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
;
212 case op_call_varargs
:
213 if (codeBlock
->usesArguments() && pc
[4].u
.operand
== codeBlock
->argumentsRegister().offset()
216 // FIXME: We should handle this.
217 // https://bugs.webkit.org/show_bug.cgi?id=127626
218 return CannotCompile
;
221 case op_create_activation
:
222 case op_tear_off_activation
:
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.
230 return CannotCompile
;
234 CapabilityLevel
capabilityLevel(CodeBlock
* codeBlock
)
236 Interpreter
* interpreter
= codeBlock
->vm()->interpreter
;
237 Instruction
* instructionsBegin
= codeBlock
->instructions().begin();
238 unsigned instructionCount
= codeBlock
->instructions().size();
239 CapabilityLevel result
= CanCompileAndInline
;
241 for (unsigned bytecodeOffset
= 0; bytecodeOffset
< instructionCount
; ) {
242 switch (interpreter
->getOpcodeID(instructionsBegin
[bytecodeOffset
].u
.opcode
)) {
243 #define DEFINE_OP(opcode, length) \
245 CapabilityLevel newResult = leastUpperBound(result, capabilityLevel(opcode, codeBlock, instructionsBegin + bytecodeOffset)); \
246 if (newResult != result) { \
247 debugFail(codeBlock, opcode, newResult); \
248 result = newResult; \
250 bytecodeOffset += length; \
253 FOR_EACH_OPCODE_ID(DEFINE_OP
)
256 RELEASE_ASSERT_NOT_REACHED();
264 } } // namespace JSC::DFG