2 * Copyright (C) 2011, 2013-2015 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 "Interpreter.h"
34 #include "JSCInlines.h"
37 namespace JSC
{ namespace DFG
{
41 return Options::useDFGJIT()
42 && MacroAssembler::supportsFloatingPoint();
45 bool isSupportedForInlining(CodeBlock
* codeBlock
)
47 return codeBlock
->ownerExecutable()->isInliningCandidate();
50 bool mightCompileEval(CodeBlock
* codeBlock
)
53 && codeBlock
->instructionCount() <= Options::maximumOptimizationCandidateInstructionCount();
55 bool mightCompileProgram(CodeBlock
* codeBlock
)
58 && codeBlock
->instructionCount() <= Options::maximumOptimizationCandidateInstructionCount();
60 bool mightCompileFunctionForCall(CodeBlock
* codeBlock
)
63 && codeBlock
->instructionCount() <= Options::maximumOptimizationCandidateInstructionCount();
65 bool mightCompileFunctionForConstruct(CodeBlock
* codeBlock
)
68 && codeBlock
->instructionCount() <= Options::maximumOptimizationCandidateInstructionCount();
71 bool mightInlineFunctionForCall(CodeBlock
* codeBlock
)
73 return codeBlock
->instructionCount() <= Options::maximumFunctionForCallInlineCandidateInstructionCount()
74 && isSupportedForInlining(codeBlock
);
76 bool mightInlineFunctionForClosureCall(CodeBlock
* codeBlock
)
78 return codeBlock
->instructionCount() <= Options::maximumFunctionForClosureCallInlineCandidateInstructionCount()
79 && isSupportedForInlining(codeBlock
);
81 bool mightInlineFunctionForConstruct(CodeBlock
* codeBlock
)
83 return codeBlock
->instructionCount() <= Options::maximumFunctionForConstructInlineCandidateInstructionCount()
84 && isSupportedForInlining(codeBlock
);
87 inline void debugFail(CodeBlock
* codeBlock
, OpcodeID opcodeID
, CapabilityLevel result
)
89 if (Options::verboseCompilation() && !canCompile(result
))
90 dataLog("Cannot compile code block ", *codeBlock
, " because of opcode ", opcodeNames
[opcodeID
], "\n");
93 CapabilityLevel
capabilityLevel(OpcodeID opcodeID
, CodeBlock
* codeBlock
, Instruction
* pc
)
95 UNUSED_PARAM(codeBlock
); // This function does some bytecode parsing. Ordinarily bytecode parsing requires the owning CodeBlock. It's sort of strange that we don't use it here right now.
118 case op_profile_will_call
:
119 case op_profile_did_call
:
120 case op_profile_type
:
121 case op_profile_control_flow
:
123 case op_check_has_instance
:
125 case op_is_undefined
:
130 case op_is_object_or_null
:
145 case op_put_by_val_direct
:
147 case op_get_by_id_out_of_line
:
148 case op_get_array_length
:
150 case op_put_by_id_out_of_line
:
151 case op_put_by_id_transition_direct
:
152 case op_put_by_id_transition_direct_out_of_line
:
153 case op_put_by_id_transition_normal
:
154 case op_put_by_id_transition_normal_out_of_line
:
155 case op_init_global_const_nop
:
156 case op_init_global_const
:
175 case op_new_array_with_size
:
176 case op_new_array_buffer
:
178 case op_to_primitive
:
180 case op_throw_static_error
:
183 case op_call_varargs
:
184 case op_construct_varargs
:
185 case op_create_direct_arguments
:
186 case op_create_scoped_arguments
:
187 case op_create_out_of_band_arguments
:
188 case op_get_from_arguments
:
189 case op_put_to_arguments
:
198 case op_get_from_scope
:
199 case op_get_enumerable_length
:
200 case op_has_generic_property
:
201 case op_has_structure_property
:
202 case op_has_indexed_property
:
203 case op_get_direct_pname
:
204 case op_get_property_enumerator
:
205 case op_enumerator_structure_pname
:
206 case op_enumerator_generic_pname
:
207 case op_to_index_string
:
209 case op_new_func_exp
:
210 case op_create_lexical_environment
:
211 return CanCompileAndInline
;
213 case op_put_to_scope
: {
214 ResolveType resolveType
= ResolveModeAndType(pc
[4].u
.operand
).type();
215 // If we're writing to a readonly property we emit a Dynamic put that
216 // the DFG can't currently handle.
217 if (resolveType
== Dynamic
)
218 return CannotCompile
;
219 return CanCompileAndInline
;
222 case op_resolve_scope
: {
223 // We don't compile 'catch' or 'with', so there's no point in compiling variable resolution within them.
224 ResolveType resolveType
= ResolveModeAndType(pc
[4].u
.operand
).type();
225 if (resolveType
== Dynamic
)
226 return CannotCompile
;
227 return CanCompileAndInline
;
231 case op_switch_string
: // Don't inline because we don't want to copy string tables in the concurrent JIT.
235 return CannotCompile
;
239 CapabilityLevel
capabilityLevel(CodeBlock
* codeBlock
)
241 Interpreter
* interpreter
= codeBlock
->vm()->interpreter
;
242 Instruction
* instructionsBegin
= codeBlock
->instructions().begin();
243 unsigned instructionCount
= codeBlock
->instructions().size();
244 CapabilityLevel result
= CanCompileAndInline
;
246 for (unsigned bytecodeOffset
= 0; bytecodeOffset
< instructionCount
; ) {
247 switch (interpreter
->getOpcodeID(instructionsBegin
[bytecodeOffset
].u
.opcode
)) {
248 #define DEFINE_OP(opcode, length) \
250 CapabilityLevel newResult = leastUpperBound(result, capabilityLevel(opcode, codeBlock, instructionsBegin + bytecodeOffset)); \
251 if (newResult != result) { \
252 debugFail(codeBlock, opcode, newResult); \
253 result = newResult; \
255 bytecodeOffset += length; \
258 FOR_EACH_OPCODE_ID(DEFINE_OP
)
261 RELEASE_ASSERT_NOT_REACHED();
269 } } // namespace JSC::DFG