Changeset 240229 in webkit
- Timestamp:
- Jan 20, 2019 10:13:08 PM (5 years ago)
- Location:
- trunk
- Files:
-
- 2 added
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/JSTests/ChangeLog
r240223 r240229 1 2019-01-20 Saam Barati <sbarati@apple.com> 2 3 DFG: When inlining DataView set* intrinsics we need to set undefined as our result 4 https://bugs.webkit.org/show_bug.cgi?id=193644 5 <rdar://problem/46209745> 6 7 Reviewed by Yusuke Suzuki. 8 9 * stress/data-view-set-intrinsic-undefined-result-2.js: Added. 10 (foo): 11 * stress/data-view-set-intrinsic-undefined-result.js: Added. 12 (foo): 13 (bar): 14 1 15 2019-01-20 Saam Barati <sbarati@apple.com> 2 16 -
trunk/Source/JavaScriptCore/ChangeLog
r240228 r240229 1 2019-01-20 Saam Barati <sbarati@apple.com> 2 3 DFG: When inlining DataView set* intrinsics we need to set undefined as our result 4 https://bugs.webkit.org/show_bug.cgi?id=193644 5 <rdar://problem/46209745> 6 7 Reviewed by Yusuke Suzuki. 8 9 This patch also makes it so we fail fast when we make this mistake. 10 I've made this mistake more than once. 11 12 * dfg/DFGByteCodeParser.cpp: 13 (JSC::DFG::ByteCodeParser::handleIntrinsicCall): 14 1 15 2019-01-20 Yusuke Suzuki <ysuzuki@apple.com> 2 16 -
trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
r240220 r240229 2128 2128 if (!result.isValid()) 2129 2129 return false; 2130 2131 switch (intrinsic) { 2132 2133 // Intrinsic Functions: 2134 2135 case AbsIntrinsic: { 2136 if (argumentCountIncludingThis == 1) { // Math.abs() 2130 2131 bool didSetResult = false; 2132 auto setResult = [&] (Node* node) { 2133 RELEASE_ASSERT(!didSetResult); 2134 set(result, node); 2135 didSetResult = true; 2136 }; 2137 2138 auto inlineIntrinsic = [&] { 2139 switch (intrinsic) { 2140 2141 // Intrinsic Functions: 2142 2143 case AbsIntrinsic: { 2144 if (argumentCountIncludingThis == 1) { // Math.abs() 2145 insertChecks(); 2146 setResult(addToGraph(JSConstant, OpInfo(m_constantNaN))); 2147 return true; 2148 } 2149 2150 if (!MacroAssembler::supportsFloatingPointAbs()) 2151 return false; 2152 2137 2153 insertChecks(); 2138 set(result, addToGraph(JSConstant, OpInfo(m_constantNaN))); 2154 Node* node = addToGraph(ArithAbs, get(virtualRegisterForArgument(1, registerOffset))); 2155 if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, Overflow)) 2156 node->mergeFlags(NodeMayOverflowInt32InDFG); 2157 setResult(node); 2139 2158 return true; 2140 2159 } 2141 2160 2142 if (!MacroAssembler::supportsFloatingPointAbs()) 2161 case MinIntrinsic: 2162 case MaxIntrinsic: 2163 if (handleMinMax(result, intrinsic == MinIntrinsic ? ArithMin : ArithMax, registerOffset, argumentCountIncludingThis, insertChecks)) { 2164 didSetResult = true; 2165 return true; 2166 } 2143 2167 return false; 2144 2168 2145 insertChecks();2146 Node* node = addToGraph(ArithAbs, get(virtualRegisterForArgument(1, registerOffset)));2147 if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, Overflow))2148 node->mergeFlags(NodeMayOverflowInt32InDFG);2149 set(result, node);2150 return true;2151 }2152 2153 case MinIntrinsic:2154 return handleMinMax(result, ArithMin, registerOffset, argumentCountIncludingThis, insertChecks);2155 2156 case MaxIntrinsic:2157 return handleMinMax(result, ArithMax, registerOffset, argumentCountIncludingThis, insertChecks);2158 2159 2169 #define DFG_ARITH_UNARY(capitalizedName, lowerName) \ 2160 case capitalizedName##Intrinsic:2161 FOR_EACH_DFG_ARITH_UNARY_OP(DFG_ARITH_UNARY)2170 case capitalizedName##Intrinsic: 2171 FOR_EACH_DFG_ARITH_UNARY_OP(DFG_ARITH_UNARY) 2162 2172 #undef DFG_ARITH_UNARY 2163 { 2164 if (argumentCountIncludingThis == 1) { 2173 { 2174 if (argumentCountIncludingThis == 1) { 2175 insertChecks(); 2176 setResult(addToGraph(JSConstant, OpInfo(m_constantNaN))); 2177 return true; 2178 } 2179 Arith::UnaryType type = Arith::UnaryType::Sin; 2180 switch (intrinsic) { 2181 #define DFG_ARITH_UNARY(capitalizedName, lowerName) \ 2182 case capitalizedName##Intrinsic: \ 2183 type = Arith::UnaryType::capitalizedName; \ 2184 break; 2185 FOR_EACH_DFG_ARITH_UNARY_OP(DFG_ARITH_UNARY) 2186 #undef DFG_ARITH_UNARY 2187 default: 2188 RELEASE_ASSERT_NOT_REACHED(); 2189 } 2165 2190 insertChecks(); 2166 set (result, addToGraph(JSConstant, OpInfo(m_constantNaN)));2191 setResult(addToGraph(ArithUnary, OpInfo(static_cast<std::underlying_type<Arith::UnaryType>::type>(type)), get(virtualRegisterForArgument(1, registerOffset)))); 2167 2192 return true; 2168 2193 } 2169 Arith::UnaryType type = Arith::UnaryType::Sin; 2170 switch (intrinsic) { 2171 #define DFG_ARITH_UNARY(capitalizedName, lowerName) \ 2172 case capitalizedName##Intrinsic: \ 2173 type = Arith::UnaryType::capitalizedName; \ 2174 break; 2175 FOR_EACH_DFG_ARITH_UNARY_OP(DFG_ARITH_UNARY) 2176 #undef DFG_ARITH_UNARY 2177 default: 2194 2195 case FRoundIntrinsic: 2196 case SqrtIntrinsic: { 2197 if (argumentCountIncludingThis == 1) { 2198 insertChecks(); 2199 setResult(addToGraph(JSConstant, OpInfo(m_constantNaN))); 2200 return true; 2201 } 2202 2203 NodeType nodeType = Unreachable; 2204 switch (intrinsic) { 2205 case FRoundIntrinsic: 2206 nodeType = ArithFRound; 2207 break; 2208 case SqrtIntrinsic: 2209 nodeType = ArithSqrt; 2210 break; 2211 default: 2212 RELEASE_ASSERT_NOT_REACHED(); 2213 } 2214 insertChecks(); 2215 setResult(addToGraph(nodeType, get(virtualRegisterForArgument(1, registerOffset)))); 2216 return true; 2217 } 2218 2219 case PowIntrinsic: { 2220 if (argumentCountIncludingThis < 3) { 2221 // Math.pow() and Math.pow(x) return NaN. 2222 insertChecks(); 2223 setResult(addToGraph(JSConstant, OpInfo(m_constantNaN))); 2224 return true; 2225 } 2226 insertChecks(); 2227 VirtualRegister xOperand = virtualRegisterForArgument(1, registerOffset); 2228 VirtualRegister yOperand = virtualRegisterForArgument(2, registerOffset); 2229 setResult(addToGraph(ArithPow, get(xOperand), get(yOperand))); 2230 return true; 2231 } 2232 2233 case ArrayPushIntrinsic: { 2234 #if USE(JSVALUE32_64) 2235 if (isX86()) { 2236 if (argumentCountIncludingThis > 2) 2237 return false; 2238 } 2239 #endif 2240 2241 if (static_cast<unsigned>(argumentCountIncludingThis) >= MIN_SPARSE_ARRAY_INDEX) 2242 return false; 2243 2244 ArrayMode arrayMode = getArrayMode(Array::Write); 2245 if (!arrayMode.isJSArray()) 2246 return false; 2247 switch (arrayMode.type()) { 2248 case Array::Int32: 2249 case Array::Double: 2250 case Array::Contiguous: 2251 case Array::ArrayStorage: { 2252 insertChecks(); 2253 2254 addVarArgChild(nullptr); // For storage. 2255 for (int i = 0; i < argumentCountIncludingThis; ++i) 2256 addVarArgChild(get(virtualRegisterForArgument(i, registerOffset))); 2257 Node* arrayPush = addToGraph(Node::VarArg, ArrayPush, OpInfo(arrayMode.asWord()), OpInfo(prediction)); 2258 setResult(arrayPush); 2259 return true; 2260 } 2261 2262 default: 2263 return false; 2264 } 2265 } 2266 2267 case ArraySliceIntrinsic: { 2268 #if USE(JSVALUE32_64) 2269 if (isX86()) { 2270 // There aren't enough registers for this to be done easily. 2271 return false; 2272 } 2273 #endif 2274 if (argumentCountIncludingThis < 1) 2275 return false; 2276 2277 if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadConstantCache) 2278 || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCache)) 2279 return false; 2280 2281 ArrayMode arrayMode = getArrayMode(Array::Read); 2282 if (!arrayMode.isJSArray()) 2283 return false; 2284 2285 if (!arrayMode.isJSArrayWithOriginalStructure()) 2286 return false; 2287 2288 switch (arrayMode.type()) { 2289 case Array::Double: 2290 case Array::Int32: 2291 case Array::Contiguous: { 2292 JSGlobalObject* globalObject = m_graph.globalObjectFor(currentNodeOrigin().semantic); 2293 2294 Structure* arrayPrototypeStructure = globalObject->arrayPrototype()->structure(*m_vm); 2295 Structure* objectPrototypeStructure = globalObject->objectPrototype()->structure(*m_vm); 2296 2297 // FIXME: We could easily relax the Array/Object.prototype transition as long as we OSR exitted if we saw a hole. 2298 // https://bugs.webkit.org/show_bug.cgi?id=173171 2299 if (globalObject->arraySpeciesWatchpoint().state() == IsWatched 2300 && globalObject->havingABadTimeWatchpoint()->isStillValid() 2301 && arrayPrototypeStructure->transitionWatchpointSetIsStillValid() 2302 && objectPrototypeStructure->transitionWatchpointSetIsStillValid() 2303 && globalObject->arrayPrototypeChainIsSane()) { 2304 2305 m_graph.watchpoints().addLazily(globalObject->arraySpeciesWatchpoint()); 2306 m_graph.watchpoints().addLazily(globalObject->havingABadTimeWatchpoint()); 2307 m_graph.registerAndWatchStructureTransition(arrayPrototypeStructure); 2308 m_graph.registerAndWatchStructureTransition(objectPrototypeStructure); 2309 2310 insertChecks(); 2311 2312 Node* array = get(virtualRegisterForArgument(0, registerOffset)); 2313 // We do a few things here to prove that we aren't skipping doing side-effects in an observable way: 2314 // 1. We ensure that the "constructor" property hasn't been changed (because the observable 2315 // effects of slice require that we perform a Get(array, "constructor") and we can skip 2316 // that if we're an original array structure. (We can relax this in the future by using 2317 // TryGetById and CheckCell). 2318 // 2319 // 2. We check that the array we're calling slice on has the same global object as the lexical 2320 // global object that this code is running in. This requirement is necessary because we setup the 2321 // watchpoints above on the lexical global object. This means that code that calls slice on 2322 // arrays produced by other global objects won't get this optimization. We could relax this 2323 // requirement in the future by checking that the watchpoint hasn't fired at runtime in the code 2324 // we generate instead of registering it as a watchpoint that would invalidate the compilation. 2325 // 2326 // 3. By proving we're an original array structure, we guarantee that the incoming array 2327 // isn't a subclass of Array. 2328 2329 StructureSet structureSet; 2330 structureSet.add(globalObject->originalArrayStructureForIndexingType(ArrayWithInt32)); 2331 structureSet.add(globalObject->originalArrayStructureForIndexingType(ArrayWithContiguous)); 2332 structureSet.add(globalObject->originalArrayStructureForIndexingType(ArrayWithDouble)); 2333 structureSet.add(globalObject->originalArrayStructureForIndexingType(CopyOnWriteArrayWithInt32)); 2334 structureSet.add(globalObject->originalArrayStructureForIndexingType(CopyOnWriteArrayWithContiguous)); 2335 structureSet.add(globalObject->originalArrayStructureForIndexingType(CopyOnWriteArrayWithDouble)); 2336 addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(structureSet)), array); 2337 2338 addVarArgChild(array); 2339 if (argumentCountIncludingThis >= 2) 2340 addVarArgChild(get(virtualRegisterForArgument(1, registerOffset))); // Start index. 2341 if (argumentCountIncludingThis >= 3) 2342 addVarArgChild(get(virtualRegisterForArgument(2, registerOffset))); // End index. 2343 addVarArgChild(addToGraph(GetButterfly, array)); 2344 2345 Node* arraySlice = addToGraph(Node::VarArg, ArraySlice, OpInfo(), OpInfo()); 2346 setResult(arraySlice); 2347 return true; 2348 } 2349 2350 return false; 2351 } 2352 default: 2353 return false; 2354 } 2355 2178 2356 RELEASE_ASSERT_NOT_REACHED(); 2179 } 2180 insertChecks(); 2181 set(result, addToGraph(ArithUnary, OpInfo(static_cast<std::underlying_type<Arith::UnaryType>::type>(type)), get(virtualRegisterForArgument(1, registerOffset)))); 2182 return true; 2183 } 2184 2185 case FRoundIntrinsic: 2186 case SqrtIntrinsic: { 2187 if (argumentCountIncludingThis == 1) { 2357 return false; 2358 } 2359 2360 case ArrayIndexOfIntrinsic: { 2361 if (argumentCountIncludingThis < 2) 2362 return false; 2363 2364 if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadIndexingType) 2365 || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadConstantCache) 2366 || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCache) 2367 || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadType)) 2368 return false; 2369 2370 ArrayMode arrayMode = getArrayMode(Array::Read); 2371 if (!arrayMode.isJSArray()) 2372 return false; 2373 2374 if (!arrayMode.isJSArrayWithOriginalStructure()) 2375 return false; 2376 2377 // We do not want to convert arrays into one type just to perform indexOf. 2378 if (arrayMode.doesConversion()) 2379 return false; 2380 2381 switch (arrayMode.type()) { 2382 case Array::Double: 2383 case Array::Int32: 2384 case Array::Contiguous: { 2385 JSGlobalObject* globalObject = m_graph.globalObjectFor(currentNodeOrigin().semantic); 2386 2387 Structure* arrayPrototypeStructure = globalObject->arrayPrototype()->structure(*m_vm); 2388 Structure* objectPrototypeStructure = globalObject->objectPrototype()->structure(*m_vm); 2389 2390 // FIXME: We could easily relax the Array/Object.prototype transition as long as we OSR exitted if we saw a hole. 2391 // https://bugs.webkit.org/show_bug.cgi?id=173171 2392 if (arrayPrototypeStructure->transitionWatchpointSetIsStillValid() 2393 && objectPrototypeStructure->transitionWatchpointSetIsStillValid() 2394 && globalObject->arrayPrototypeChainIsSane()) { 2395 2396 m_graph.registerAndWatchStructureTransition(arrayPrototypeStructure); 2397 m_graph.registerAndWatchStructureTransition(objectPrototypeStructure); 2398 2399 insertChecks(); 2400 2401 Node* array = get(virtualRegisterForArgument(0, registerOffset)); 2402 addVarArgChild(array); 2403 addVarArgChild(get(virtualRegisterForArgument(1, registerOffset))); // Search element. 2404 if (argumentCountIncludingThis >= 3) 2405 addVarArgChild(get(virtualRegisterForArgument(2, registerOffset))); // Start index. 2406 addVarArgChild(nullptr); 2407 2408 Node* node = addToGraph(Node::VarArg, ArrayIndexOf, OpInfo(arrayMode.asWord()), OpInfo()); 2409 setResult(node); 2410 return true; 2411 } 2412 2413 return false; 2414 } 2415 default: 2416 return false; 2417 } 2418 2419 RELEASE_ASSERT_NOT_REACHED(); 2420 return false; 2421 2422 } 2423 2424 case ArrayPopIntrinsic: { 2425 if (argumentCountIncludingThis != 1) 2426 return false; 2427 2428 ArrayMode arrayMode = getArrayMode(Array::Write); 2429 if (!arrayMode.isJSArray()) 2430 return false; 2431 switch (arrayMode.type()) { 2432 case Array::Int32: 2433 case Array::Double: 2434 case Array::Contiguous: 2435 case Array::ArrayStorage: { 2436 insertChecks(); 2437 Node* arrayPop = addToGraph(ArrayPop, OpInfo(arrayMode.asWord()), OpInfo(prediction), get(virtualRegisterForArgument(0, registerOffset))); 2438 setResult(arrayPop); 2439 return true; 2440 } 2441 2442 default: 2443 return false; 2444 } 2445 } 2446 2447 case AtomicsAddIntrinsic: 2448 case AtomicsAndIntrinsic: 2449 case AtomicsCompareExchangeIntrinsic: 2450 case AtomicsExchangeIntrinsic: 2451 case AtomicsIsLockFreeIntrinsic: 2452 case AtomicsLoadIntrinsic: 2453 case AtomicsOrIntrinsic: 2454 case AtomicsStoreIntrinsic: 2455 case AtomicsSubIntrinsic: 2456 case AtomicsXorIntrinsic: { 2457 if (!is64Bit()) 2458 return false; 2459 2460 NodeType op = LastNodeType; 2461 Array::Action action = Array::Write; 2462 unsigned numArgs = 0; // Number of actual args; we add one for the backing store pointer. 2463 switch (intrinsic) { 2464 case AtomicsAddIntrinsic: 2465 op = AtomicsAdd; 2466 numArgs = 3; 2467 break; 2468 case AtomicsAndIntrinsic: 2469 op = AtomicsAnd; 2470 numArgs = 3; 2471 break; 2472 case AtomicsCompareExchangeIntrinsic: 2473 op = AtomicsCompareExchange; 2474 numArgs = 4; 2475 break; 2476 case AtomicsExchangeIntrinsic: 2477 op = AtomicsExchange; 2478 numArgs = 3; 2479 break; 2480 case AtomicsIsLockFreeIntrinsic: 2481 // This gets no backing store, but we need no special logic for this since this also does 2482 // not need varargs. 2483 op = AtomicsIsLockFree; 2484 numArgs = 1; 2485 break; 2486 case AtomicsLoadIntrinsic: 2487 op = AtomicsLoad; 2488 numArgs = 2; 2489 action = Array::Read; 2490 break; 2491 case AtomicsOrIntrinsic: 2492 op = AtomicsOr; 2493 numArgs = 3; 2494 break; 2495 case AtomicsStoreIntrinsic: 2496 op = AtomicsStore; 2497 numArgs = 3; 2498 break; 2499 case AtomicsSubIntrinsic: 2500 op = AtomicsSub; 2501 numArgs = 3; 2502 break; 2503 case AtomicsXorIntrinsic: 2504 op = AtomicsXor; 2505 numArgs = 3; 2506 break; 2507 default: 2508 RELEASE_ASSERT_NOT_REACHED(); 2509 break; 2510 } 2511 2512 if (static_cast<unsigned>(argumentCountIncludingThis) < 1 + numArgs) 2513 return false; 2514 2188 2515 insertChecks(); 2189 set(result, addToGraph(JSConstant, OpInfo(m_constantNaN))); 2516 2517 Vector<Node*, 3> args; 2518 for (unsigned i = 0; i < numArgs; ++i) 2519 args.append(get(virtualRegisterForArgument(1 + i, registerOffset))); 2520 2521 Node* resultNode; 2522 if (numArgs + 1 <= 3) { 2523 while (args.size() < 3) 2524 args.append(nullptr); 2525 resultNode = addToGraph(op, OpInfo(ArrayMode(Array::SelectUsingPredictions, action).asWord()), OpInfo(prediction), args[0], args[1], args[2]); 2526 } else { 2527 for (Node* node : args) 2528 addVarArgChild(node); 2529 addVarArgChild(nullptr); 2530 resultNode = addToGraph(Node::VarArg, op, OpInfo(ArrayMode(Array::SelectUsingPredictions, action).asWord()), OpInfo(prediction)); 2531 } 2532 2533 setResult(resultNode); 2190 2534 return true; 2191 2535 } 2192 2536 2193 NodeType nodeType = Unreachable; 2194 switch (intrinsic) { 2195 case FRoundIntrinsic: 2196 nodeType = ArithFRound; 2197 break; 2198 case SqrtIntrinsic: 2199 nodeType = ArithSqrt; 2200 break; 2201 default: 2202 RELEASE_ASSERT_NOT_REACHED(); 2203 } 2204 insertChecks(); 2205 set(result, addToGraph(nodeType, get(virtualRegisterForArgument(1, registerOffset)))); 2206 return true; 2207 } 2208 2209 case PowIntrinsic: { 2210 if (argumentCountIncludingThis < 3) { 2211 // Math.pow() and Math.pow(x) return NaN. 2537 case ParseIntIntrinsic: { 2538 if (argumentCountIncludingThis < 2) 2539 return false; 2540 2541 if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCell) || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadType)) 2542 return false; 2543 2212 2544 insertChecks(); 2213 set(result, addToGraph(JSConstant, OpInfo(m_constantNaN))); 2545 VirtualRegister valueOperand = virtualRegisterForArgument(1, registerOffset); 2546 Node* parseInt; 2547 if (argumentCountIncludingThis == 2) 2548 parseInt = addToGraph(ParseInt, OpInfo(), OpInfo(prediction), get(valueOperand)); 2549 else { 2550 ASSERT(argumentCountIncludingThis > 2); 2551 VirtualRegister radixOperand = virtualRegisterForArgument(2, registerOffset); 2552 parseInt = addToGraph(ParseInt, OpInfo(), OpInfo(prediction), get(valueOperand), get(radixOperand)); 2553 } 2554 setResult(parseInt); 2214 2555 return true; 2215 2556 } 2216 insertChecks(); 2217 VirtualRegister xOperand = virtualRegisterForArgument(1, registerOffset); 2218 VirtualRegister yOperand = virtualRegisterForArgument(2, registerOffset); 2219 set(result, addToGraph(ArithPow, get(xOperand), get(yOperand))); 2220 return true; 2221 } 2222 2223 case ArrayPushIntrinsic: { 2224 #if USE(JSVALUE32_64) 2225 if (isX86()) { 2226 if (argumentCountIncludingThis > 2) 2227 return false; 2228 } 2229 #endif 2230 2231 if (static_cast<unsigned>(argumentCountIncludingThis) >= MIN_SPARSE_ARRAY_INDEX) 2232 return false; 2233 2234 ArrayMode arrayMode = getArrayMode(Array::Write); 2235 if (!arrayMode.isJSArray()) 2236 return false; 2237 switch (arrayMode.type()) { 2238 case Array::Int32: 2239 case Array::Double: 2240 case Array::Contiguous: 2241 case Array::ArrayStorage: { 2557 2558 case CharCodeAtIntrinsic: { 2559 if (argumentCountIncludingThis != 2) 2560 return false; 2561 2242 2562 insertChecks(); 2243 2244 addVarArgChild(nullptr); // For storage. 2245 for (int i = 0; i < argumentCountIncludingThis; ++i) 2246 addVarArgChild(get(virtualRegisterForArgument(i, registerOffset))); 2247 Node* arrayPush = addToGraph(Node::VarArg, ArrayPush, OpInfo(arrayMode.asWord()), OpInfo(prediction)); 2248 set(result, arrayPush); 2563 VirtualRegister thisOperand = virtualRegisterForArgument(0, registerOffset); 2564 VirtualRegister indexOperand = virtualRegisterForArgument(1, registerOffset); 2565 Node* charCode = addToGraph(StringCharCodeAt, OpInfo(ArrayMode(Array::String, Array::Read).asWord()), get(thisOperand), get(indexOperand)); 2566 2567 setResult(charCode); 2568 return true; 2569 } 2570 2571 case CharAtIntrinsic: { 2572 if (argumentCountIncludingThis != 2) 2573 return false; 2574 2575 insertChecks(); 2576 VirtualRegister thisOperand = virtualRegisterForArgument(0, registerOffset); 2577 VirtualRegister indexOperand = virtualRegisterForArgument(1, registerOffset); 2578 Node* charCode = addToGraph(StringCharAt, OpInfo(ArrayMode(Array::String, Array::Read).asWord()), get(thisOperand), get(indexOperand)); 2579 2580 setResult(charCode); 2581 return true; 2582 } 2583 case Clz32Intrinsic: { 2584 insertChecks(); 2585 if (argumentCountIncludingThis == 1) 2586 setResult(addToGraph(JSConstant, OpInfo(m_graph.freeze(jsNumber(32))))); 2587 else { 2588 Node* operand = get(virtualRegisterForArgument(1, registerOffset)); 2589 setResult(addToGraph(ArithClz32, operand)); 2590 } 2591 return true; 2592 } 2593 case FromCharCodeIntrinsic: { 2594 if (argumentCountIncludingThis != 2) 2595 return false; 2596 2597 insertChecks(); 2598 VirtualRegister indexOperand = virtualRegisterForArgument(1, registerOffset); 2599 Node* charCode = addToGraph(StringFromCharCode, get(indexOperand)); 2600 2601 setResult(charCode); 2602 2603 return true; 2604 } 2605 2606 case RegExpExecIntrinsic: { 2607 if (argumentCountIncludingThis != 2) 2608 return false; 2609 2610 insertChecks(); 2611 Node* regExpExec = addToGraph(RegExpExec, OpInfo(0), OpInfo(prediction), addToGraph(GetGlobalObject, callee), get(virtualRegisterForArgument(0, registerOffset)), get(virtualRegisterForArgument(1, registerOffset))); 2612 setResult(regExpExec); 2249 2613 2250 2614 return true; 2251 2615 } 2252 2616 2253 default: 2254 return false; 2255 } 2256 } 2257 2258 case ArraySliceIntrinsic: { 2259 #if USE(JSVALUE32_64) 2260 if (isX86()) { 2261 // There aren't enough registers for this to be done easily. 2262 return false; 2263 } 2264 #endif 2265 if (argumentCountIncludingThis < 1) 2266 return false; 2267 2268 if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadConstantCache) 2269 || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCache)) 2270 return false; 2271 2272 ArrayMode arrayMode = getArrayMode(Array::Read); 2273 if (!arrayMode.isJSArray()) 2274 return false; 2275 2276 if (!arrayMode.isJSArrayWithOriginalStructure()) 2277 return false; 2278 2279 switch (arrayMode.type()) { 2280 case Array::Double: 2281 case Array::Int32: 2282 case Array::Contiguous: { 2283 JSGlobalObject* globalObject = m_graph.globalObjectFor(currentNodeOrigin().semantic); 2284 2285 Structure* arrayPrototypeStructure = globalObject->arrayPrototype()->structure(*m_vm); 2286 Structure* objectPrototypeStructure = globalObject->objectPrototype()->structure(*m_vm); 2287 2288 // FIXME: We could easily relax the Array/Object.prototype transition as long as we OSR exitted if we saw a hole. 2289 // https://bugs.webkit.org/show_bug.cgi?id=173171 2290 if (globalObject->arraySpeciesWatchpoint().state() == IsWatched 2291 && globalObject->havingABadTimeWatchpoint()->isStillValid() 2292 && arrayPrototypeStructure->transitionWatchpointSetIsStillValid() 2293 && objectPrototypeStructure->transitionWatchpointSetIsStillValid() 2294 && globalObject->arrayPrototypeChainIsSane()) { 2295 2296 m_graph.watchpoints().addLazily(globalObject->arraySpeciesWatchpoint()); 2297 m_graph.watchpoints().addLazily(globalObject->havingABadTimeWatchpoint()); 2298 m_graph.registerAndWatchStructureTransition(arrayPrototypeStructure); 2299 m_graph.registerAndWatchStructureTransition(objectPrototypeStructure); 2300 2301 insertChecks(); 2302 2303 Node* array = get(virtualRegisterForArgument(0, registerOffset)); 2304 // We do a few things here to prove that we aren't skipping doing side-effects in an observable way: 2305 // 1. We ensure that the "constructor" property hasn't been changed (because the observable 2306 // effects of slice require that we perform a Get(array, "constructor") and we can skip 2307 // that if we're an original array structure. (We can relax this in the future by using 2308 // TryGetById and CheckCell). 2309 // 2310 // 2. We check that the array we're calling slice on has the same global object as the lexical 2311 // global object that this code is running in. This requirement is necessary because we setup the 2312 // watchpoints above on the lexical global object. This means that code that calls slice on 2313 // arrays produced by other global objects won't get this optimization. We could relax this 2314 // requirement in the future by checking that the watchpoint hasn't fired at runtime in the code 2315 // we generate instead of registering it as a watchpoint that would invalidate the compilation. 2316 // 2317 // 3. By proving we're an original array structure, we guarantee that the incoming array 2318 // isn't a subclass of Array. 2319 2320 StructureSet structureSet; 2321 structureSet.add(globalObject->originalArrayStructureForIndexingType(ArrayWithInt32)); 2322 structureSet.add(globalObject->originalArrayStructureForIndexingType(ArrayWithContiguous)); 2323 structureSet.add(globalObject->originalArrayStructureForIndexingType(ArrayWithDouble)); 2324 structureSet.add(globalObject->originalArrayStructureForIndexingType(CopyOnWriteArrayWithInt32)); 2325 structureSet.add(globalObject->originalArrayStructureForIndexingType(CopyOnWriteArrayWithContiguous)); 2326 structureSet.add(globalObject->originalArrayStructureForIndexingType(CopyOnWriteArrayWithDouble)); 2327 addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(structureSet)), array); 2328 2329 addVarArgChild(array); 2330 if (argumentCountIncludingThis >= 2) 2331 addVarArgChild(get(virtualRegisterForArgument(1, registerOffset))); // Start index. 2332 if (argumentCountIncludingThis >= 3) 2333 addVarArgChild(get(virtualRegisterForArgument(2, registerOffset))); // End index. 2334 addVarArgChild(addToGraph(GetButterfly, array)); 2335 2336 Node* arraySlice = addToGraph(Node::VarArg, ArraySlice, OpInfo(), OpInfo()); 2337 set(result, arraySlice); 2338 return true; 2339 } 2340 2341 return false; 2342 } 2343 default: 2344 return false; 2345 } 2346 2347 RELEASE_ASSERT_NOT_REACHED(); 2348 return false; 2349 } 2350 2351 case ArrayIndexOfIntrinsic: { 2352 if (argumentCountIncludingThis < 2) 2353 return false; 2354 2355 if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadIndexingType) 2356 || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadConstantCache) 2357 || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCache) 2358 || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadType)) 2359 return false; 2360 2361 ArrayMode arrayMode = getArrayMode(Array::Read); 2362 if (!arrayMode.isJSArray()) 2363 return false; 2364 2365 if (!arrayMode.isJSArrayWithOriginalStructure()) 2366 return false; 2367 2368 // We do not want to convert arrays into one type just to perform indexOf. 2369 if (arrayMode.doesConversion()) 2370 return false; 2371 2372 switch (arrayMode.type()) { 2373 case Array::Double: 2374 case Array::Int32: 2375 case Array::Contiguous: { 2376 JSGlobalObject* globalObject = m_graph.globalObjectFor(currentNodeOrigin().semantic); 2377 2378 Structure* arrayPrototypeStructure = globalObject->arrayPrototype()->structure(*m_vm); 2379 Structure* objectPrototypeStructure = globalObject->objectPrototype()->structure(*m_vm); 2380 2381 // FIXME: We could easily relax the Array/Object.prototype transition as long as we OSR exitted if we saw a hole. 2382 // https://bugs.webkit.org/show_bug.cgi?id=173171 2383 if (arrayPrototypeStructure->transitionWatchpointSetIsStillValid() 2384 && objectPrototypeStructure->transitionWatchpointSetIsStillValid() 2385 && globalObject->arrayPrototypeChainIsSane()) { 2386 2387 m_graph.registerAndWatchStructureTransition(arrayPrototypeStructure); 2388 m_graph.registerAndWatchStructureTransition(objectPrototypeStructure); 2389 2390 insertChecks(); 2391 2392 Node* array = get(virtualRegisterForArgument(0, registerOffset)); 2393 addVarArgChild(array); 2394 addVarArgChild(get(virtualRegisterForArgument(1, registerOffset))); // Search element. 2395 if (argumentCountIncludingThis >= 3) 2396 addVarArgChild(get(virtualRegisterForArgument(2, registerOffset))); // Start index. 2397 addVarArgChild(nullptr); 2398 2399 Node* node = addToGraph(Node::VarArg, ArrayIndexOf, OpInfo(arrayMode.asWord()), OpInfo()); 2400 set(result, node); 2401 return true; 2402 } 2403 2404 return false; 2405 } 2406 default: 2407 return false; 2408 } 2409 2410 RELEASE_ASSERT_NOT_REACHED(); 2411 return false; 2412 2413 } 2414 2415 case ArrayPopIntrinsic: { 2416 if (argumentCountIncludingThis != 1) 2417 return false; 2418 2419 ArrayMode arrayMode = getArrayMode(Array::Write); 2420 if (!arrayMode.isJSArray()) 2421 return false; 2422 switch (arrayMode.type()) { 2423 case Array::Int32: 2424 case Array::Double: 2425 case Array::Contiguous: 2426 case Array::ArrayStorage: { 2617 case RegExpTestIntrinsic: 2618 case RegExpTestFastIntrinsic: { 2619 if (argumentCountIncludingThis != 2) 2620 return false; 2621 2622 if (intrinsic == RegExpTestIntrinsic) { 2623 // Don't inline intrinsic if we exited due to one of the primordial RegExp checks failing. 2624 if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCell)) 2625 return false; 2626 2627 JSGlobalObject* globalObject = m_inlineStackTop->m_codeBlock->globalObject(); 2628 Structure* regExpStructure = globalObject->regExpStructure(); 2629 m_graph.registerStructure(regExpStructure); 2630 ASSERT(regExpStructure->storedPrototype().isObject()); 2631 ASSERT(regExpStructure->storedPrototype().asCell()->classInfo(*m_vm) == RegExpPrototype::info()); 2632 2633 FrozenValue* regExpPrototypeObjectValue = m_graph.freeze(regExpStructure->storedPrototype()); 2634 Structure* regExpPrototypeStructure = regExpPrototypeObjectValue->structure(); 2635 2636 auto isRegExpPropertySame = [&] (JSValue primordialProperty, UniquedStringImpl* propertyUID) { 2637 JSValue currentProperty; 2638 if (!m_graph.getRegExpPrototypeProperty(regExpStructure->storedPrototypeObject(), regExpPrototypeStructure, propertyUID, currentProperty)) 2639 return false; 2640 2641 return currentProperty == primordialProperty; 2642 }; 2643 2644 // Check that RegExp.exec is still the primordial RegExp.prototype.exec 2645 if (!isRegExpPropertySame(globalObject->regExpProtoExecFunction(), m_vm->propertyNames->exec.impl())) 2646 return false; 2647 2648 // Check that regExpObject is actually a RegExp object. 2649 Node* regExpObject = get(virtualRegisterForArgument(0, registerOffset)); 2650 addToGraph(Check, Edge(regExpObject, RegExpObjectUse)); 2651 2652 // Check that regExpObject's exec is actually the primodial RegExp.prototype.exec. 2653 UniquedStringImpl* execPropertyID = m_vm->propertyNames->exec.impl(); 2654 unsigned execIndex = m_graph.identifiers().ensure(execPropertyID); 2655 Node* actualProperty = addToGraph(TryGetById, OpInfo(execIndex), OpInfo(SpecFunction), Edge(regExpObject, CellUse)); 2656 FrozenValue* regExpPrototypeExec = m_graph.freeze(globalObject->regExpProtoExecFunction()); 2657 addToGraph(CheckCell, OpInfo(regExpPrototypeExec), Edge(actualProperty, CellUse)); 2658 } 2659 2427 2660 insertChecks(); 2428 Node* arrayPop = addToGraph(ArrayPop, OpInfo(arrayMode.asWord()), OpInfo(prediction), get(virtualRegisterForArgument(0, registerOffset))); 2429 set(result, arrayPop); 2661 Node* regExpObject = get(virtualRegisterForArgument(0, registerOffset)); 2662 Node* regExpExec = addToGraph(RegExpTest, OpInfo(0), OpInfo(prediction), addToGraph(GetGlobalObject, callee), regExpObject, get(virtualRegisterForArgument(1, registerOffset))); 2663 setResult(regExpExec); 2664 2430 2665 return true; 2431 2666 } 2432 2433 default: 2434 return false; 2435 } 2436 } 2437 2438 case AtomicsAddIntrinsic: 2439 case AtomicsAndIntrinsic: 2440 case AtomicsCompareExchangeIntrinsic: 2441 case AtomicsExchangeIntrinsic: 2442 case AtomicsIsLockFreeIntrinsic: 2443 case AtomicsLoadIntrinsic: 2444 case AtomicsOrIntrinsic: 2445 case AtomicsStoreIntrinsic: 2446 case AtomicsSubIntrinsic: 2447 case AtomicsXorIntrinsic: { 2448 if (!is64Bit()) 2449 return false; 2450 2451 NodeType op = LastNodeType; 2452 Array::Action action = Array::Write; 2453 unsigned numArgs = 0; // Number of actual args; we add one for the backing store pointer. 2454 switch (intrinsic) { 2455 case AtomicsAddIntrinsic: 2456 op = AtomicsAdd; 2457 numArgs = 3; 2458 break; 2459 case AtomicsAndIntrinsic: 2460 op = AtomicsAnd; 2461 numArgs = 3; 2462 break; 2463 case AtomicsCompareExchangeIntrinsic: 2464 op = AtomicsCompareExchange; 2465 numArgs = 4; 2466 break; 2467 case AtomicsExchangeIntrinsic: 2468 op = AtomicsExchange; 2469 numArgs = 3; 2470 break; 2471 case AtomicsIsLockFreeIntrinsic: 2472 // This gets no backing store, but we need no special logic for this since this also does 2473 // not need varargs. 2474 op = AtomicsIsLockFree; 2475 numArgs = 1; 2476 break; 2477 case AtomicsLoadIntrinsic: 2478 op = AtomicsLoad; 2479 numArgs = 2; 2480 action = Array::Read; 2481 break; 2482 case AtomicsOrIntrinsic: 2483 op = AtomicsOr; 2484 numArgs = 3; 2485 break; 2486 case AtomicsStoreIntrinsic: 2487 op = AtomicsStore; 2488 numArgs = 3; 2489 break; 2490 case AtomicsSubIntrinsic: 2491 op = AtomicsSub; 2492 numArgs = 3; 2493 break; 2494 case AtomicsXorIntrinsic: 2495 op = AtomicsXor; 2496 numArgs = 3; 2497 break; 2498 default: 2499 RELEASE_ASSERT_NOT_REACHED(); 2500 break; 2501 } 2502 2503 if (static_cast<unsigned>(argumentCountIncludingThis) < 1 + numArgs) 2504 return false; 2505 2506 insertChecks(); 2507 2508 Vector<Node*, 3> args; 2509 for (unsigned i = 0; i < numArgs; ++i) 2510 args.append(get(virtualRegisterForArgument(1 + i, registerOffset))); 2511 2512 Node* resultNode; 2513 if (numArgs + 1 <= 3) { 2514 while (args.size() < 3) 2515 args.append(nullptr); 2516 resultNode = addToGraph(op, OpInfo(ArrayMode(Array::SelectUsingPredictions, action).asWord()), OpInfo(prediction), args[0], args[1], args[2]); 2517 } else { 2518 for (Node* node : args) 2519 addVarArgChild(node); 2520 addVarArgChild(nullptr); 2521 resultNode = addToGraph(Node::VarArg, op, OpInfo(ArrayMode(Array::SelectUsingPredictions, action).asWord()), OpInfo(prediction)); 2522 } 2523 2524 set(result, resultNode); 2525 return true; 2526 } 2527 2528 case ParseIntIntrinsic: { 2529 if (argumentCountIncludingThis < 2) 2530 return false; 2531 2532 if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCell) || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadType)) 2533 return false; 2534 2535 insertChecks(); 2536 VirtualRegister valueOperand = virtualRegisterForArgument(1, registerOffset); 2537 Node* parseInt; 2538 if (argumentCountIncludingThis == 2) 2539 parseInt = addToGraph(ParseInt, OpInfo(), OpInfo(prediction), get(valueOperand)); 2540 else { 2541 ASSERT(argumentCountIncludingThis > 2); 2542 VirtualRegister radixOperand = virtualRegisterForArgument(2, registerOffset); 2543 parseInt = addToGraph(ParseInt, OpInfo(), OpInfo(prediction), get(valueOperand), get(radixOperand)); 2544 } 2545 set(result, parseInt); 2546 return true; 2547 } 2548 2549 case CharCodeAtIntrinsic: { 2550 if (argumentCountIncludingThis != 2) 2551 return false; 2552 2553 insertChecks(); 2554 VirtualRegister thisOperand = virtualRegisterForArgument(0, registerOffset); 2555 VirtualRegister indexOperand = virtualRegisterForArgument(1, registerOffset); 2556 Node* charCode = addToGraph(StringCharCodeAt, OpInfo(ArrayMode(Array::String, Array::Read).asWord()), get(thisOperand), get(indexOperand)); 2557 2558 set(result, charCode); 2559 return true; 2560 } 2561 2562 case CharAtIntrinsic: { 2563 if (argumentCountIncludingThis != 2) 2564 return false; 2565 2566 insertChecks(); 2567 VirtualRegister thisOperand = virtualRegisterForArgument(0, registerOffset); 2568 VirtualRegister indexOperand = virtualRegisterForArgument(1, registerOffset); 2569 Node* charCode = addToGraph(StringCharAt, OpInfo(ArrayMode(Array::String, Array::Read).asWord()), get(thisOperand), get(indexOperand)); 2570 2571 set(result, charCode); 2572 return true; 2573 } 2574 case Clz32Intrinsic: { 2575 insertChecks(); 2576 if (argumentCountIncludingThis == 1) 2577 set(result, addToGraph(JSConstant, OpInfo(m_graph.freeze(jsNumber(32))))); 2578 else { 2579 Node* operand = get(virtualRegisterForArgument(1, registerOffset)); 2580 set(result, addToGraph(ArithClz32, operand)); 2581 } 2582 return true; 2583 } 2584 case FromCharCodeIntrinsic: { 2585 if (argumentCountIncludingThis != 2) 2586 return false; 2587 2588 insertChecks(); 2589 VirtualRegister indexOperand = virtualRegisterForArgument(1, registerOffset); 2590 Node* charCode = addToGraph(StringFromCharCode, get(indexOperand)); 2591 2592 set(result, charCode); 2593 2594 return true; 2595 } 2596 2597 case RegExpExecIntrinsic: { 2598 if (argumentCountIncludingThis != 2) 2599 return false; 2600 2601 insertChecks(); 2602 Node* regExpExec = addToGraph(RegExpExec, OpInfo(0), OpInfo(prediction), addToGraph(GetGlobalObject, callee), get(virtualRegisterForArgument(0, registerOffset)), get(virtualRegisterForArgument(1, registerOffset))); 2603 set(result, regExpExec); 2604 2605 return true; 2606 } 2607 2608 case RegExpTestIntrinsic: 2609 case RegExpTestFastIntrinsic: { 2610 if (argumentCountIncludingThis != 2) 2611 return false; 2612 2613 if (intrinsic == RegExpTestIntrinsic) { 2667 2668 case RegExpMatchFastIntrinsic: { 2669 RELEASE_ASSERT(argumentCountIncludingThis == 2); 2670 2671 insertChecks(); 2672 Node* regExpMatch = addToGraph(RegExpMatchFast, OpInfo(0), OpInfo(prediction), addToGraph(GetGlobalObject, callee), get(virtualRegisterForArgument(0, registerOffset)), get(virtualRegisterForArgument(1, registerOffset))); 2673 setResult(regExpMatch); 2674 return true; 2675 } 2676 2677 case ObjectCreateIntrinsic: { 2678 if (argumentCountIncludingThis != 2) 2679 return false; 2680 2681 insertChecks(); 2682 setResult(addToGraph(ObjectCreate, get(virtualRegisterForArgument(1, registerOffset)))); 2683 return true; 2684 } 2685 2686 case ObjectGetPrototypeOfIntrinsic: { 2687 if (argumentCountIncludingThis != 2) 2688 return false; 2689 2690 insertChecks(); 2691 setResult(addToGraph(GetPrototypeOf, OpInfo(0), OpInfo(prediction), get(virtualRegisterForArgument(1, registerOffset)))); 2692 return true; 2693 } 2694 2695 case ObjectIsIntrinsic: { 2696 if (argumentCountIncludingThis < 3) 2697 return false; 2698 2699 insertChecks(); 2700 setResult(addToGraph(SameValue, get(virtualRegisterForArgument(1, registerOffset)), get(virtualRegisterForArgument(2, registerOffset)))); 2701 return true; 2702 } 2703 2704 case ObjectKeysIntrinsic: { 2705 if (argumentCountIncludingThis < 2) 2706 return false; 2707 2708 insertChecks(); 2709 setResult(addToGraph(ObjectKeys, get(virtualRegisterForArgument(1, registerOffset)))); 2710 return true; 2711 } 2712 2713 case ObjectPrototypeToStringIntrinsic: { 2714 insertChecks(); 2715 Node* value = get(virtualRegisterForArgument(0, registerOffset)); 2716 setResult(addToGraph(ObjectToString, value)); 2717 return true; 2718 } 2719 2720 case ReflectGetPrototypeOfIntrinsic: { 2721 if (argumentCountIncludingThis != 2) 2722 return false; 2723 2724 insertChecks(); 2725 setResult(addToGraph(GetPrototypeOf, OpInfo(0), OpInfo(prediction), Edge(get(virtualRegisterForArgument(1, registerOffset)), ObjectUse))); 2726 return true; 2727 } 2728 2729 case IsTypedArrayViewIntrinsic: { 2730 ASSERT(argumentCountIncludingThis == 2); 2731 2732 insertChecks(); 2733 setResult(addToGraph(IsTypedArrayView, OpInfo(prediction), get(virtualRegisterForArgument(1, registerOffset)))); 2734 return true; 2735 } 2736 2737 case StringPrototypeValueOfIntrinsic: { 2738 insertChecks(); 2739 Node* value = get(virtualRegisterForArgument(0, registerOffset)); 2740 setResult(addToGraph(StringValueOf, value)); 2741 return true; 2742 } 2743 2744 case StringPrototypeReplaceIntrinsic: { 2745 if (argumentCountIncludingThis != 3) 2746 return false; 2747 2748 // Don't inline intrinsic if we exited due to "search" not being a RegExp or String object. 2749 if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadType)) 2750 return false; 2751 2614 2752 // Don't inline intrinsic if we exited due to one of the primordial RegExp checks failing. 2615 2753 if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCell)) … … 2629 2767 if (!m_graph.getRegExpPrototypeProperty(regExpStructure->storedPrototypeObject(), regExpPrototypeStructure, propertyUID, currentProperty)) 2630 2768 return false; 2631 2769 2632 2770 return currentProperty == primordialProperty; 2633 2771 }; 2634 2772 2635 // Check that RegExp.exec is still the primordial RegExp.prototype.exec2773 // Check that searchRegExp.exec is still the primordial RegExp.prototype.exec 2636 2774 if (!isRegExpPropertySame(globalObject->regExpProtoExecFunction(), m_vm->propertyNames->exec.impl())) 2637 2775 return false; 2638 2776 2639 // Check that regExpObject is actually a RegExp object. 2640 Node* regExpObject = get(virtualRegisterForArgument(0, registerOffset)); 2641 addToGraph(Check, Edge(regExpObject, RegExpObjectUse)); 2642 2643 // Check that regExpObject's exec is actually the primodial RegExp.prototype.exec. 2644 UniquedStringImpl* execPropertyID = m_vm->propertyNames->exec.impl(); 2645 unsigned execIndex = m_graph.identifiers().ensure(execPropertyID); 2646 Node* actualProperty = addToGraph(TryGetById, OpInfo(execIndex), OpInfo(SpecFunction), Edge(regExpObject, CellUse)); 2647 FrozenValue* regExpPrototypeExec = m_graph.freeze(globalObject->regExpProtoExecFunction()); 2648 addToGraph(CheckCell, OpInfo(regExpPrototypeExec), Edge(actualProperty, CellUse)); 2649 } 2650 2651 insertChecks(); 2652 Node* regExpObject = get(virtualRegisterForArgument(0, registerOffset)); 2653 Node* regExpExec = addToGraph(RegExpTest, OpInfo(0), OpInfo(prediction), addToGraph(GetGlobalObject, callee), regExpObject, get(virtualRegisterForArgument(1, registerOffset))); 2654 set(result, regExpExec); 2655 2777 // Check that searchRegExp.global is still the primordial RegExp.prototype.global 2778 if (!isRegExpPropertySame(globalObject->regExpProtoGlobalGetter(), m_vm->propertyNames->global.impl())) 2779 return false; 2780 2781 // Check that searchRegExp.unicode is still the primordial RegExp.prototype.unicode 2782 if (!isRegExpPropertySame(globalObject->regExpProtoUnicodeGetter(), m_vm->propertyNames->unicode.impl())) 2783 return false; 2784 2785 // Check that searchRegExp[Symbol.match] is still the primordial RegExp.prototype[Symbol.replace] 2786 if (!isRegExpPropertySame(globalObject->regExpProtoSymbolReplaceFunction(), m_vm->propertyNames->replaceSymbol.impl())) 2787 return false; 2788 2789 insertChecks(); 2790 2791 Node* resultNode = addToGraph(StringReplace, OpInfo(0), OpInfo(prediction), get(virtualRegisterForArgument(0, registerOffset)), get(virtualRegisterForArgument(1, registerOffset)), get(virtualRegisterForArgument(2, registerOffset))); 2792 setResult(resultNode); 2793 return true; 2794 } 2795 2796 case StringPrototypeReplaceRegExpIntrinsic: { 2797 if (argumentCountIncludingThis != 3) 2798 return false; 2799 2800 insertChecks(); 2801 Node* resultNode = addToGraph(StringReplaceRegExp, OpInfo(0), OpInfo(prediction), get(virtualRegisterForArgument(0, registerOffset)), get(virtualRegisterForArgument(1, registerOffset)), get(virtualRegisterForArgument(2, registerOffset))); 2802 setResult(resultNode); 2803 return true; 2804 } 2805 2806 case RoundIntrinsic: 2807 case FloorIntrinsic: 2808 case CeilIntrinsic: 2809 case TruncIntrinsic: { 2810 if (argumentCountIncludingThis == 1) { 2811 insertChecks(); 2812 setResult(addToGraph(JSConstant, OpInfo(m_constantNaN))); 2813 return true; 2814 } 2815 insertChecks(); 2816 Node* operand = get(virtualRegisterForArgument(1, registerOffset)); 2817 NodeType op; 2818 if (intrinsic == RoundIntrinsic) 2819 op = ArithRound; 2820 else if (intrinsic == FloorIntrinsic) 2821 op = ArithFloor; 2822 else if (intrinsic == CeilIntrinsic) 2823 op = ArithCeil; 2824 else { 2825 ASSERT(intrinsic == TruncIntrinsic); 2826 op = ArithTrunc; 2827 } 2828 Node* roundNode = addToGraph(op, OpInfo(0), OpInfo(prediction), operand); 2829 setResult(roundNode); 2830 return true; 2831 } 2832 case IMulIntrinsic: { 2833 if (argumentCountIncludingThis != 3) 2834 return false; 2835 insertChecks(); 2836 VirtualRegister leftOperand = virtualRegisterForArgument(1, registerOffset); 2837 VirtualRegister rightOperand = virtualRegisterForArgument(2, registerOffset); 2838 Node* left = get(leftOperand); 2839 Node* right = get(rightOperand); 2840 setResult(addToGraph(ArithIMul, left, right)); 2841 return true; 2842 } 2843 2844 case RandomIntrinsic: { 2845 if (argumentCountIncludingThis != 1) 2846 return false; 2847 insertChecks(); 2848 setResult(addToGraph(ArithRandom)); 2849 return true; 2850 } 2851 2852 case DFGTrueIntrinsic: { 2853 insertChecks(); 2854 setResult(jsConstant(jsBoolean(true))); 2855 return true; 2856 } 2857 2858 case FTLTrueIntrinsic: { 2859 insertChecks(); 2860 setResult(jsConstant(jsBoolean(m_graph.m_plan.isFTL()))); 2861 return true; 2862 } 2863 2864 case OSRExitIntrinsic: { 2865 insertChecks(); 2866 addToGraph(ForceOSRExit); 2867 setResult(addToGraph(JSConstant, OpInfo(m_constantUndefined))); 2868 return true; 2869 } 2870 2871 case IsFinalTierIntrinsic: { 2872 insertChecks(); 2873 setResult(jsConstant(jsBoolean(Options::useFTLJIT() ? m_graph.m_plan.isFTL() : true))); 2874 return true; 2875 } 2876 2877 case SetInt32HeapPredictionIntrinsic: { 2878 insertChecks(); 2879 for (int i = 1; i < argumentCountIncludingThis; ++i) { 2880 Node* node = get(virtualRegisterForArgument(i, registerOffset)); 2881 if (node->hasHeapPrediction()) 2882 node->setHeapPrediction(SpecInt32Only); 2883 } 2884 setResult(addToGraph(JSConstant, OpInfo(m_constantUndefined))); 2885 return true; 2886 } 2887 2888 case CheckInt32Intrinsic: { 2889 insertChecks(); 2890 for (int i = 1; i < argumentCountIncludingThis; ++i) { 2891 Node* node = get(virtualRegisterForArgument(i, registerOffset)); 2892 addToGraph(Phantom, Edge(node, Int32Use)); 2893 } 2894 setResult(jsConstant(jsBoolean(true))); 2895 return true; 2896 } 2897 2898 case FiatInt52Intrinsic: { 2899 if (argumentCountIncludingThis != 2) 2900 return false; 2901 insertChecks(); 2902 VirtualRegister operand = virtualRegisterForArgument(1, registerOffset); 2903 if (enableInt52()) 2904 setResult(addToGraph(FiatInt52, get(operand))); 2905 else 2906 setResult(get(operand)); 2907 return true; 2908 } 2909 2910 case JSMapGetIntrinsic: { 2911 if (argumentCountIncludingThis != 2) 2912 return false; 2913 2914 insertChecks(); 2915 Node* map = get(virtualRegisterForArgument(0, registerOffset)); 2916 Node* key = get(virtualRegisterForArgument(1, registerOffset)); 2917 Node* normalizedKey = addToGraph(NormalizeMapKey, key); 2918 Node* hash = addToGraph(MapHash, normalizedKey); 2919 Node* bucket = addToGraph(GetMapBucket, Edge(map, MapObjectUse), Edge(normalizedKey), Edge(hash)); 2920 Node* resultNode = addToGraph(LoadValueFromMapBucket, OpInfo(BucketOwnerType::Map), OpInfo(prediction), bucket); 2921 setResult(resultNode); 2922 return true; 2923 } 2924 2925 case JSSetHasIntrinsic: 2926 case JSMapHasIntrinsic: { 2927 if (argumentCountIncludingThis != 2) 2928 return false; 2929 2930 insertChecks(); 2931 Node* mapOrSet = get(virtualRegisterForArgument(0, registerOffset)); 2932 Node* key = get(virtualRegisterForArgument(1, registerOffset)); 2933 Node* normalizedKey = addToGraph(NormalizeMapKey, key); 2934 Node* hash = addToGraph(MapHash, normalizedKey); 2935 UseKind useKind = intrinsic == JSSetHasIntrinsic ? SetObjectUse : MapObjectUse; 2936 Node* bucket = addToGraph(GetMapBucket, OpInfo(0), Edge(mapOrSet, useKind), Edge(normalizedKey), Edge(hash)); 2937 JSCell* sentinel = nullptr; 2938 if (intrinsic == JSMapHasIntrinsic) 2939 sentinel = m_vm->sentinelMapBucket.get(); 2940 else 2941 sentinel = m_vm->sentinelSetBucket.get(); 2942 2943 FrozenValue* frozenPointer = m_graph.freeze(sentinel); 2944 Node* invertedResult = addToGraph(CompareEqPtr, OpInfo(frozenPointer), bucket); 2945 Node* resultNode = addToGraph(LogicalNot, invertedResult); 2946 setResult(resultNode); 2947 return true; 2948 } 2949 2950 case JSSetAddIntrinsic: { 2951 if (argumentCountIncludingThis != 2) 2952 return false; 2953 2954 insertChecks(); 2955 Node* base = get(virtualRegisterForArgument(0, registerOffset)); 2956 Node* key = get(virtualRegisterForArgument(1, registerOffset)); 2957 Node* normalizedKey = addToGraph(NormalizeMapKey, key); 2958 Node* hash = addToGraph(MapHash, normalizedKey); 2959 addToGraph(SetAdd, base, normalizedKey, hash); 2960 setResult(base); 2961 return true; 2962 } 2963 2964 case JSMapSetIntrinsic: { 2965 if (argumentCountIncludingThis != 3) 2966 return false; 2967 2968 insertChecks(); 2969 Node* base = get(virtualRegisterForArgument(0, registerOffset)); 2970 Node* key = get(virtualRegisterForArgument(1, registerOffset)); 2971 Node* value = get(virtualRegisterForArgument(2, registerOffset)); 2972 2973 Node* normalizedKey = addToGraph(NormalizeMapKey, key); 2974 Node* hash = addToGraph(MapHash, normalizedKey); 2975 2976 addVarArgChild(base); 2977 addVarArgChild(normalizedKey); 2978 addVarArgChild(value); 2979 addVarArgChild(hash); 2980 addToGraph(Node::VarArg, MapSet, OpInfo(0), OpInfo(0)); 2981 setResult(base); 2982 return true; 2983 } 2984 2985 case JSSetBucketHeadIntrinsic: 2986 case JSMapBucketHeadIntrinsic: { 2987 ASSERT(argumentCountIncludingThis == 2); 2988 2989 insertChecks(); 2990 Node* map = get(virtualRegisterForArgument(1, registerOffset)); 2991 UseKind useKind = intrinsic == JSSetBucketHeadIntrinsic ? SetObjectUse : MapObjectUse; 2992 Node* resultNode = addToGraph(GetMapBucketHead, Edge(map, useKind)); 2993 setResult(resultNode); 2994 return true; 2995 } 2996 2997 case JSSetBucketNextIntrinsic: 2998 case JSMapBucketNextIntrinsic: { 2999 ASSERT(argumentCountIncludingThis == 2); 3000 3001 insertChecks(); 3002 Node* bucket = get(virtualRegisterForArgument(1, registerOffset)); 3003 BucketOwnerType type = intrinsic == JSSetBucketNextIntrinsic ? BucketOwnerType::Set : BucketOwnerType::Map; 3004 Node* resultNode = addToGraph(GetMapBucketNext, OpInfo(type), bucket); 3005 setResult(resultNode); 3006 return true; 3007 } 3008 3009 case JSSetBucketKeyIntrinsic: 3010 case JSMapBucketKeyIntrinsic: { 3011 ASSERT(argumentCountIncludingThis == 2); 3012 3013 insertChecks(); 3014 Node* bucket = get(virtualRegisterForArgument(1, registerOffset)); 3015 BucketOwnerType type = intrinsic == JSSetBucketKeyIntrinsic ? BucketOwnerType::Set : BucketOwnerType::Map; 3016 Node* resultNode = addToGraph(LoadKeyFromMapBucket, OpInfo(type), OpInfo(prediction), bucket); 3017 setResult(resultNode); 3018 return true; 3019 } 3020 3021 case JSMapBucketValueIntrinsic: { 3022 ASSERT(argumentCountIncludingThis == 2); 3023 3024 insertChecks(); 3025 Node* bucket = get(virtualRegisterForArgument(1, registerOffset)); 3026 Node* resultNode = addToGraph(LoadValueFromMapBucket, OpInfo(BucketOwnerType::Map), OpInfo(prediction), bucket); 3027 setResult(resultNode); 3028 return true; 3029 } 3030 3031 case JSWeakMapGetIntrinsic: { 3032 if (argumentCountIncludingThis != 2) 3033 return false; 3034 3035 if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadType)) 3036 return false; 3037 3038 insertChecks(); 3039 Node* map = get(virtualRegisterForArgument(0, registerOffset)); 3040 Node* key = get(virtualRegisterForArgument(1, registerOffset)); 3041 addToGraph(Check, Edge(key, ObjectUse)); 3042 Node* hash = addToGraph(MapHash, key); 3043 Node* holder = addToGraph(WeakMapGet, Edge(map, WeakMapObjectUse), Edge(key, ObjectUse), Edge(hash, Int32Use)); 3044 Node* resultNode = addToGraph(ExtractValueFromWeakMapGet, OpInfo(), OpInfo(prediction), holder); 3045 3046 setResult(resultNode); 3047 return true; 3048 } 3049 3050 case JSWeakMapHasIntrinsic: { 3051 if (argumentCountIncludingThis != 2) 3052 return false; 3053 3054 if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadType)) 3055 return false; 3056 3057 insertChecks(); 3058 Node* map = get(virtualRegisterForArgument(0, registerOffset)); 3059 Node* key = get(virtualRegisterForArgument(1, registerOffset)); 3060 addToGraph(Check, Edge(key, ObjectUse)); 3061 Node* hash = addToGraph(MapHash, key); 3062 Node* holder = addToGraph(WeakMapGet, Edge(map, WeakMapObjectUse), Edge(key, ObjectUse), Edge(hash, Int32Use)); 3063 Node* invertedResult = addToGraph(IsEmpty, holder); 3064 Node* resultNode = addToGraph(LogicalNot, invertedResult); 3065 3066 setResult(resultNode); 3067 return true; 3068 } 3069 3070 case JSWeakSetHasIntrinsic: { 3071 if (argumentCountIncludingThis != 2) 3072 return false; 3073 3074 if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadType)) 3075 return false; 3076 3077 insertChecks(); 3078 Node* map = get(virtualRegisterForArgument(0, registerOffset)); 3079 Node* key = get(virtualRegisterForArgument(1, registerOffset)); 3080 addToGraph(Check, Edge(key, ObjectUse)); 3081 Node* hash = addToGraph(MapHash, key); 3082 Node* holder = addToGraph(WeakMapGet, Edge(map, WeakSetObjectUse), Edge(key, ObjectUse), Edge(hash, Int32Use)); 3083 Node* invertedResult = addToGraph(IsEmpty, holder); 3084 Node* resultNode = addToGraph(LogicalNot, invertedResult); 3085 3086 setResult(resultNode); 3087 return true; 3088 } 3089 3090 case JSWeakSetAddIntrinsic: { 3091 if (argumentCountIncludingThis != 2) 3092 return false; 3093 3094 if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadType)) 3095 return false; 3096 3097 insertChecks(); 3098 Node* base = get(virtualRegisterForArgument(0, registerOffset)); 3099 Node* key = get(virtualRegisterForArgument(1, registerOffset)); 3100 addToGraph(Check, Edge(key, ObjectUse)); 3101 Node* hash = addToGraph(MapHash, key); 3102 addToGraph(WeakSetAdd, Edge(base, WeakSetObjectUse), Edge(key, ObjectUse), Edge(hash, Int32Use)); 3103 setResult(base); 3104 return true; 3105 } 3106 3107 case JSWeakMapSetIntrinsic: { 3108 if (argumentCountIncludingThis != 3) 3109 return false; 3110 3111 if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadType)) 3112 return false; 3113 3114 insertChecks(); 3115 Node* base = get(virtualRegisterForArgument(0, registerOffset)); 3116 Node* key = get(virtualRegisterForArgument(1, registerOffset)); 3117 Node* value = get(virtualRegisterForArgument(2, registerOffset)); 3118 3119 addToGraph(Check, Edge(key, ObjectUse)); 3120 Node* hash = addToGraph(MapHash, key); 3121 3122 addVarArgChild(Edge(base, WeakMapObjectUse)); 3123 addVarArgChild(Edge(key, ObjectUse)); 3124 addVarArgChild(Edge(value)); 3125 addVarArgChild(Edge(hash, Int32Use)); 3126 addToGraph(Node::VarArg, WeakMapSet, OpInfo(0), OpInfo(0)); 3127 setResult(base); 3128 return true; 3129 } 3130 3131 case DataViewGetInt8: 3132 case DataViewGetUint8: 3133 case DataViewGetInt16: 3134 case DataViewGetUint16: 3135 case DataViewGetInt32: 3136 case DataViewGetUint32: 3137 case DataViewGetFloat32: 3138 case DataViewGetFloat64: { 3139 if (!is64Bit()) 3140 return false; 3141 3142 // To inline data view accesses, we assume the architecture we're running on: 3143 // - Is little endian. 3144 // - Allows unaligned loads/stores without crashing. 3145 3146 if (argumentCountIncludingThis < 2) 3147 return false; 3148 if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadType)) 3149 return false; 3150 3151 insertChecks(); 3152 3153 uint8_t byteSize; 3154 NodeType op = DataViewGetInt; 3155 bool isSigned = false; 3156 switch (intrinsic) { 3157 case DataViewGetInt8: 3158 isSigned = true; 3159 FALLTHROUGH; 3160 case DataViewGetUint8: 3161 byteSize = 1; 3162 break; 3163 3164 case DataViewGetInt16: 3165 isSigned = true; 3166 FALLTHROUGH; 3167 case DataViewGetUint16: 3168 byteSize = 2; 3169 break; 3170 3171 case DataViewGetInt32: 3172 isSigned = true; 3173 FALLTHROUGH; 3174 case DataViewGetUint32: 3175 byteSize = 4; 3176 break; 3177 3178 case DataViewGetFloat32: 3179 byteSize = 4; 3180 op = DataViewGetFloat; 3181 break; 3182 case DataViewGetFloat64: 3183 byteSize = 8; 3184 op = DataViewGetFloat; 3185 break; 3186 default: 3187 RELEASE_ASSERT_NOT_REACHED(); 3188 } 3189 3190 TriState isLittleEndian = MixedTriState; 3191 Node* littleEndianChild = nullptr; 3192 if (byteSize > 1) { 3193 if (argumentCountIncludingThis < 3) 3194 isLittleEndian = FalseTriState; 3195 else { 3196 littleEndianChild = get(virtualRegisterForArgument(2, registerOffset)); 3197 if (littleEndianChild->hasConstant()) { 3198 JSValue constant = littleEndianChild->constant()->value(); 3199 isLittleEndian = constant.pureToBoolean(); 3200 if (isLittleEndian != MixedTriState) 3201 littleEndianChild = nullptr; 3202 } else 3203 isLittleEndian = MixedTriState; 3204 } 3205 } 3206 3207 DataViewData data { }; 3208 data.isLittleEndian = isLittleEndian; 3209 data.isSigned = isSigned; 3210 data.byteSize = byteSize; 3211 3212 setResult( 3213 addToGraph(op, OpInfo(data.asQuadWord), OpInfo(prediction), get(virtualRegisterForArgument(0, registerOffset)), get(virtualRegisterForArgument(1, registerOffset)), littleEndianChild)); 3214 return true; 3215 } 3216 3217 case DataViewSetInt8: 3218 case DataViewSetUint8: 3219 case DataViewSetInt16: 3220 case DataViewSetUint16: 3221 case DataViewSetInt32: 3222 case DataViewSetUint32: 3223 case DataViewSetFloat32: 3224 case DataViewSetFloat64: { 3225 if (!is64Bit()) 3226 return false; 3227 3228 if (argumentCountIncludingThis < 3) 3229 return false; 3230 3231 if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadType)) 3232 return false; 3233 3234 insertChecks(); 3235 3236 uint8_t byteSize; 3237 bool isFloatingPoint = false; 3238 bool isSigned = false; 3239 switch (intrinsic) { 3240 case DataViewSetInt8: 3241 isSigned = true; 3242 FALLTHROUGH; 3243 case DataViewSetUint8: 3244 byteSize = 1; 3245 break; 3246 3247 case DataViewSetInt16: 3248 isSigned = true; 3249 FALLTHROUGH; 3250 case DataViewSetUint16: 3251 byteSize = 2; 3252 break; 3253 3254 case DataViewSetInt32: 3255 isSigned = true; 3256 FALLTHROUGH; 3257 case DataViewSetUint32: 3258 byteSize = 4; 3259 break; 3260 3261 case DataViewSetFloat32: 3262 isFloatingPoint = true; 3263 byteSize = 4; 3264 break; 3265 case DataViewSetFloat64: 3266 isFloatingPoint = true; 3267 byteSize = 8; 3268 break; 3269 default: 3270 RELEASE_ASSERT_NOT_REACHED(); 3271 } 3272 3273 TriState isLittleEndian = MixedTriState; 3274 Node* littleEndianChild = nullptr; 3275 if (byteSize > 1) { 3276 if (argumentCountIncludingThis < 4) 3277 isLittleEndian = FalseTriState; 3278 else { 3279 littleEndianChild = get(virtualRegisterForArgument(3, registerOffset)); 3280 if (littleEndianChild->hasConstant()) { 3281 JSValue constant = littleEndianChild->constant()->value(); 3282 isLittleEndian = constant.pureToBoolean(); 3283 if (isLittleEndian != MixedTriState) 3284 littleEndianChild = nullptr; 3285 } else 3286 isLittleEndian = MixedTriState; 3287 } 3288 } 3289 3290 DataViewData data { }; 3291 data.isLittleEndian = isLittleEndian; 3292 data.isSigned = isSigned; 3293 data.byteSize = byteSize; 3294 data.isFloatingPoint = isFloatingPoint; 3295 3296 addVarArgChild(get(virtualRegisterForArgument(0, registerOffset))); 3297 addVarArgChild(get(virtualRegisterForArgument(1, registerOffset))); 3298 addVarArgChild(get(virtualRegisterForArgument(2, registerOffset))); 3299 addVarArgChild(littleEndianChild); 3300 3301 addToGraph(Node::VarArg, DataViewSet, OpInfo(data.asQuadWord), OpInfo()); 3302 setResult(addToGraph(JSConstant, OpInfo(m_constantUndefined))); 3303 return true; 3304 } 3305 3306 case HasOwnPropertyIntrinsic: { 3307 if (argumentCountIncludingThis != 2) 3308 return false; 3309 3310 // This can be racy, that's fine. We know that once we observe that this is created, 3311 // that it will never be destroyed until the VM is destroyed. It's unlikely that 3312 // we'd ever get to the point where we inline this as an intrinsic without the 3313 // cache being created, however, it's possible if we always throw exceptions inside 3314 // hasOwnProperty. 3315 if (!m_vm->hasOwnPropertyCache()) 3316 return false; 3317 3318 insertChecks(); 3319 Node* object = get(virtualRegisterForArgument(0, registerOffset)); 3320 Node* key = get(virtualRegisterForArgument(1, registerOffset)); 3321 Node* resultNode = addToGraph(HasOwnProperty, object, key); 3322 setResult(resultNode); 3323 return true; 3324 } 3325 3326 case StringPrototypeSliceIntrinsic: { 3327 if (argumentCountIncludingThis < 2) 3328 return false; 3329 3330 if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadType)) 3331 return false; 3332 3333 insertChecks(); 3334 Node* thisString = get(virtualRegisterForArgument(0, registerOffset)); 3335 Node* start = get(virtualRegisterForArgument(1, registerOffset)); 3336 Node* end = nullptr; 3337 if (argumentCountIncludingThis > 2) 3338 end = get(virtualRegisterForArgument(2, registerOffset)); 3339 Node* resultNode = addToGraph(StringSlice, thisString, start, end); 3340 setResult(resultNode); 3341 return true; 3342 } 3343 3344 case StringPrototypeToLowerCaseIntrinsic: { 3345 if (argumentCountIncludingThis != 1) 3346 return false; 3347 3348 if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadType)) 3349 return false; 3350 3351 insertChecks(); 3352 Node* thisString = get(virtualRegisterForArgument(0, registerOffset)); 3353 Node* resultNode = addToGraph(ToLowerCase, thisString); 3354 setResult(resultNode); 3355 return true; 3356 } 3357 3358 case NumberPrototypeToStringIntrinsic: { 3359 if (argumentCountIncludingThis != 1 && argumentCountIncludingThis != 2) 3360 return false; 3361 3362 if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadType)) 3363 return false; 3364 3365 insertChecks(); 3366 Node* thisNumber = get(virtualRegisterForArgument(0, registerOffset)); 3367 if (argumentCountIncludingThis == 1) { 3368 Node* resultNode = addToGraph(ToString, thisNumber); 3369 setResult(resultNode); 3370 } else { 3371 Node* radix = get(virtualRegisterForArgument(1, registerOffset)); 3372 Node* resultNode = addToGraph(NumberToStringWithRadix, thisNumber, radix); 3373 setResult(resultNode); 3374 } 3375 return true; 3376 } 3377 3378 case NumberIsIntegerIntrinsic: { 3379 if (argumentCountIncludingThis < 2) 3380 return false; 3381 3382 insertChecks(); 3383 Node* input = get(virtualRegisterForArgument(1, registerOffset)); 3384 Node* resultNode = addToGraph(NumberIsInteger, input); 3385 setResult(resultNode); 3386 return true; 3387 } 3388 3389 case CPUMfenceIntrinsic: 3390 case CPURdtscIntrinsic: 3391 case CPUCpuidIntrinsic: 3392 case CPUPauseIntrinsic: { 3393 #if CPU(X86_64) 3394 if (!m_graph.m_plan.isFTL()) 3395 return false; 3396 insertChecks(); 3397 setResult(addToGraph(CPUIntrinsic, OpInfo(intrinsic), OpInfo())); 3398 return true; 3399 #else 3400 return false; 3401 #endif 3402 } 3403 3404 default: 3405 return false; 3406 } 3407 }; 3408 3409 if (inlineIntrinsic()) { 3410 RELEASE_ASSERT(didSetResult); 2656 3411 return true; 2657 3412 } 2658 3413 2659 case RegExpMatchFastIntrinsic: { 2660 RELEASE_ASSERT(argumentCountIncludingThis == 2); 2661 2662 insertChecks(); 2663 Node* regExpMatch = addToGraph(RegExpMatchFast, OpInfo(0), OpInfo(prediction), addToGraph(GetGlobalObject, callee), get(virtualRegisterForArgument(0, registerOffset)), get(virtualRegisterForArgument(1, registerOffset))); 2664 set(result, regExpMatch); 2665 return true; 2666 } 2667 2668 case ObjectCreateIntrinsic: { 2669 if (argumentCountIncludingThis != 2) 2670 return false; 2671 2672 insertChecks(); 2673 set(result, addToGraph(ObjectCreate, get(virtualRegisterForArgument(1, registerOffset)))); 2674 return true; 2675 } 2676 2677 case ObjectGetPrototypeOfIntrinsic: { 2678 if (argumentCountIncludingThis != 2) 2679 return false; 2680 2681 insertChecks(); 2682 set(result, addToGraph(GetPrototypeOf, OpInfo(0), OpInfo(prediction), get(virtualRegisterForArgument(1, registerOffset)))); 2683 return true; 2684 } 2685 2686 case ObjectIsIntrinsic: { 2687 if (argumentCountIncludingThis < 3) 2688 return false; 2689 2690 insertChecks(); 2691 set(result, addToGraph(SameValue, get(virtualRegisterForArgument(1, registerOffset)), get(virtualRegisterForArgument(2, registerOffset)))); 2692 return true; 2693 } 2694 2695 case ObjectKeysIntrinsic: { 2696 if (argumentCountIncludingThis < 2) 2697 return false; 2698 2699 insertChecks(); 2700 set(result, addToGraph(ObjectKeys, get(virtualRegisterForArgument(1, registerOffset)))); 2701 return true; 2702 } 2703 2704 case ObjectPrototypeToStringIntrinsic: { 2705 insertChecks(); 2706 Node* value = get(virtualRegisterForArgument(0, registerOffset)); 2707 set(result, addToGraph(ObjectToString, value)); 2708 return true; 2709 } 2710 2711 case ReflectGetPrototypeOfIntrinsic: { 2712 if (argumentCountIncludingThis != 2) 2713 return false; 2714 2715 insertChecks(); 2716 set(result, addToGraph(GetPrototypeOf, OpInfo(0), OpInfo(prediction), Edge(get(virtualRegisterForArgument(1, registerOffset)), ObjectUse))); 2717 return true; 2718 } 2719 2720 case IsTypedArrayViewIntrinsic: { 2721 ASSERT(argumentCountIncludingThis == 2); 2722 2723 insertChecks(); 2724 set(result, addToGraph(IsTypedArrayView, OpInfo(prediction), get(virtualRegisterForArgument(1, registerOffset)))); 2725 return true; 2726 } 2727 2728 case StringPrototypeValueOfIntrinsic: { 2729 insertChecks(); 2730 Node* value = get(virtualRegisterForArgument(0, registerOffset)); 2731 set(result, addToGraph(StringValueOf, value)); 2732 return true; 2733 } 2734 2735 case StringPrototypeReplaceIntrinsic: { 2736 if (argumentCountIncludingThis != 3) 2737 return false; 2738 2739 // Don't inline intrinsic if we exited due to "search" not being a RegExp or String object. 2740 if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadType)) 2741 return false; 2742 2743 // Don't inline intrinsic if we exited due to one of the primordial RegExp checks failing. 2744 if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCell)) 2745 return false; 2746 2747 JSGlobalObject* globalObject = m_inlineStackTop->m_codeBlock->globalObject(); 2748 Structure* regExpStructure = globalObject->regExpStructure(); 2749 m_graph.registerStructure(regExpStructure); 2750 ASSERT(regExpStructure->storedPrototype().isObject()); 2751 ASSERT(regExpStructure->storedPrototype().asCell()->classInfo(*m_vm) == RegExpPrototype::info()); 2752 2753 FrozenValue* regExpPrototypeObjectValue = m_graph.freeze(regExpStructure->storedPrototype()); 2754 Structure* regExpPrototypeStructure = regExpPrototypeObjectValue->structure(); 2755 2756 auto isRegExpPropertySame = [&] (JSValue primordialProperty, UniquedStringImpl* propertyUID) { 2757 JSValue currentProperty; 2758 if (!m_graph.getRegExpPrototypeProperty(regExpStructure->storedPrototypeObject(), regExpPrototypeStructure, propertyUID, currentProperty)) 2759 return false; 2760 2761 return currentProperty == primordialProperty; 2762 }; 2763 2764 // Check that searchRegExp.exec is still the primordial RegExp.prototype.exec 2765 if (!isRegExpPropertySame(globalObject->regExpProtoExecFunction(), m_vm->propertyNames->exec.impl())) 2766 return false; 2767 2768 // Check that searchRegExp.global is still the primordial RegExp.prototype.global 2769 if (!isRegExpPropertySame(globalObject->regExpProtoGlobalGetter(), m_vm->propertyNames->global.impl())) 2770 return false; 2771 2772 // Check that searchRegExp.unicode is still the primordial RegExp.prototype.unicode 2773 if (!isRegExpPropertySame(globalObject->regExpProtoUnicodeGetter(), m_vm->propertyNames->unicode.impl())) 2774 return false; 2775 2776 // Check that searchRegExp[Symbol.match] is still the primordial RegExp.prototype[Symbol.replace] 2777 if (!isRegExpPropertySame(globalObject->regExpProtoSymbolReplaceFunction(), m_vm->propertyNames->replaceSymbol.impl())) 2778 return false; 2779 2780 insertChecks(); 2781 2782 Node* resultNode = addToGraph(StringReplace, OpInfo(0), OpInfo(prediction), get(virtualRegisterForArgument(0, registerOffset)), get(virtualRegisterForArgument(1, registerOffset)), get(virtualRegisterForArgument(2, registerOffset))); 2783 set(result, resultNode); 2784 return true; 2785 } 2786 2787 case StringPrototypeReplaceRegExpIntrinsic: { 2788 if (argumentCountIncludingThis != 3) 2789 return false; 2790 2791 insertChecks(); 2792 Node* resultNode = addToGraph(StringReplaceRegExp, OpInfo(0), OpInfo(prediction), get(virtualRegisterForArgument(0, registerOffset)), get(virtualRegisterForArgument(1, registerOffset)), get(virtualRegisterForArgument(2, registerOffset))); 2793 set(result, resultNode); 2794 return true; 2795 } 2796 2797 case RoundIntrinsic: 2798 case FloorIntrinsic: 2799 case CeilIntrinsic: 2800 case TruncIntrinsic: { 2801 if (argumentCountIncludingThis == 1) { 2802 insertChecks(); 2803 set(result, addToGraph(JSConstant, OpInfo(m_constantNaN))); 2804 return true; 2805 } 2806 insertChecks(); 2807 Node* operand = get(virtualRegisterForArgument(1, registerOffset)); 2808 NodeType op; 2809 if (intrinsic == RoundIntrinsic) 2810 op = ArithRound; 2811 else if (intrinsic == FloorIntrinsic) 2812 op = ArithFloor; 2813 else if (intrinsic == CeilIntrinsic) 2814 op = ArithCeil; 2815 else { 2816 ASSERT(intrinsic == TruncIntrinsic); 2817 op = ArithTrunc; 2818 } 2819 Node* roundNode = addToGraph(op, OpInfo(0), OpInfo(prediction), operand); 2820 set(result, roundNode); 2821 return true; 2822 } 2823 case IMulIntrinsic: { 2824 if (argumentCountIncludingThis != 3) 2825 return false; 2826 insertChecks(); 2827 VirtualRegister leftOperand = virtualRegisterForArgument(1, registerOffset); 2828 VirtualRegister rightOperand = virtualRegisterForArgument(2, registerOffset); 2829 Node* left = get(leftOperand); 2830 Node* right = get(rightOperand); 2831 set(result, addToGraph(ArithIMul, left, right)); 2832 return true; 2833 } 2834 2835 case RandomIntrinsic: { 2836 if (argumentCountIncludingThis != 1) 2837 return false; 2838 insertChecks(); 2839 set(result, addToGraph(ArithRandom)); 2840 return true; 2841 } 2842 2843 case DFGTrueIntrinsic: { 2844 insertChecks(); 2845 set(result, jsConstant(jsBoolean(true))); 2846 return true; 2847 } 2848 2849 case FTLTrueIntrinsic: { 2850 insertChecks(); 2851 set(result, jsConstant(jsBoolean(m_graph.m_plan.isFTL()))); 2852 return true; 2853 } 2854 2855 case OSRExitIntrinsic: { 2856 insertChecks(); 2857 addToGraph(ForceOSRExit); 2858 set(result, addToGraph(JSConstant, OpInfo(m_constantUndefined))); 2859 return true; 2860 } 2861 2862 case IsFinalTierIntrinsic: { 2863 insertChecks(); 2864 set(result, 2865 jsConstant(jsBoolean(Options::useFTLJIT() ? m_graph.m_plan.isFTL() : true))); 2866 return true; 2867 } 2868 2869 case SetInt32HeapPredictionIntrinsic: { 2870 insertChecks(); 2871 for (int i = 1; i < argumentCountIncludingThis; ++i) { 2872 Node* node = get(virtualRegisterForArgument(i, registerOffset)); 2873 if (node->hasHeapPrediction()) 2874 node->setHeapPrediction(SpecInt32Only); 2875 } 2876 set(result, addToGraph(JSConstant, OpInfo(m_constantUndefined))); 2877 return true; 2878 } 2879 2880 case CheckInt32Intrinsic: { 2881 insertChecks(); 2882 for (int i = 1; i < argumentCountIncludingThis; ++i) { 2883 Node* node = get(virtualRegisterForArgument(i, registerOffset)); 2884 addToGraph(Phantom, Edge(node, Int32Use)); 2885 } 2886 set(result, jsConstant(jsBoolean(true))); 2887 return true; 2888 } 2889 2890 case FiatInt52Intrinsic: { 2891 if (argumentCountIncludingThis != 2) 2892 return false; 2893 insertChecks(); 2894 VirtualRegister operand = virtualRegisterForArgument(1, registerOffset); 2895 if (enableInt52()) 2896 set(result, addToGraph(FiatInt52, get(operand))); 2897 else 2898 set(result, get(operand)); 2899 return true; 2900 } 2901 2902 case JSMapGetIntrinsic: { 2903 if (argumentCountIncludingThis != 2) 2904 return false; 2905 2906 insertChecks(); 2907 Node* map = get(virtualRegisterForArgument(0, registerOffset)); 2908 Node* key = get(virtualRegisterForArgument(1, registerOffset)); 2909 Node* normalizedKey = addToGraph(NormalizeMapKey, key); 2910 Node* hash = addToGraph(MapHash, normalizedKey); 2911 Node* bucket = addToGraph(GetMapBucket, Edge(map, MapObjectUse), Edge(normalizedKey), Edge(hash)); 2912 Node* resultNode = addToGraph(LoadValueFromMapBucket, OpInfo(BucketOwnerType::Map), OpInfo(prediction), bucket); 2913 set(result, resultNode); 2914 return true; 2915 } 2916 2917 case JSSetHasIntrinsic: 2918 case JSMapHasIntrinsic: { 2919 if (argumentCountIncludingThis != 2) 2920 return false; 2921 2922 insertChecks(); 2923 Node* mapOrSet = get(virtualRegisterForArgument(0, registerOffset)); 2924 Node* key = get(virtualRegisterForArgument(1, registerOffset)); 2925 Node* normalizedKey = addToGraph(NormalizeMapKey, key); 2926 Node* hash = addToGraph(MapHash, normalizedKey); 2927 UseKind useKind = intrinsic == JSSetHasIntrinsic ? SetObjectUse : MapObjectUse; 2928 Node* bucket = addToGraph(GetMapBucket, OpInfo(0), Edge(mapOrSet, useKind), Edge(normalizedKey), Edge(hash)); 2929 JSCell* sentinel = nullptr; 2930 if (intrinsic == JSMapHasIntrinsic) 2931 sentinel = m_vm->sentinelMapBucket.get(); 2932 else 2933 sentinel = m_vm->sentinelSetBucket.get(); 2934 2935 FrozenValue* frozenPointer = m_graph.freeze(sentinel); 2936 Node* invertedResult = addToGraph(CompareEqPtr, OpInfo(frozenPointer), bucket); 2937 Node* resultNode = addToGraph(LogicalNot, invertedResult); 2938 set(result, resultNode); 2939 return true; 2940 } 2941 2942 case JSSetAddIntrinsic: { 2943 if (argumentCountIncludingThis != 2) 2944 return false; 2945 2946 insertChecks(); 2947 Node* base = get(virtualRegisterForArgument(0, registerOffset)); 2948 Node* key = get(virtualRegisterForArgument(1, registerOffset)); 2949 Node* normalizedKey = addToGraph(NormalizeMapKey, key); 2950 Node* hash = addToGraph(MapHash, normalizedKey); 2951 addToGraph(SetAdd, base, normalizedKey, hash); 2952 set(result, base); 2953 return true; 2954 } 2955 2956 case JSMapSetIntrinsic: { 2957 if (argumentCountIncludingThis != 3) 2958 return false; 2959 2960 insertChecks(); 2961 Node* base = get(virtualRegisterForArgument(0, registerOffset)); 2962 Node* key = get(virtualRegisterForArgument(1, registerOffset)); 2963 Node* value = get(virtualRegisterForArgument(2, registerOffset)); 2964 2965 Node* normalizedKey = addToGraph(NormalizeMapKey, key); 2966 Node* hash = addToGraph(MapHash, normalizedKey); 2967 2968 addVarArgChild(base); 2969 addVarArgChild(normalizedKey); 2970 addVarArgChild(value); 2971 addVarArgChild(hash); 2972 addToGraph(Node::VarArg, MapSet, OpInfo(0), OpInfo(0)); 2973 set(result, base); 2974 return true; 2975 } 2976 2977 case JSSetBucketHeadIntrinsic: 2978 case JSMapBucketHeadIntrinsic: { 2979 ASSERT(argumentCountIncludingThis == 2); 2980 2981 insertChecks(); 2982 Node* map = get(virtualRegisterForArgument(1, registerOffset)); 2983 UseKind useKind = intrinsic == JSSetBucketHeadIntrinsic ? SetObjectUse : MapObjectUse; 2984 Node* resultNode = addToGraph(GetMapBucketHead, Edge(map, useKind)); 2985 set(result, resultNode); 2986 return true; 2987 } 2988 2989 case JSSetBucketNextIntrinsic: 2990 case JSMapBucketNextIntrinsic: { 2991 ASSERT(argumentCountIncludingThis == 2); 2992 2993 insertChecks(); 2994 Node* bucket = get(virtualRegisterForArgument(1, registerOffset)); 2995 BucketOwnerType type = intrinsic == JSSetBucketNextIntrinsic ? BucketOwnerType::Set : BucketOwnerType::Map; 2996 Node* resultNode = addToGraph(GetMapBucketNext, OpInfo(type), bucket); 2997 set(result, resultNode); 2998 return true; 2999 } 3000 3001 case JSSetBucketKeyIntrinsic: 3002 case JSMapBucketKeyIntrinsic: { 3003 ASSERT(argumentCountIncludingThis == 2); 3004 3005 insertChecks(); 3006 Node* bucket = get(virtualRegisterForArgument(1, registerOffset)); 3007 BucketOwnerType type = intrinsic == JSSetBucketKeyIntrinsic ? BucketOwnerType::Set : BucketOwnerType::Map; 3008 Node* resultNode = addToGraph(LoadKeyFromMapBucket, OpInfo(type), OpInfo(prediction), bucket); 3009 set(result, resultNode); 3010 return true; 3011 } 3012 3013 case JSMapBucketValueIntrinsic: { 3014 ASSERT(argumentCountIncludingThis == 2); 3015 3016 insertChecks(); 3017 Node* bucket = get(virtualRegisterForArgument(1, registerOffset)); 3018 Node* resultNode = addToGraph(LoadValueFromMapBucket, OpInfo(BucketOwnerType::Map), OpInfo(prediction), bucket); 3019 set(result, resultNode); 3020 return true; 3021 } 3022 3023 case JSWeakMapGetIntrinsic: { 3024 if (argumentCountIncludingThis != 2) 3025 return false; 3026 3027 if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadType)) 3028 return false; 3029 3030 insertChecks(); 3031 Node* map = get(virtualRegisterForArgument(0, registerOffset)); 3032 Node* key = get(virtualRegisterForArgument(1, registerOffset)); 3033 addToGraph(Check, Edge(key, ObjectUse)); 3034 Node* hash = addToGraph(MapHash, key); 3035 Node* holder = addToGraph(WeakMapGet, Edge(map, WeakMapObjectUse), Edge(key, ObjectUse), Edge(hash, Int32Use)); 3036 Node* resultNode = addToGraph(ExtractValueFromWeakMapGet, OpInfo(), OpInfo(prediction), holder); 3037 3038 set(result, resultNode); 3039 return true; 3040 } 3041 3042 case JSWeakMapHasIntrinsic: { 3043 if (argumentCountIncludingThis != 2) 3044 return false; 3045 3046 if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadType)) 3047 return false; 3048 3049 insertChecks(); 3050 Node* map = get(virtualRegisterForArgument(0, registerOffset)); 3051 Node* key = get(virtualRegisterForArgument(1, registerOffset)); 3052 addToGraph(Check, Edge(key, ObjectUse)); 3053 Node* hash = addToGraph(MapHash, key); 3054 Node* holder = addToGraph(WeakMapGet, Edge(map, WeakMapObjectUse), Edge(key, ObjectUse), Edge(hash, Int32Use)); 3055 Node* invertedResult = addToGraph(IsEmpty, holder); 3056 Node* resultNode = addToGraph(LogicalNot, invertedResult); 3057 3058 set(result, resultNode); 3059 return true; 3060 } 3061 3062 case JSWeakSetHasIntrinsic: { 3063 if (argumentCountIncludingThis != 2) 3064 return false; 3065 3066 if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadType)) 3067 return false; 3068 3069 insertChecks(); 3070 Node* map = get(virtualRegisterForArgument(0, registerOffset)); 3071 Node* key = get(virtualRegisterForArgument(1, registerOffset)); 3072 addToGraph(Check, Edge(key, ObjectUse)); 3073 Node* hash = addToGraph(MapHash, key); 3074 Node* holder = addToGraph(WeakMapGet, Edge(map, WeakSetObjectUse), Edge(key, ObjectUse), Edge(hash, Int32Use)); 3075 Node* invertedResult = addToGraph(IsEmpty, holder); 3076 Node* resultNode = addToGraph(LogicalNot, invertedResult); 3077 3078 set(result, resultNode); 3079 return true; 3080 } 3081 3082 case JSWeakSetAddIntrinsic: { 3083 if (argumentCountIncludingThis != 2) 3084 return false; 3085 3086 if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadType)) 3087 return false; 3088 3089 insertChecks(); 3090 Node* base = get(virtualRegisterForArgument(0, registerOffset)); 3091 Node* key = get(virtualRegisterForArgument(1, registerOffset)); 3092 addToGraph(Check, Edge(key, ObjectUse)); 3093 Node* hash = addToGraph(MapHash, key); 3094 addToGraph(WeakSetAdd, Edge(base, WeakSetObjectUse), Edge(key, ObjectUse), Edge(hash, Int32Use)); 3095 set(result, base); 3096 return true; 3097 } 3098 3099 case JSWeakMapSetIntrinsic: { 3100 if (argumentCountIncludingThis != 3) 3101 return false; 3102 3103 if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadType)) 3104 return false; 3105 3106 insertChecks(); 3107 Node* base = get(virtualRegisterForArgument(0, registerOffset)); 3108 Node* key = get(virtualRegisterForArgument(1, registerOffset)); 3109 Node* value = get(virtualRegisterForArgument(2, registerOffset)); 3110 3111 addToGraph(Check, Edge(key, ObjectUse)); 3112 Node* hash = addToGraph(MapHash, key); 3113 3114 addVarArgChild(Edge(base, WeakMapObjectUse)); 3115 addVarArgChild(Edge(key, ObjectUse)); 3116 addVarArgChild(Edge(value)); 3117 addVarArgChild(Edge(hash, Int32Use)); 3118 addToGraph(Node::VarArg, WeakMapSet, OpInfo(0), OpInfo(0)); 3119 set(result, base); 3120 return true; 3121 } 3122 3123 case DataViewGetInt8: 3124 case DataViewGetUint8: 3125 case DataViewGetInt16: 3126 case DataViewGetUint16: 3127 case DataViewGetInt32: 3128 case DataViewGetUint32: 3129 case DataViewGetFloat32: 3130 case DataViewGetFloat64: { 3131 if (!is64Bit()) 3132 return false; 3133 3134 // To inline data view accesses, we assume the architecture we're running on: 3135 // - Is little endian. 3136 // - Allows unaligned loads/stores without crashing. 3137 3138 if (argumentCountIncludingThis < 2) 3139 return false; 3140 if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadType)) 3141 return false; 3142 3143 insertChecks(); 3144 3145 uint8_t byteSize; 3146 NodeType op = DataViewGetInt; 3147 bool isSigned = false; 3148 switch (intrinsic) { 3149 case DataViewGetInt8: 3150 isSigned = true; 3151 FALLTHROUGH; 3152 case DataViewGetUint8: 3153 byteSize = 1; 3154 break; 3155 3156 case DataViewGetInt16: 3157 isSigned = true; 3158 FALLTHROUGH; 3159 case DataViewGetUint16: 3160 byteSize = 2; 3161 break; 3162 3163 case DataViewGetInt32: 3164 isSigned = true; 3165 FALLTHROUGH; 3166 case DataViewGetUint32: 3167 byteSize = 4; 3168 break; 3169 3170 case DataViewGetFloat32: 3171 byteSize = 4; 3172 op = DataViewGetFloat; 3173 break; 3174 case DataViewGetFloat64: 3175 byteSize = 8; 3176 op = DataViewGetFloat; 3177 break; 3178 default: 3179 RELEASE_ASSERT_NOT_REACHED(); 3180 } 3181 3182 TriState isLittleEndian = MixedTriState; 3183 Node* littleEndianChild = nullptr; 3184 if (byteSize > 1) { 3185 if (argumentCountIncludingThis < 3) 3186 isLittleEndian = FalseTriState; 3187 else { 3188 littleEndianChild = get(virtualRegisterForArgument(2, registerOffset)); 3189 if (littleEndianChild->hasConstant()) { 3190 JSValue constant = littleEndianChild->constant()->value(); 3191 isLittleEndian = constant.pureToBoolean(); 3192 if (isLittleEndian != MixedTriState) 3193 littleEndianChild = nullptr; 3194 } else 3195 isLittleEndian = MixedTriState; 3196 } 3197 } 3198 3199 DataViewData data { }; 3200 data.isLittleEndian = isLittleEndian; 3201 data.isSigned = isSigned; 3202 data.byteSize = byteSize; 3203 3204 set(VirtualRegister(result), 3205 addToGraph(op, OpInfo(data.asQuadWord), OpInfo(prediction), get(virtualRegisterForArgument(0, registerOffset)), get(virtualRegisterForArgument(1, registerOffset)), littleEndianChild)); 3206 return true; 3207 } 3208 3209 case DataViewSetInt8: 3210 case DataViewSetUint8: 3211 case DataViewSetInt16: 3212 case DataViewSetUint16: 3213 case DataViewSetInt32: 3214 case DataViewSetUint32: 3215 case DataViewSetFloat32: 3216 case DataViewSetFloat64: { 3217 if (!is64Bit()) 3218 return false; 3219 3220 if (argumentCountIncludingThis < 3) 3221 return false; 3222 3223 if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadType)) 3224 return false; 3225 3226 insertChecks(); 3227 3228 uint8_t byteSize; 3229 bool isFloatingPoint = false; 3230 bool isSigned = false; 3231 switch (intrinsic) { 3232 case DataViewSetInt8: 3233 isSigned = true; 3234 FALLTHROUGH; 3235 case DataViewSetUint8: 3236 byteSize = 1; 3237 break; 3238 3239 case DataViewSetInt16: 3240 isSigned = true; 3241 FALLTHROUGH; 3242 case DataViewSetUint16: 3243 byteSize = 2; 3244 break; 3245 3246 case DataViewSetInt32: 3247 isSigned = true; 3248 FALLTHROUGH; 3249 case DataViewSetUint32: 3250 byteSize = 4; 3251 break; 3252 3253 case DataViewSetFloat32: 3254 isFloatingPoint = true; 3255 byteSize = 4; 3256 break; 3257 case DataViewSetFloat64: 3258 isFloatingPoint = true; 3259 byteSize = 8; 3260 break; 3261 default: 3262 RELEASE_ASSERT_NOT_REACHED(); 3263 } 3264 3265 TriState isLittleEndian = MixedTriState; 3266 Node* littleEndianChild = nullptr; 3267 if (byteSize > 1) { 3268 if (argumentCountIncludingThis < 4) 3269 isLittleEndian = FalseTriState; 3270 else { 3271 littleEndianChild = get(virtualRegisterForArgument(3, registerOffset)); 3272 if (littleEndianChild->hasConstant()) { 3273 JSValue constant = littleEndianChild->constant()->value(); 3274 isLittleEndian = constant.pureToBoolean(); 3275 if (isLittleEndian != MixedTriState) 3276 littleEndianChild = nullptr; 3277 } else 3278 isLittleEndian = MixedTriState; 3279 } 3280 } 3281 3282 DataViewData data { }; 3283 data.isLittleEndian = isLittleEndian; 3284 data.isSigned = isSigned; 3285 data.byteSize = byteSize; 3286 data.isFloatingPoint = isFloatingPoint; 3287 3288 addVarArgChild(get(virtualRegisterForArgument(0, registerOffset))); 3289 addVarArgChild(get(virtualRegisterForArgument(1, registerOffset))); 3290 addVarArgChild(get(virtualRegisterForArgument(2, registerOffset))); 3291 addVarArgChild(littleEndianChild); 3292 3293 addToGraph(Node::VarArg, DataViewSet, OpInfo(data.asQuadWord), OpInfo()); 3294 return true; 3295 } 3296 3297 case HasOwnPropertyIntrinsic: { 3298 if (argumentCountIncludingThis != 2) 3299 return false; 3300 3301 // This can be racy, that's fine. We know that once we observe that this is created, 3302 // that it will never be destroyed until the VM is destroyed. It's unlikely that 3303 // we'd ever get to the point where we inline this as an intrinsic without the 3304 // cache being created, however, it's possible if we always throw exceptions inside 3305 // hasOwnProperty. 3306 if (!m_vm->hasOwnPropertyCache()) 3307 return false; 3308 3309 insertChecks(); 3310 Node* object = get(virtualRegisterForArgument(0, registerOffset)); 3311 Node* key = get(virtualRegisterForArgument(1, registerOffset)); 3312 Node* resultNode = addToGraph(HasOwnProperty, object, key); 3313 set(result, resultNode); 3314 return true; 3315 } 3316 3317 case StringPrototypeSliceIntrinsic: { 3318 if (argumentCountIncludingThis < 2) 3319 return false; 3320 3321 if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadType)) 3322 return false; 3323 3324 insertChecks(); 3325 Node* thisString = get(virtualRegisterForArgument(0, registerOffset)); 3326 Node* start = get(virtualRegisterForArgument(1, registerOffset)); 3327 Node* end = nullptr; 3328 if (argumentCountIncludingThis > 2) 3329 end = get(virtualRegisterForArgument(2, registerOffset)); 3330 Node* resultNode = addToGraph(StringSlice, thisString, start, end); 3331 set(result, resultNode); 3332 return true; 3333 } 3334 3335 case StringPrototypeToLowerCaseIntrinsic: { 3336 if (argumentCountIncludingThis != 1) 3337 return false; 3338 3339 if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadType)) 3340 return false; 3341 3342 insertChecks(); 3343 Node* thisString = get(virtualRegisterForArgument(0, registerOffset)); 3344 Node* resultNode = addToGraph(ToLowerCase, thisString); 3345 set(result, resultNode); 3346 return true; 3347 } 3348 3349 case NumberPrototypeToStringIntrinsic: { 3350 if (argumentCountIncludingThis != 1 && argumentCountIncludingThis != 2) 3351 return false; 3352 3353 if (m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadType)) 3354 return false; 3355 3356 insertChecks(); 3357 Node* thisNumber = get(virtualRegisterForArgument(0, registerOffset)); 3358 if (argumentCountIncludingThis == 1) { 3359 Node* resultNode = addToGraph(ToString, thisNumber); 3360 set(result, resultNode); 3361 } else { 3362 Node* radix = get(virtualRegisterForArgument(1, registerOffset)); 3363 Node* resultNode = addToGraph(NumberToStringWithRadix, thisNumber, radix); 3364 set(result, resultNode); 3365 } 3366 return true; 3367 } 3368 3369 case NumberIsIntegerIntrinsic: { 3370 if (argumentCountIncludingThis < 2) 3371 return false; 3372 3373 insertChecks(); 3374 Node* input = get(virtualRegisterForArgument(1, registerOffset)); 3375 Node* resultNode = addToGraph(NumberIsInteger, input); 3376 set(result, resultNode); 3377 return true; 3378 } 3379 3380 case CPUMfenceIntrinsic: 3381 case CPURdtscIntrinsic: 3382 case CPUCpuidIntrinsic: 3383 case CPUPauseIntrinsic: { 3384 #if CPU(X86_64) 3385 if (!m_graph.m_plan.isFTL()) 3386 return false; 3387 insertChecks(); 3388 set(result, 3389 addToGraph(CPUIntrinsic, OpInfo(intrinsic), OpInfo())); 3390 return true; 3391 #else 3392 return false; 3393 #endif 3394 } 3395 3396 3397 default: 3398 return false; 3399 } 3414 return false; 3400 3415 } 3401 3416
Note: See TracChangeset
for help on using the changeset viewer.