Changeset 211224 in webkit
- Timestamp:
- Jan 26, 2017 11:52:35 AM (7 years ago)
- Location:
- trunk
- Files:
-
- 2 added
- 15 edited
- 1 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk/JSTests/ChangeLog
r211195 r211224 1 2017-01-26 JF Bastien <jfbastien@apple.com> 2 3 OSR entry: delay outer-loop compilation when at inner-loop 4 https://bugs.webkit.org/show_bug.cgi?id=167149 5 6 Reviewed by Filip Pizlo. 7 8 Try to be mean to OSR entry by using nested loops, and having 9 non-int32 types or truly varying types. 10 11 Mandelbrot currently never tiers up to FTL because it exits too 12 many times before this. That shouldn't happen because it's just 13 numbers and int32s. I'll file a bug to fix this. 14 15 * microbenchmarks/mandelbrot.js: Added. 16 (mandelbrot): 17 (printable): 18 * microbenchmarks/nonude.js: Added. 19 (Array.prototype.remove): 20 (const.u): 21 (const.load): 22 (const.scan): 23 (const.main): 24 1 25 2017-01-25 Saam Barati <sbarati@apple.com> 2 26 -
trunk/Source/JavaScriptCore/ChangeLog
r211195 r211224 1 2017-01-26 JF Bastien <jfbastien@apple.com> 2 3 OSR entry: delay outer-loop compilation when at inner-loop 4 https://bugs.webkit.org/show_bug.cgi?id=167149 5 6 Reviewed by Filip Pizlo. 7 8 As of https://bugs.webkit.org/show_bug.cgi?id=155217 OSR 9 compilation can be kicked off for an entry into an outer-loop, 10 while executing an inner-loop. This is desirable because often the 11 codegen from an inner-entry isn't as good as the codegen from an 12 outer-entry, but execution from an inner-loop is often pretty hot 13 and likely to kick off compilation. This approach provided nice 14 speedups on Kraken because we'd select to enter to the outer-loop 15 very reliably, which reduces variability (the inner-loop was 16 selected roughly 1/5 times from my unscientific measurements). 17 18 When compilation starts we take a snapshot of the JSValues at the 19 current execution state using OSR's recovery mechanism. These 20 values are passed to the compiler and are used as way to perform 21 type profiling, and could be used to observe cell types as well as 22 to perform predictions such as through constant propagation. 23 24 It's therefore desired to enter from the outer-loop when we can, 25 but we need to be executing from that location to capture the 26 right JSValues, otherwise we're confusing the compiler and giving 27 it inaccurate JSValues which can lead it to predict the wrong 28 things, leading to suboptimal code or recompilation due to 29 misprediction, or in super-corner-cases a crash. 30 31 These effects are pretty hard to measure: Fil points out that 32 marsalis-osr-entry really needs mustHandleValues (the JSValues 33 from the point of execution) because right now it just happens to 34 correctly guess int32. I tried removing mustHandleValues entirely 35 and saw no slowdowns, but our benchmarks probably aren't 36 sufficient to reliably find issues, sometimes because we happen to 37 have sufficient mitigations. 38 39 DFG tier-up was added here: 40 https://bugs.webkit.org/show_bug.cgi?id=112838 41 42 * JavaScriptCore.xcodeproj/project.pbxproj: 43 * dfg/DFGJITCode.h: 44 * dfg/DFGJITCompiler.cpp: 45 (JSC::DFG::JITCompiler::JITCompiler): 46 * dfg/DFGOSREntry.cpp: 47 (JSC::DFG::prepareOSREntry): 48 * dfg/DFGOSREntry.h: 49 (JSC::DFG::prepareOSREntry): 50 * dfg/DFGOperations.cpp: 51 * dfg/DFGOperations.h: 52 * dfg/DFGSpeculativeJIT64.cpp: 53 (JSC::DFG::SpeculativeJIT::compile): 54 * dfg/DFGTierUpEntryTrigger.h: Copied from Source/JavaScriptCore/ftl/FTLOSREntry.h. 55 * dfg/DFGToFTLForOSREntryDeferredCompilationCallback.cpp: 56 (JSC::DFG::ToFTLForOSREntryDeferredCompilationCallback::ToFTLForOSREntryDeferredCompilationCallback): 57 (JSC::DFG::Ref<ToFTLForOSREntryDeferredCompilationCallback>ToFTLForOSREntryDeferredCompilationCallback::create): 58 (JSC::DFG::ToFTLForOSREntryDeferredCompilationCallback::compilationDidBecomeReadyAsynchronously): 59 (JSC::DFG::ToFTLForOSREntryDeferredCompilationCallback::compilationDidComplete): 60 * dfg/DFGToFTLForOSREntryDeferredCompilationCallback.h: 61 * ftl/FTLOSREntry.cpp: 62 (JSC::FTL::prepareOSREntry): 63 * ftl/FTLOSREntry.h: 64 * jit/JITOperations.cpp: 65 1 66 2017-01-25 Saam Barati <sbarati@apple.com> 2 67 -
trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
r211069 r211224 2060 2060 ADE8029C1E08F1DE0058DE78 /* WebAssemblyLinkErrorPrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = ADE802971E08F1C90058DE78 /* WebAssemblyLinkErrorPrototype.h */; settings = {ATTRIBUTES = (Private, ); }; }; 2061 2061 ADE8029E1E08F2280058DE78 /* WebAssemblyLinkErrorConstructor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ADE8029D1E08F2260058DE78 /* WebAssemblyLinkErrorConstructor.cpp */; }; 2062 ADFF2F701E319DE3001EA54E /* DFGTierUpEntryTrigger.h in Headers */ = {isa = PBXBuildFile; fileRef = ADFF2F6F1E319DD0001EA54E /* DFGTierUpEntryTrigger.h */; }; 2062 2063 B59F89391891F29F00D5CCDC /* UnlinkedInstructionStream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B59F89381891ADB500D5CCDC /* UnlinkedInstructionStream.cpp */; }; 2063 2064 BC02E90D0E1839DB000F9297 /* ErrorConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = BC02E9050E1839DB000F9297 /* ErrorConstructor.h */; }; … … 4572 4573 ADE802971E08F1C90058DE78 /* WebAssemblyLinkErrorPrototype.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WebAssemblyLinkErrorPrototype.h; path = js/WebAssemblyLinkErrorPrototype.h; sourceTree = "<group>"; }; 4573 4574 ADE8029D1E08F2260058DE78 /* WebAssemblyLinkErrorConstructor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = WebAssemblyLinkErrorConstructor.cpp; path = js/WebAssemblyLinkErrorConstructor.cpp; sourceTree = "<group>"; }; 4575 ADFF2F6F1E319DD0001EA54E /* DFGTierUpEntryTrigger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGTierUpEntryTrigger.h; path = dfg/DFGTierUpEntryTrigger.h; sourceTree = "<group>"; }; 4574 4576 B59F89371891AD3300D5CCDC /* UnlinkedInstructionStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UnlinkedInstructionStream.h; sourceTree = "<group>"; }; 4575 4577 B59F89381891ADB500D5CCDC /* UnlinkedInstructionStream.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = UnlinkedInstructionStream.cpp; sourceTree = "<group>"; }; … … 7130 7132 0FD8A31F17D51F5700CA2C40 /* DFGTierUpCheckInjectionPhase.cpp */, 7131 7133 0FD8A32017D51F5700CA2C40 /* DFGTierUpCheckInjectionPhase.h */, 7134 ADFF2F6F1E319DD0001EA54E /* DFGTierUpEntryTrigger.h */, 7132 7135 0FD8A32117D51F5700CA2C40 /* DFGToFTLDeferredCompilationCallback.cpp */, 7133 7136 0FD8A32217D51F5700CA2C40 /* DFGToFTLDeferredCompilationCallback.h */, … … 8812 8815 A1A009C01831A22D00CF8711 /* MacroAssemblerARM64.h in Headers */, 8813 8816 86ADD1460FDDEA980006EEC2 /* MacroAssemblerARMv7.h in Headers */, 8817 ADFF2F701E319DE3001EA54E /* DFGTierUpEntryTrigger.h in Headers */, 8814 8818 863B23E00FC6118900703AA4 /* MacroAssemblerCodeRef.h in Headers */, 8815 8819 E32AB2441DCD75F400D7533A /* MacroAssemblerHelpers.h in Headers */, -
trunk/Source/JavaScriptCore/dfg/DFGJITCode.h
r208985 r211224 34 34 #include "DFGOSREntry.h" 35 35 #include "DFGOSRExit.h" 36 #include "DFGTierUpEntryTrigger.h" 36 37 #include "DFGVariableEventStream.h" 37 38 #include "ExecutionCounter.h" … … 155 156 // This can never be modified after it has been initialized since the addresses of the triggers 156 157 // are used by the JIT. 157 HashMap<unsigned, uint8_t> tierUpEntryTriggers;158 HashMap<unsigned, TierUpEntryTrigger> tierUpEntryTriggers; 158 159 159 160 // Set of bytecode that were the target of a TierUp operation. -
trunk/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp
r210023 r211224 61 61 m_jitCode->tierUpInLoopHierarchy = WTFMove(m_graph.m_plan.tierUpInLoopHierarchy); 62 62 for (unsigned tierUpBytecode : m_graph.m_plan.tierUpAndOSREnterBytecodes) 63 m_jitCode->tierUpEntryTriggers.add(tierUpBytecode, 0);63 m_jitCode->tierUpEntryTriggers.add(tierUpBytecode, TierUpEntryTrigger::None); 64 64 #endif 65 65 } -
trunk/Source/JavaScriptCore/dfg/DFGOSREntry.cpp
r203356 r211224 92 92 93 93 SUPPRESS_ASAN 94 void*prepareOSREntry(ExecState* exec, CodeBlock* codeBlock, unsigned bytecodeIndex)94 Expected<void*, OSREntryFail> prepareOSREntry(ExecState* exec, CodeBlock* codeBlock, unsigned bytecodeIndex) 95 95 { 96 96 ASSERT(JITCode::isOptimizingJIT(codeBlock->jitType())); … … 100 100 101 101 if (!Options::useOSREntryToDFG()) 102 return 0;102 return makeUnexpected(OSREntryFail::Disabled); 103 103 104 104 if (Options::verboseOSR()) { … … 137 137 if (Options::verboseOSR()) 138 138 dataLog(" OSR failed because the target code block is not DFG.\n"); 139 return 0;139 return makeUnexpected(OSREntryFail::TargetNotDFG); 140 140 } 141 141 … … 146 146 if (Options::verboseOSR()) 147 147 dataLogF(" OSR failed because the entrypoint was optimized out.\n"); 148 return 0;148 return makeUnexpected(OSREntryFail::TargetOptimizedOut); 149 149 } 150 150 … … 182 182 dataLogF(".\n"); 183 183 } 184 return 0;184 return makeUnexpected(OSREntryFail::BadPrediction); 185 185 } 186 186 … … 197 197 ", expected ", entry->m_expectedValues.argument(argument), ".\n"); 198 198 } 199 return 0;199 return makeUnexpected(OSREntryFail::BadPrediction); 200 200 } 201 201 } … … 210 210 exec->registers()[localOffset].asanUnsafeJSValue(), ", expected number.\n"); 211 211 } 212 return 0;212 return makeUnexpected(OSREntryFail::BadPrediction); 213 213 } 214 214 continue; … … 222 222 "machine int.\n"); 223 223 } 224 return 0;224 return makeUnexpected(OSREntryFail::BadPrediction); 225 225 } 226 226 continue; … … 233 233 entry->m_expectedValues.local(local), ".\n"); 234 234 } 235 return 0;235 return makeUnexpected(OSREntryFail::BadPrediction); 236 236 } 237 237 } … … 248 248 if (Options::verboseOSR()) 249 249 dataLogF(" OSR failed because stack growth failed.\n"); 250 return 0;250 return makeUnexpected(OSREntryFail::StackGrowthFailed); 251 251 } 252 252 -
trunk/Source/JavaScriptCore/dfg/DFGOSREntry.h
r206525 r211224 29 29 #include "Operands.h" 30 30 #include <wtf/BitVector.h> 31 #include <wtf/Expected.h> 31 32 32 33 namespace JSC { … … 36 37 37 38 namespace DFG { 39 40 enum class OSREntryFail { 41 Disabled, 42 TargetNotDFG, 43 TargetOptimizedOut, 44 BadPrediction, 45 StackGrowthFailed, 46 }; 38 47 39 48 #if ENABLE(DFG_JIT) … … 70 79 } 71 80 72 // Returns a pointer to a data buffer that the OSR entry thunk will recognize and 73 // parse. If this returns null, it means 74 void* prepareOSREntry(ExecState*, CodeBlock*, unsigned bytecodeIndex); 81 // Returns a pointer to a data buffer that the OSR entry thunk will recognize and parse. 82 Expected<void*, OSREntryFail> prepareOSREntry(ExecState*, CodeBlock*, unsigned bytecodeIndex); 75 83 #else 76 inline void* prepareOSREntry(ExecState*, CodeBlock*, unsigned) { return 0; }84 inline Expected<void*, OSREntryFail> prepareOSREntry(ExecState*, CodeBlock*, unsigned) { return makeUnexpected(OSREntryFail::Disabled); } 77 85 #endif 78 86 -
trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp
r211110 r211224 2315 2315 } 2316 2316 2317 // This updates the execution counter. 2317 2318 if (shouldTriggerFTLCompile(codeBlock, jitCode)) 2318 2319 triggerFTLReplacementCompile(vm, codeBlock, jitCode); … … 2338 2339 } 2339 2340 2340 static char* tierUpCommon(ExecState* exec, unsigned originBytecodeIndex, unsigned osrEntryBytecodeIndex) 2341 { 2342 VM* vm = &exec->vm(); 2343 CodeBlock* codeBlock = exec->codeBlock(); 2341 enum class EntryReason { 2342 Spurious, 2343 CheckingUpOnHowCompilationIsGoing, 2344 HaveOSREntryReady, 2345 ShouldStartCompiling, 2346 ShouldStartCompilingRightNow, 2347 CompilationFailed, 2348 }; 2349 2350 static EntryReason whatHaveYouDoneAndWhyAmIHere(VM* vm, CodeBlock* codeBlock, JITCode* jitCode, unsigned bytecodeIndex, CodeBlock*& osrEntryBlock) 2351 { 2352 // Gather facts about why we could be here. 2344 2353 2345 2354 // Resolve any pending plan for OSR Enter on this function. 2346 2355 Worklist::State worklistState; 2347 if (Worklist* worklist = existingGlobalFTLWorklistOrNull()) { 2348 worklistState = worklist->completeAllReadyPlansForVM( 2349 *vm, CompilationKey(codeBlock->baselineVersion(), FTLForOSREntryMode)); 2350 } else 2356 if (Worklist* worklist = existingGlobalFTLWorklistOrNull()) 2357 worklistState = worklist->completeAllReadyPlansForVM(*vm, CompilationKey(codeBlock->baselineVersion(), FTLForOSREntryMode)); 2358 else 2351 2359 worklistState = Worklist::NotKnown; 2352 2360 2353 JITCode* jitCode = codeBlock->jitCode()->dfg(); 2354 if (worklistState == Worklist::Compiling) { 2361 osrEntryBlock = jitCode->osrEntryBlock(); 2362 2363 // Was the tier-up entry trigger set to slow-path? 2364 bool triggeredSlowPath = false; 2365 auto tierUpEntryTriggers = jitCode->tierUpEntryTriggers.find(bytecodeIndex); 2366 if (tierUpEntryTriggers != jitCode->tierUpEntryTriggers.end()) { 2367 if (tierUpEntryTriggers->value == TierUpEntryTrigger::TakeSlowPath) { 2368 // We were asked to enter as soon as possible. Unset this trigger so we don't continually enter. 2369 if (Options::verboseOSR()) 2370 dataLog("EntryTrigger for ", *codeBlock, " forced slow-path.\n"); 2371 triggeredSlowPath = true; 2372 tierUpEntryTriggers->value = TierUpEntryTrigger::None; 2373 } 2374 } 2375 2376 // Put those facts together to make a final determination. 2377 2378 switch (worklistState) { 2379 case Worklist::NotKnown: 2380 if (osrEntryBlock) 2381 return EntryReason::HaveOSREntryReady; 2382 if (triggeredSlowPath) { 2383 // Someone went through the trouble of forcing us into slow-path, they really wanted us to compile. 2384 return EntryReason::ShouldStartCompilingRightNow; 2385 } 2386 return EntryReason::ShouldStartCompiling; 2387 2388 case Worklist::Compiling: 2389 if (triggeredSlowPath) { 2390 // We're already compiling, and can't OSR enter. We therefore must 2391 // have set our slow-path trigger as well as another slow path 2392 // trigger, hoping one of these would kick off a compilation. Sure 2393 // enough another bytecode location did kick off a compilation 2394 // before this one got a chance to do so. There's nothing for us to 2395 // do but wait. 2396 return EntryReason::Spurious; 2397 } 2398 return EntryReason::CheckingUpOnHowCompilationIsGoing; 2399 2400 case Worklist::Compiled: 2401 return EntryReason::CompilationFailed; 2402 } 2403 2404 RELEASE_ASSERT_NOT_REACHED(); 2405 return EntryReason::Spurious; 2406 } 2407 2408 enum class CanOSREnterFromHere { 2409 No, 2410 Yes, 2411 }; 2412 2413 static char* tierUpCommon(VM* vm, ExecState* exec, CodeBlock* codeBlock, JITCode* jitCode, unsigned bytecodeIndex, CanOSREnterFromHere canOSREnterFromHere) 2414 { 2415 CodeBlock* osrEntryBlock; 2416 EntryReason entryReason = whatHaveYouDoneAndWhyAmIHere(vm, codeBlock, jitCode, bytecodeIndex, osrEntryBlock); 2417 2418 switch (entryReason) { 2419 case EntryReason::CheckingUpOnHowCompilationIsGoing: 2355 2420 CODEBLOCK_LOG_EVENT(codeBlock, "delayFTLCompile", ("still compiling")); 2356 2421 jitCode->setOptimizationThresholdBasedOnCompilationResult( 2357 2422 codeBlock, CompilationDeferred); 2358 2423 return nullptr; 2359 } 2360 2361 if (worklistState == Worklist::Compiled) { 2424 2425 case EntryReason::CompilationFailed: 2362 2426 CODEBLOCK_LOG_EVENT(codeBlock, "delayFTLCompile", ("compiled and failed")); 2363 // This means that compilation failed and we already set the thresholds.2427 // We've already set the thresholds. 2364 2428 if (Options::verboseOSR()) 2365 2429 dataLog("Code block ", *codeBlock, " was compiled but it doesn't have an optimized replacement.\n"); 2366 2430 return nullptr; 2367 } 2368 2369 // If we can OSR Enter, do it right away. 2370 if (originBytecodeIndex == osrEntryBytecodeIndex) { 2371 unsigned streamIndex = jitCode->bytecodeIndexToStreamIndex.get(originBytecodeIndex); 2372 if (CodeBlock* entryBlock = jitCode->osrEntryBlock()) { 2373 if (void* address = FTL::prepareOSREntry(exec, codeBlock, entryBlock, originBytecodeIndex, streamIndex)) { 2374 CODEBLOCK_LOG_EVENT(entryBlock, "osrEntry", ("at bc#", originBytecodeIndex)); 2431 2432 case EntryReason::HaveOSREntryReady: 2433 if (canOSREnterFromHere == CanOSREnterFromHere::No) 2434 break; // OSR entry is for another location. 2435 2436 { 2437 // If we can OSR Enter, do it right away. 2438 unsigned streamIndex = jitCode->bytecodeIndexToStreamIndex.get(bytecodeIndex); 2439 auto osrEntryPreparation = FTL::prepareOSREntry(exec, codeBlock, osrEntryBlock, bytecodeIndex, streamIndex); 2440 if (osrEntryPreparation) { 2441 CODEBLOCK_LOG_EVENT(osrEntryBlock, "osrEntry", ("at bc#", bytecodeIndex)); 2442 void* address = osrEntryPreparation.value(); 2443 ASSERT(address); 2375 2444 return static_cast<char*>(address); 2376 2445 } 2446 switch (osrEntryPreparation.error()) { 2447 case FTL::OSREntryFail::StackGrowthFailed: 2448 break; 2449 case FTL::OSREntryFail::WrongBytecode: 2450 // Above we checked that an entry was possible from the current 2451 // location, but we didn't know whether the compiled OSR entry 2452 // was for this location. Now we know it's not. 2453 break; 2454 } 2455 2456 break; 2377 2457 } 2458 2459 case EntryReason::ShouldStartCompiling: 2460 case EntryReason::ShouldStartCompilingRightNow: 2461 // We'll take care of that below. 2462 break; 2463 2464 case EntryReason::Spurious: 2465 if (Options::verboseOSR()) 2466 dataLog("Code block ", *codeBlock, " was spuriously woken up, compilation is already under way.\n"); 2467 jitCode->checkIfOptimizationThresholdReached(codeBlock); 2468 return nullptr; 2378 2469 } 2379 2470 … … 2382 2473 // - If we couldn't enter for a while, then trigger OSR entry. 2383 2474 2475 // This updates the execution counter. 2384 2476 if (!shouldTriggerFTLCompile(codeBlock, jitCode)) 2385 2477 return nullptr; … … 2399 2491 CODEBLOCK_LOG_EVENT(codeBlock, "delayFTLCompile", ("avoiding replacement compile")); 2400 2492 2401 // It's time to try to compile code for OSR entry. 2402 if (CodeBlock* entryBlock = jitCode->osrEntryBlock()) { 2493 if (osrEntryBlock) { 2494 // We have a compiled OSR entry for this function, but didn't enter. 2495 2403 2496 if (jitCode->osrEntryRetry < Options::ftlOSREntryRetryThreshold()) { 2404 2497 CODEBLOCK_LOG_EVENT(codeBlock, "delayFTLCompile", ("OSR entry failed, OSR entry threshold not met")); … … 2409 2502 } 2410 2503 2411 FTL::ForOSREntryJITCode* entryCode = entryBlock->jitCode()->ftlForOSREntry();2504 FTL::ForOSREntryJITCode* entryCode = osrEntryBlock->jitCode()->ftlForOSREntry(); 2412 2505 entryCode->countEntryFailure(); 2413 2506 if (entryCode->entryFailureCount() < … … 2422 2515 // without exponential backoff and we only do this for the entry code block. 2423 2516 CODEBLOCK_LOG_EVENT(codeBlock, "delayFTLCompile", ("OSR entry failed too many times")); 2424 unsigned osrEntryBytecode = entryBlock->jitCode()->ftlForOSREntry()->bytecodeIndex();2517 unsigned osrEntryBytecode = osrEntryBlock->jitCode()->ftlForOSREntry()->bytecodeIndex(); 2425 2518 jitCode->clearOSREntryBlock(); 2426 2519 jitCode->osrEntryRetry = 0; 2427 jitCode->tierUpEntryTriggers.set(osrEntryBytecode, 0);2520 jitCode->tierUpEntryTriggers.set(osrEntryBytecode, TierUpEntryTrigger::None); 2428 2521 jitCode->setOptimizationThresholdBasedOnCompilationResult( 2429 2522 codeBlock, CompilationDeferred); … … 2431 2524 } 2432 2525 2433 unsigned streamIndex = jitCode->bytecodeIndexToStreamIndex.get(osrEntryBytecodeIndex); 2434 auto tierUpHierarchyEntry = jitCode->tierUpInLoopHierarchy.find(osrEntryBytecodeIndex); 2435 if (tierUpHierarchyEntry != jitCode->tierUpInLoopHierarchy.end()) { 2436 for (unsigned osrEntryCandidate : tierUpHierarchyEntry->value) { 2437 if (jitCode->tierUpEntrySeen.contains(osrEntryCandidate)) { 2438 osrEntryBytecodeIndex = osrEntryCandidate; 2439 streamIndex = jitCode->bytecodeIndexToStreamIndex.get(osrEntryBytecodeIndex); 2526 // We aren't compiling and haven't compiled anything for OSR entry. So, try to compile something. 2527 2528 if (entryReason != EntryReason::ShouldStartCompilingRightNow) { 2529 // We entered because our threshold was set, not because someone is forcing us to compile. 2530 // Try to see if there would be a better place to compile from than where we currently are. 2531 2532 // Compiling an outer-loop for OSR entry often generates better code than an inner-loop because 2533 // the entry is less disruptive. If we're at an inner-loop be smart and mark the outer-loop as 2534 // needing compilation ASAP. Once execution reaches the outer-loop compilation will trigger. 2535 auto tierUpHierarchyEntry = jitCode->tierUpInLoopHierarchy.find(bytecodeIndex); 2536 if (tierUpHierarchyEntry != jitCode->tierUpInLoopHierarchy.end() && !tierUpHierarchyEntry->value.isEmpty()) { 2537 // Traverse the loop hierarchy from the outer-most loop, to the inner-most one. 2538 for (auto iterator = tierUpHierarchyEntry->value.rbegin(), end = tierUpHierarchyEntry->value.rend(); iterator != end; ++iterator) { 2539 unsigned osrEntryCandidate = *iterator; 2540 if (jitCode->tierUpEntrySeen.contains(osrEntryCandidate)) { 2541 unsigned outerLoopOsrEntryBytecodeIndex = osrEntryCandidate; 2542 2543 // We found an outer-loop which would be a better OSR entry 2544 // than the current location: 2545 // - Set its trigger so it takes the slow-path ASAP; 2546 // - Tell the codeblock to stop its counter slow-path for a 2547 // while, because it should wait for the outer-loop to 2548 // trigger. 2549 // 2550 // If we slow-path again then one of these is true: 2551 // 1. We enter from the outer-loop because of its trigger, 2552 // it un-sets its trigger, kicks off a compile, 2553 // everything is good; 2554 // 2. We enter from anywhere and a compile is under way, 2555 // just chill as usual; 2556 // 3. We never got to that outer-loop and the counter 2557 // tripped again, bummer! 2558 // 2559 // We can detect 3. because the outer-loop's trigger is 2560 // set. It's still a great place to enter, so leave its 2561 // trigger set, but also: 2562 // - Set the trigger for the next loop in, hope that one triggers; 2563 // - Backoff the counter as before. 2564 // That is, unless all the inner-loop's parent triggers are 2565 // set. In that case just optimize the innermost-loop: it 2566 // won't generate as good code, but the outer-loops aren't 2567 // triggering so we may as we tier up where we can. 2568 auto outerLoopTierUpEntryTriggers = jitCode->tierUpEntryTriggers.find(outerLoopOsrEntryBytecodeIndex); 2569 ASSERT(outerLoopTierUpEntryTriggers != jitCode->tierUpEntryTriggers.end()); 2570 2571 if (outerLoopTierUpEntryTriggers->value != TierUpEntryTrigger::TakeSlowPath) { 2572 if (Options::verboseOSR()) 2573 dataLog("Forcibly FTL-optimize outer-loop bc#", outerLoopOsrEntryBytecodeIndex, " in ", *codeBlock, "by setting its trigger.\n"); 2574 2575 CODEBLOCK_LOG_EVENT(codeBlock, "delayFTLCompile", ("OSR entry request from inner-loop for outer-loop")); 2576 jitCode->tierUpEntryTriggers.set(outerLoopOsrEntryBytecodeIndex, TierUpEntryTrigger::TakeSlowPath); 2577 jitCode->optimizeSoon(codeBlock); 2578 return nullptr; 2579 } 2580 2581 if (Options::verboseOSR()) 2582 dataLog("Trying to forcibly FTL-optimize outer-loop bc#", outerLoopOsrEntryBytecodeIndex, " in ", *codeBlock, ", but trigger is already set.\n"); 2583 } 2440 2584 } 2585 2586 // All the outer-loops have their trigger set, but none have been entered. 2587 2588 if (canOSREnterFromHere == CanOSREnterFromHere::No) { 2589 // We just can't enter from here, we've asked everyone we know 2590 // to please optimize ASAP, nobody has heeded our call. Keep 2591 // hoping one of the outer loops triggers get to their slow 2592 // path. Stop the counter, there's nothing we can do. 2593 jitCode->dontOptimizeAnytimeSoon(codeBlock); 2594 return nullptr; 2595 } 2596 2597 if (Options::verboseOSR()) 2598 dataLog("Tried to forcibly-optimize outer-loop, but falling back to bc#", bytecodeIndex, " in ", *codeBlock, ", outer-loop triggers didn't work.\n"); 2441 2599 } 2442 2600 } 2443 2601 2444 // We aren't compiling and haven't compiled anything for OSR entry. So, try to compile 2445 // something. 2446 auto triggerIterator = jitCode->tierUpEntryTriggers.find(osrEntryBytecodeIndex); 2602 RELEASE_ASSERT(canOSREnterFromHere == CanOSREnterFromHere::Yes); 2603 2604 unsigned streamIndex = jitCode->bytecodeIndexToStreamIndex.get(bytecodeIndex); 2605 2606 // We're not trying to kick off a compile of an outer-loop from within an 2607 // inner-loop. We can compile right here, right now. 2608 auto triggerIterator = jitCode->tierUpEntryTriggers.find(bytecodeIndex); 2447 2609 RELEASE_ASSERT(triggerIterator != jitCode->tierUpEntryTriggers.end()); 2448 uint8_t* triggerAddress = &(triggerIterator->value); 2449 2610 TierUpEntryTrigger* triggerAddress = &(triggerIterator->value); 2611 2612 // Use OSR reconstruction to generate a snapshot of JSValues at the current 2613 // location of execution. The optimizer is happy when it can look at real 2614 // and live values, as opposed to mere type traces. 2450 2615 Operands<JSValue> mustHandleValues; 2451 2616 jitCode->reconstruct( 2452 exec, codeBlock, CodeOrigin( osrEntryBytecodeIndex), streamIndex, mustHandleValues);2617 exec, codeBlock, CodeOrigin(bytecodeIndex), streamIndex, mustHandleValues); 2453 2618 CodeBlock* replacementCodeBlock = codeBlock->newReplacement(); 2454 2619 2455 2620 CODEBLOCK_LOG_EVENT(codeBlock, "triggerFTLOSR", ()); 2456 2621 CompilationResult forEntryResult = compile( 2457 *vm, replacementCodeBlock, codeBlock, FTLForOSREntryMode, osrEntryBytecodeIndex,2622 *vm, replacementCodeBlock, codeBlock, FTLForOSREntryMode, bytecodeIndex, 2458 2623 mustHandleValues, ToFTLForOSREntryDeferredCompilationCallback::create(triggerAddress)); 2459 2624 … … 2467 2632 return nullptr; 2468 2633 } 2469 2470 CODEBLOCK_LOG_EVENT(jitCode->osrEntryBlock(), "osrEntry", ("at bc#", originBytecodeIndex)); 2471 // It's possible that the for-entry compile already succeeded. In that case OSR 2472 // entry will succeed unless we ran out of stack. It's not clear what we should do. 2473 // We signal to try again after a while if that happens. 2474 void* address = FTL::prepareOSREntry( 2475 exec, codeBlock, jitCode->osrEntryBlock(), originBytecodeIndex, streamIndex); 2476 return static_cast<char*>(address); 2634 2635 // It's possible that the for-entry compile already succeeded. In that case 2636 // OSR entry will succeed unless we ran out of stack. 2637 auto osrEntryPreparation = FTL::prepareOSREntry(exec, codeBlock, jitCode->osrEntryBlock(), bytecodeIndex, streamIndex); 2638 if (osrEntryPreparation) { 2639 CODEBLOCK_LOG_EVENT(jitCode->osrEntryBlock(), "osrEntry", ("at bc#", bytecodeIndex)); 2640 void* address = osrEntryPreparation.value(); 2641 ASSERT(address); 2642 return static_cast<char*>(address); 2643 } 2644 switch (osrEntryPreparation.error()) { 2645 case FTL::OSREntryFail::StackGrowthFailed: 2646 // It's not clear what we should do. We signal to try again after a 2647 // while if that happens. 2648 return nullptr; 2649 case FTL::OSREntryFail::WrongBytecode: 2650 RELEASE_ASSERT_NOT_REACHED(); 2651 } 2652 2653 RELEASE_ASSERT_NOT_REACHED(); 2654 return nullptr; 2477 2655 } 2478 2656 … … 2497 2675 } 2498 2676 2677 // It's impossible to OSR enter from the current bytecode index: CheckTierUpInLoop is only even generated for non-OSR-entry bytecodes. 2678 // It's nonetheless a good spot to request that a nearby loop get optimized the next time it's entered. 2679 2499 2680 auto tierUpHierarchyEntry = jitCode->tierUpInLoopHierarchy.find(bytecodeIndex); 2500 2681 if (tierUpHierarchyEntry != jitCode->tierUpInLoopHierarchy.end() 2501 2682 && !tierUpHierarchyEntry->value.isEmpty()) { 2502 tierUpCommon(exec, bytecodeIndex, tierUpHierarchyEntry->value.first()); 2503 } else if (shouldTriggerFTLCompile(codeBlock, jitCode)) 2683 // There is a suitable loop to OSR enter from. 2684 tierUpCommon(vm, exec, codeBlock, jitCode, bytecodeIndex, CanOSREnterFromHere::No); 2685 } else if (shouldTriggerFTLCompile(codeBlock, jitCode)) // This updates the execution counter. 2504 2686 triggerFTLReplacementCompile(vm, codeBlock, jitCode); 2505 2687 … … 2511 2693 } 2512 2694 2513 char* JIT_OPERATION triggerOSREntryNow(ExecState* exec, unsigned bytecodeIndex)2695 char* JIT_OPERATION checkTierUpAndOSREnterNow(ExecState* exec, unsigned bytecodeIndex) 2514 2696 { 2515 2697 VM* vm = &exec->vm(); … … 2524 2706 2525 2707 JITCode* jitCode = codeBlock->jitCode()->dfg(); 2526 jitCode->tierUpEntrySeen.add(bytecodeIndex);2527 2708 2528 2709 if (Options::verboseOSR()) { … … 2532 2713 } 2533 2714 2534 return tierUpCommon(exec, bytecodeIndex, bytecodeIndex); 2715 jitCode->tierUpEntrySeen.add(bytecodeIndex); 2716 return tierUpCommon(vm, exec, codeBlock, jitCode, bytecodeIndex, CanOSREnterFromHere::Yes); 2535 2717 } 2536 2718 -
trunk/Source/JavaScriptCore/dfg/DFGOperations.h
r209638 r211224 221 221 void JIT_OPERATION triggerTierUpNow(ExecState*) WTF_INTERNAL; 222 222 void JIT_OPERATION triggerTierUpNowInLoop(ExecState*, unsigned bytecodeIndex) WTF_INTERNAL; 223 char* JIT_OPERATION triggerOSREntryNow(ExecState*, unsigned bytecodeIndex) WTF_INTERNAL;223 char* JIT_OPERATION checkTierUpAndOSREnterNow(ExecState*, unsigned bytecodeIndex) WTF_INTERNAL; 224 224 #endif // ENABLE(FTL_JIT) 225 225 -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
r210844 r211224 5782 5782 auto triggerIterator = m_jit.jitCode()->tierUpEntryTriggers.find(bytecodeIndex); 5783 5783 DFG_ASSERT(m_jit.graph(), node, triggerIterator != m_jit.jitCode()->tierUpEntryTriggers.end()); 5784 uint8_t* forceEntryTrigger = &(m_jit.jitCode()->tierUpEntryTriggers.find(bytecodeIndex)->value); 5785 5784 TierUpEntryTrigger* forceEntryTrigger = &(m_jit.jitCode()->tierUpEntryTriggers.find(bytecodeIndex)->value); 5785 5786 static_assert(sizeof(TierUpEntryTrigger) == 1, "8-bit load is generated below"); 5787 static_assert(!static_cast<uint8_t>(TierUpEntryTrigger::None), "NonZero test below depends on this"); 5786 5788 MacroAssembler::Jump forceOSREntry = m_jit.branchTest8(MacroAssembler::NonZero, MacroAssembler::AbsoluteAddress(forceEntryTrigger)); 5787 5789 MacroAssembler::Jump overflowedCounter = m_jit.branchAdd32( … … 5803 5805 silentSpill(savePlans); 5804 5806 m_jit.setupArgumentsWithExecState(TrustedImm32(bytecodeIndex)); 5805 appendCallSetResult( triggerOSREntryNow, tempGPR);5807 appendCallSetResult(checkTierUpAndOSREnterNow, tempGPR); 5806 5808 5807 5809 if (savePlans.isEmpty()) -
trunk/Source/JavaScriptCore/dfg/DFGTierUpEntryTrigger.h
r211223 r211224 1 1 /* 2 * Copyright (C) 201 3Apple Inc. All rights reserved.2 * Copyright (C) 2017 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 26 26 #pragma once 27 27 28 #if ENABLE( FTL_JIT)28 #if ENABLE(DFG_JIT) 29 29 30 namespace JSC { 30 namespace JSC { namespace DFG { 31 31 32 class CodeBlock; 33 class ExecState; 32 enum class TierUpEntryTrigger : uint8_t { 33 None = 0, // Must stay zero: JIT-compiled code takes the triggerOSREntryNow slow-path when non-zero. 34 TakeSlowPath, // The slow path can be taken because the compilation needs to be started, or it's ready and we should OSR enter. 35 }; 34 36 35 namespace FTL { 37 } } // namespace JSC::DFG 36 38 37 void* prepareOSREntry( 38 ExecState*, CodeBlock* dfgCodeBlock, CodeBlock* entryCodeBlock, unsigned bytecodeIndex, 39 unsigned streamIndex); 40 41 } } // namespace JSC::FTL 42 43 #endif // ENABLE(FTL_JIT) 39 #endif // ENABLE(DFG_JIT) -
trunk/Source/JavaScriptCore/dfg/DFGToFTLForOSREntryDeferredCompilationCallback.cpp
r208063 r211224 36 36 namespace JSC { namespace DFG { 37 37 38 ToFTLForOSREntryDeferredCompilationCallback::ToFTLForOSREntryDeferredCompilationCallback( uint8_t* forcedOSREntryTrigger)38 ToFTLForOSREntryDeferredCompilationCallback::ToFTLForOSREntryDeferredCompilationCallback(TierUpEntryTrigger* forcedOSREntryTrigger) 39 39 : m_forcedOSREntryTrigger(forcedOSREntryTrigger) 40 40 { … … 45 45 } 46 46 47 Ref<ToFTLForOSREntryDeferredCompilationCallback>ToFTLForOSREntryDeferredCompilationCallback::create( uint8_t* forcedOSREntryTrigger)47 Ref<ToFTLForOSREntryDeferredCompilationCallback>ToFTLForOSREntryDeferredCompilationCallback::create(TierUpEntryTrigger* forcedOSREntryTrigger) 48 48 { 49 49 return adoptRef(*new ToFTLForOSREntryDeferredCompilationCallback(forcedOSREntryTrigger)); … … 59 59 } 60 60 61 *m_forcedOSREntryTrigger = 1;61 *m_forcedOSREntryTrigger = TierUpEntryTrigger::TakeSlowPath; 62 62 } 63 63 … … 77 77 jitCode->setOSREntryBlock(*codeBlock->vm(), profiledDFGCodeBlock, codeBlock); 78 78 unsigned osrEntryBytecode = codeBlock->jitCode()->ftlForOSREntry()->bytecodeIndex(); 79 jitCode->tierUpEntryTriggers.set(osrEntryBytecode, 1);79 jitCode->tierUpEntryTriggers.set(osrEntryBytecode, TierUpEntryTrigger::TakeSlowPath); 80 80 break; 81 81 } -
trunk/Source/JavaScriptCore/dfg/DFGToFTLForOSREntryDeferredCompilationCallback.h
r206525 r211224 28 28 #if ENABLE(FTL_JIT) 29 29 30 #include "DFGTierUpEntryTrigger.h" 30 31 #include "DeferredCompilationCallback.h" 31 32 #include <wtf/RefPtr.h> … … 39 40 class ToFTLForOSREntryDeferredCompilationCallback : public DeferredCompilationCallback { 40 41 protected: 41 ToFTLForOSREntryDeferredCompilationCallback( uint8_t* forcedOSREntryTrigger);42 ToFTLForOSREntryDeferredCompilationCallback(TierUpEntryTrigger* forcedOSREntryTrigger); 42 43 43 44 public: 44 45 virtual ~ToFTLForOSREntryDeferredCompilationCallback(); 45 46 46 static Ref<ToFTLForOSREntryDeferredCompilationCallback> create( uint8_t* forcedOSREntryTrigger);47 static Ref<ToFTLForOSREntryDeferredCompilationCallback> create(TierUpEntryTrigger* forcedOSREntryTrigger); 47 48 48 49 virtual void compilationDidBecomeReadyAsynchronously(CodeBlock*, CodeBlock* profiledDFGCodeBlock); … … 50 51 51 52 private: 52 uint8_t* m_forcedOSREntryTrigger;53 TierUpEntryTrigger* m_forcedOSREntryTrigger; 53 54 }; 54 55 -
trunk/Source/JavaScriptCore/ftl/FTLOSREntry.cpp
r209764 r211224 40 40 41 41 SUPPRESS_ASAN 42 void*prepareOSREntry(42 Expected<void*, OSREntryFail> prepareOSREntry( 43 43 ExecState* exec, CodeBlock* dfgCodeBlock, CodeBlock* entryCodeBlock, 44 44 unsigned bytecodeIndex, unsigned streamIndex) … … 62 62 if (Options::verboseOSR()) 63 63 dataLog(" OSR failed because we don't have an entrypoint for bc#", bytecodeIndex, "; ours is for bc#", entryCode->bytecodeIndex(), "\n"); 64 return 0;64 return makeUnexpected(OSREntryFail::WrongBytecode); 65 65 } 66 66 … … 96 96 if (Options::verboseOSR()) 97 97 dataLog(" OSR failed because stack growth failed.\n"); 98 return 0;98 return makeUnexpected(OSREntryFail::StackGrowthFailed); 99 99 } 100 100 -
trunk/Source/JavaScriptCore/ftl/FTLOSREntry.h
r206525 r211224 28 28 #if ENABLE(FTL_JIT) 29 29 30 #include <wtf/Expected.h> 31 30 32 namespace JSC { 31 33 … … 35 37 namespace FTL { 36 38 37 void* prepareOSREntry( 39 enum class OSREntryFail { 40 WrongBytecode, 41 StackGrowthFailed, 42 }; 43 44 Expected<void*, OSREntryFail> prepareOSREntry( 38 45 ExecState*, CodeBlock* dfgCodeBlock, CodeBlock* entryCodeBlock, unsigned bytecodeIndex, 39 46 unsigned streamIndex); -
trunk/Source/JavaScriptCore/jit/JITOperations.cpp
r210565 r211224 1424 1424 ASSERT(JITCode::isOptimizingJIT(optimizedCodeBlock->jitType())); 1425 1425 1426 if (void* dataBuffer = DFG::prepareOSREntry(exec, optimizedCodeBlock, bytecodeIndex)) { 1426 if (auto osrEntryPreparation = DFG::prepareOSREntry(exec, optimizedCodeBlock, bytecodeIndex)) { 1427 void* dataBuffer = osrEntryPreparation.value(); 1427 1428 CODEBLOCK_LOG_EVENT(optimizedCodeBlock, "osrEntry", ("at bc#", bytecodeIndex)); 1428 1429 if (Options::verboseOSR()) {
Note: See TracChangeset
for help on using the changeset viewer.