1/* 2 * Copyright (C) 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 "FTLCapabilities.h" 28 29#if ENABLE(FTL_JIT) 30 31namespace JSC { namespace FTL { 32 33using namespace DFG; 34 35static bool verboseCapabilities() 36{ 37 return verboseCompilationEnabled() || Options::verboseFTLFailure(); 38} 39 40inline CapabilityLevel canCompile(Node* node) 41{ 42 // NOTE: If we ever have phantom arguments, we can compile them but we cannot 43 // OSR enter. 44 45 switch (node->op()) { 46 case JSConstant: 47 case WeakJSConstant: 48 case GetMyArgumentsLength: 49 case GetLocal: 50 case SetLocal: 51 case MovHint: 52 case ZombieHint: 53 case Phantom: 54 case HardPhantom: 55 case Flush: 56 case PhantomLocal: 57 case SetArgument: 58 case Return: 59 case BitAnd: 60 case BitOr: 61 case BitXor: 62 case BitRShift: 63 case BitLShift: 64 case BitURShift: 65 case CheckStructure: 66 case StructureTransitionWatchpoint: 67 case ArrayifyToStructure: 68 case PutStructure: 69 case PhantomPutStructure: 70 case GetButterfly: 71 case NewObject: 72 case NewArray: 73 case NewArrayBuffer: 74 case GetByOffset: 75 case PutByOffset: 76 case GetGlobalVar: 77 case PutGlobalVar: 78 case ValueAdd: 79 case ArithAdd: 80 case ArithSub: 81 case ArithMul: 82 case ArithDiv: 83 case ArithMod: 84 case ArithMin: 85 case ArithMax: 86 case ArithAbs: 87 case ArithSin: 88 case ArithCos: 89 case ArithSqrt: 90 case ArithFRound: 91 case ArithNegate: 92 case UInt32ToNumber: 93 case CompareEqConstant: 94 case Jump: 95 case ForceOSRExit: 96 case Phi: 97 case Upsilon: 98 case ExtractOSREntryLocal: 99 case LoopHint: 100 case GetMyScope: 101 case SkipScope: 102 case GetClosureRegisters: 103 case GetClosureVar: 104 case PutClosureVar: 105 case InvalidationPoint: 106 case StringCharAt: 107 case CheckFunction: 108 case StringCharCodeAt: 109 case AllocatePropertyStorage: 110 case ReallocatePropertyStorage: 111 case FunctionReentryWatchpoint: 112 case TypedArrayWatchpoint: 113 case GetTypedArrayByteOffset: 114 case VariableWatchpoint: 115 case NotifyWrite: 116 case StoreBarrier: 117 case StoreBarrierWithNullCheck: 118 case Call: 119 case Construct: 120 case ValueToInt32: 121 case Branch: 122 case LogicalNot: 123 case CheckInBounds: 124 case ConstantStoragePointer: 125 case Check: 126 case CountExecution: 127 case CheckExecutable: 128 case GetScope: 129 case AllocationProfileWatchpoint: 130 case CheckArgumentsNotCreated: 131 case GetCallee: 132 case ToString: 133 case MakeRope: 134 case NewArrayWithSize: 135 case GetById: 136 case ToThis: 137 case MultiGetByOffset: 138 case MultiPutByOffset: 139 case ToPrimitive: 140 case PhantomArguments: 141 case Throw: 142 case ThrowReferenceError: 143 case Unreachable: 144 case GetMyArgumentByVal: 145 case IsUndefined: 146 case IsBoolean: 147 case IsNumber: 148 case IsString: 149 case IsObject: 150 case IsFunction: 151 case CheckHasInstance: 152 case InstanceOf: 153 case DoubleRep: 154 case ValueRep: 155 case Int52Rep: 156 case DoubleConstant: 157 case Int52Constant: 158 case BooleanToNumber: 159 // These are OK. 160 break; 161 case Identity: 162 // No backend handles this because it will be optimized out. But we may check 163 // for capabilities before optimization. It would be a deep error to remove this 164 // case because it would prevent us from catching bugs where the FTL backend 165 // pipeline failed to optimize out an Identity. 166 break; 167 case PutByIdDirect: 168 case PutById: 169 if (node->child1().useKind() == CellUse) 170 break; 171 return CannotCompile; 172 case GetIndexedPropertyStorage: 173 if (node->arrayMode().type() == Array::String) 174 break; 175 if (isTypedView(node->arrayMode().typedArrayType())) 176 break; 177 return CannotCompile; 178 case CheckArray: 179 switch (node->arrayMode().type()) { 180 case Array::Int32: 181 case Array::Double: 182 case Array::Contiguous: 183 break; 184 default: 185 if (isTypedView(node->arrayMode().typedArrayType())) 186 break; 187 return CannotCompile; 188 } 189 break; 190 case GetArrayLength: 191 switch (node->arrayMode().type()) { 192 case Array::Int32: 193 case Array::Double: 194 case Array::Contiguous: 195 case Array::String: 196 break; 197 default: 198 if (isTypedView(node->arrayMode().typedArrayType())) 199 break; 200 return CannotCompile; 201 } 202 break; 203 case GetByVal: 204 switch (node->arrayMode().type()) { 205 case Array::ForceExit: 206 case Array::Generic: 207 case Array::String: 208 case Array::Int32: 209 case Array::Double: 210 case Array::Contiguous: 211 break; 212 default: 213 if (isTypedView(node->arrayMode().typedArrayType())) 214 return CanCompileAndOSREnter; 215 return CannotCompile; 216 } 217 break; 218 case PutByVal: 219 case PutByValAlias: 220 case PutByValDirect: 221 switch (node->arrayMode().type()) { 222 case Array::ForceExit: 223 case Array::Generic: 224 case Array::Int32: 225 case Array::Double: 226 case Array::Contiguous: 227 break; 228 default: 229 if (isTypedView(node->arrayMode().typedArrayType())) 230 return CanCompileAndOSREnter; 231 return CannotCompile; 232 } 233 break; 234 case ArrayPush: 235 case ArrayPop: 236 switch (node->arrayMode().type()) { 237 case Array::Int32: 238 case Array::Contiguous: 239 case Array::Double: 240 break; 241 default: 242 return CannotCompile; 243 } 244 break; 245 case CompareEq: 246 if (node->isBinaryUseKind(Int32Use)) 247 break; 248 if (node->isBinaryUseKind(Int52RepUse)) 249 break; 250 if (node->isBinaryUseKind(DoubleRepUse)) 251 break; 252 if (node->isBinaryUseKind(StringIdentUse)) 253 break; 254 if (node->isBinaryUseKind(ObjectUse)) 255 break; 256 if (node->isBinaryUseKind(UntypedUse)) 257 break; 258 if (node->isBinaryUseKind(BooleanUse)) 259 break; 260 if (node->isBinaryUseKind(ObjectUse, ObjectOrOtherUse)) 261 break; 262 if (node->isBinaryUseKind(ObjectOrOtherUse, ObjectUse)) 263 break; 264 return CannotCompile; 265 case CompareStrictEq: 266 if (node->isBinaryUseKind(Int32Use)) 267 break; 268 if (node->isBinaryUseKind(Int52RepUse)) 269 break; 270 if (node->isBinaryUseKind(DoubleRepUse)) 271 break; 272 if (node->isBinaryUseKind(StringIdentUse)) 273 break; 274 if (node->isBinaryUseKind(ObjectUse)) 275 break; 276 if (node->isBinaryUseKind(BooleanUse)) 277 break; 278 if (node->isBinaryUseKind(MiscUse, UntypedUse)) 279 break; 280 if (node->isBinaryUseKind(UntypedUse, MiscUse)) 281 break; 282 if (node->isBinaryUseKind(StringIdentUse, NotStringVarUse)) 283 break; 284 if (node->isBinaryUseKind(NotStringVarUse, StringIdentUse)) 285 break; 286 return CannotCompile; 287 case CompareLess: 288 case CompareLessEq: 289 case CompareGreater: 290 case CompareGreaterEq: 291 if (node->isBinaryUseKind(Int32Use)) 292 break; 293 if (node->isBinaryUseKind(Int52RepUse)) 294 break; 295 if (node->isBinaryUseKind(DoubleRepUse)) 296 break; 297 if (node->isBinaryUseKind(UntypedUse)) 298 break; 299 return CannotCompile; 300 case Switch: 301 switch (node->switchData()->kind) { 302 case SwitchImm: 303 case SwitchChar: 304 break; 305 default: 306 return CannotCompile; 307 } 308 break; 309 default: 310 // Don't know how to handle anything else. 311 return CannotCompile; 312 } 313 return CanCompileAndOSREnter; 314} 315 316CapabilityLevel canCompile(Graph& graph) 317{ 318 if (graph.m_codeBlock->instructionCount() > Options::maximumFTLCandidateInstructionCount()) { 319 if (verboseCapabilities()) 320 dataLog("FTL rejecting ", *graph.m_codeBlock, " because it's too big.\n"); 321 return CannotCompile; 322 } 323 324 if (graph.m_codeBlock->codeType() != FunctionCode) { 325 if (verboseCapabilities()) 326 dataLog("FTL rejecting ", *graph.m_codeBlock, " because it doesn't belong to a function.\n"); 327 return CannotCompile; 328 } 329 330 if (graph.m_codeBlock->needsActivation()) { 331 // Need this because although we also don't support 332 // CreateActivation/TearOffActivation, we might not see those nodes in case of 333 // OSR entry. 334 // FIXME: Support activations. 335 // https://bugs.webkit.org/show_bug.cgi?id=129576 336 if (verboseCapabilities()) 337 dataLog("FTL rejecting ", *graph.m_codeBlock, " because it uses activations.\n"); 338 return CannotCompile; 339 } 340 341 CapabilityLevel result = CanCompileAndOSREnter; 342 343 for (BlockIndex blockIndex = graph.numBlocks(); blockIndex--;) { 344 BasicBlock* block = graph.block(blockIndex); 345 if (!block) 346 continue; 347 348 // We don't care if we can compile blocks that the CFA hasn't visited. 349 if (!block->cfaHasVisited) 350 continue; 351 352 for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) { 353 Node* node = block->at(nodeIndex); 354 355 for (unsigned childIndex = graph.numChildren(node); childIndex--;) { 356 Edge edge = graph.child(node, childIndex); 357 if (!edge) 358 continue; 359 switch (edge.useKind()) { 360 case UntypedUse: 361 case Int32Use: 362 case KnownInt32Use: 363 case Int52RepUse: 364 case NumberUse: 365 case DoubleRepUse: 366 case DoubleRepRealUse: 367 case BooleanUse: 368 case CellUse: 369 case KnownCellUse: 370 case ObjectUse: 371 case ObjectOrOtherUse: 372 case StringUse: 373 case KnownStringUse: 374 case StringObjectUse: 375 case StringOrStringObjectUse: 376 case FinalObjectUse: 377 case NotCellUse: 378 case OtherUse: 379 case MiscUse: 380 case StringIdentUse: 381 case NotStringVarUse: 382 case MachineIntUse: 383 case DoubleRepMachineIntUse: 384 // These are OK. 385 break; 386 default: 387 // Don't know how to handle anything else. 388 if (verboseCapabilities()) { 389 dataLog("FTL rejecting node in ", *graph.m_codeBlock, " because of bad use kind: ", edge.useKind(), " in node:\n"); 390 graph.dump(WTF::dataFile(), " ", node); 391 } 392 return CannotCompile; 393 } 394 } 395 396 switch (canCompile(node)) { 397 case CannotCompile: 398 if (verboseCapabilities()) { 399 dataLog("FTL rejecting node in ", *graph.m_codeBlock, ":\n"); 400 graph.dump(WTF::dataFile(), " ", node); 401 } 402 return CannotCompile; 403 404 case CanCompile: 405 if (result == CanCompileAndOSREnter && verboseCompilationEnabled()) { 406 dataLog("FTL disabling OSR entry because of node:\n"); 407 graph.dump(WTF::dataFile(), " ", node); 408 } 409 result = CanCompile; 410 break; 411 412 case CanCompileAndOSREnter: 413 break; 414 } 415 416 if (node->op() == ForceOSRExit) 417 break; 418 } 419 } 420 421 return result; 422} 423 424} } // namespace JSC::FTL 425 426#endif // ENABLE(FTL_JIT) 427 428