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