Changeset 211658 in webkit
- Timestamp:
- Feb 3, 2017 5:17:38 PM (7 years ago)
- Location:
- trunk/Source/JavaScriptCore
- Files:
-
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/ChangeLog
r211642 r211658 1 2017-02-03 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 r211224 and r211461 were reverted because they caused massive 9 kraken/ai-astar regressions. This patch instead does the 10 minimally-disruptive change to fix the original bug as described 11 below, but omits extra tuning and refactoring which I had 12 before. I'll commit tuning and refactoring separately, if this 13 sticks. This patch is therefore very minimal, and layers carefully 14 on top of the complex spaghetti-logic. The only change it makes is 15 that it uses triggers to indicate to outer loops that they should 16 compile, which fixes the immediate bug and seems roughly perf 17 neutral (maybe a small gain on kraken sometimes, other times a 18 small regression as would be expected from slightly compiling 19 later). As opposed to r211461 this patch doesn't unconditionally 20 unset the trigger because it prevents further DFG executions from 21 entering. It therefore makes the trigger a tri-state enum class: 22 don't trigger, compilation done, start compilation. Only "start 23 compilation" gets reset to "don't trigger". "Compilation done" 24 does not (unless there's a problem compiling, then it gets set 25 back to "don't trigger"). 26 27 As of https://bugs.webkit.org/show_bug.cgi?id=155217 OSR 28 compilation can be kicked off for an entry into an outer-loop, 29 while executing an inner-loop. This is desirable because often the 30 codegen from an inner-entry isn't as good as the codegen from an 31 outer-entry, but execution from an inner-loop is often pretty hot 32 and likely to kick off compilation. This approach provided nice 33 speedups on Kraken because we'd select to enter to the outer-loop 34 very reliably, which reduces variability (the inner-loop was 35 selected roughly 1/5 times from my unscientific measurements). 36 37 When compilation starts we take a snapshot of the JSValues at the 38 current execution state using OSR's recovery mechanism. These 39 values are passed to the compiler and are used as way to perform 40 type profiling, and could be used to observe cell types as well as 41 to perform predictions such as through constant propagation. 42 43 It's therefore desired to enter from the outer-loop when we can, 44 but we need to be executing from that location to capture the 45 right JSValues, otherwise we're confusing the compiler and giving 46 it inaccurate JSValues which can lead it to predict the wrong 47 things, leading to suboptimal code or recompilation due to 48 misprediction, or in super-corner-cases a crash. 49 50 DFG tier-up was added here: 51 https://bugs.webkit.org/show_bug.cgi?id=112838 52 53 * dfg/DFGJITCode.h: 54 * dfg/DFGJITCompiler.cpp: 55 (JSC::DFG::JITCompiler::JITCompiler): 56 * dfg/DFGOperations.cpp: 57 * dfg/DFGSpeculativeJIT64.cpp: 58 (JSC::DFG::SpeculativeJIT::compile): 59 * dfg/DFGToFTLForOSREntryDeferredCompilationCallback.cpp: 60 (JSC::DFG::ToFTLForOSREntryDeferredCompilationCallback::ToFTLForOSREntryDeferredCompilationCallback): 61 (JSC::DFG::Ref<ToFTLForOSREntryDeferredCompilationCallback>ToFTLForOSREntryDeferredCompilationCallback::create): 62 (JSC::DFG::ToFTLForOSREntryDeferredCompilationCallback::compilationDidBecomeReadyAsynchronously): 63 (JSC::DFG::ToFTLForOSREntryDeferredCompilationCallback::compilationDidComplete): 64 * dfg/DFGToFTLForOSREntryDeferredCompilationCallback.h: 65 1 66 2017-02-03 Saam Barati <sbarati@apple.com> 2 67 -
trunk/Source/JavaScriptCore/dfg/DFGJITCode.h
r211245 r211658 152 152 HashMap<unsigned, unsigned, WTF::IntHash<unsigned>, WTF::UnsignedWithZeroKeyHashTraits<unsigned>> bytecodeIndexToStreamIndex; 153 153 154 enum class TriggerReason : uint8_t { 155 DontTrigger, 156 CompilationDone, 157 StartCompilation, 158 }; 159 154 160 // Map each bytecode of CheckTierUpAndOSREnter to its trigger forcing OSR Entry. 155 161 // This can never be modified after it has been initialized since the addresses of the triggers 156 162 // are used by the JIT. 157 HashMap<unsigned, uint8_t> tierUpEntryTriggers;163 HashMap<unsigned, TriggerReason> tierUpEntryTriggers; 158 164 159 165 // Set of bytecode that were the target of a TierUp operation. -
trunk/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp
r211245 r211658 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, JITCode::TriggerReason::DontTrigger); 64 64 #endif 65 65 } -
trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp
r211548 r211658 2352 2352 2353 2353 JITCode* jitCode = codeBlock->jitCode()->dfg(); 2354 2355 // The following is only true for triggerTierUpNowInLoop, which can never 2356 // be an OSR entry. 2357 bool canOSRFromHere = originBytecodeIndex == osrEntryBytecodeIndex; 2358 2359 bool triggeredSlowPathToStartCompilation = false; 2360 auto tierUpEntryTriggers = jitCode->tierUpEntryTriggers.find(originBytecodeIndex); 2361 if (tierUpEntryTriggers != jitCode->tierUpEntryTriggers.end()) { 2362 switch (tierUpEntryTriggers->value) { 2363 case JITCode::TriggerReason::DontTrigger: 2364 // The trigger isn't set, we entered because the counter reached its 2365 // threshold. 2366 break; 2367 2368 case JITCode::TriggerReason::CompilationDone: 2369 // The trigger was set because compilation completed. Don't unset it 2370 // so that further DFG executions OSR enters as well. 2371 RELEASE_ASSERT(canOSRFromHere); 2372 break; 2373 2374 case JITCode::TriggerReason::StartCompilation: 2375 // We were asked to enter as soon as possible and start compiling an 2376 // entry for the current bytecode location. Unset this trigger so we 2377 // don't continually enter. 2378 RELEASE_ASSERT(canOSRFromHere); 2379 tierUpEntryTriggers->value = JITCode::TriggerReason::DontTrigger; 2380 triggeredSlowPathToStartCompilation = true; 2381 break; 2382 } 2383 } 2384 2354 2385 if (worklistState == Worklist::Compiling) { 2355 2386 CODEBLOCK_LOG_EVENT(codeBlock, "delayFTLCompile", ("still compiling")); … … 2368 2399 2369 2400 // If we can OSR Enter, do it right away. 2370 if ( originBytecodeIndex == osrEntryBytecodeIndex) {2401 if (canOSRFromHere) { 2371 2402 unsigned streamIndex = jitCode->bytecodeIndexToStreamIndex.get(originBytecodeIndex); 2372 2403 if (CodeBlock* entryBlock = jitCode->osrEntryBlock()) { … … 2382 2413 // - If we couldn't enter for a while, then trigger OSR entry. 2383 2414 2384 if (!shouldTriggerFTLCompile(codeBlock, jitCode) )2415 if (!shouldTriggerFTLCompile(codeBlock, jitCode) && !triggeredSlowPathToStartCompilation) 2385 2416 return nullptr; 2386 2417 2387 if (!jitCode->neverExecutedEntry ) {2418 if (!jitCode->neverExecutedEntry && !triggeredSlowPathToStartCompilation) { 2388 2419 triggerFTLReplacementCompile(vm, codeBlock, jitCode); 2389 2420 … … 2425 2456 jitCode->clearOSREntryBlock(); 2426 2457 jitCode->osrEntryRetry = 0; 2427 jitCode->tierUpEntryTriggers.set(osrEntryBytecode, 0);2458 jitCode->tierUpEntryTriggers.set(osrEntryBytecode, JITCode::TriggerReason::DontTrigger); 2428 2459 jitCode->setOptimizationThresholdBasedOnCompilationResult( 2429 2460 codeBlock, CompilationDeferred); … … 2431 2462 } 2432 2463 2464 if (!canOSRFromHere) { 2465 // We can't OSR from here, or even start a compilation because doing so 2466 // calls jitCode->reconstruct which would get the wrong state. 2467 if (Options::verboseOSR()) 2468 dataLog("Non-OSR-able bc#", originBytecodeIndex, " in ", *codeBlock, " setting parent loop bc#", osrEntryBytecodeIndex, "'s trigger and backing off.\n"); 2469 jitCode->tierUpEntryTriggers.set(osrEntryBytecodeIndex, JITCode::TriggerReason::StartCompilation); 2470 jitCode->setOptimizationThresholdBasedOnCompilationResult(codeBlock, CompilationDeferred); 2471 return nullptr; 2472 } 2473 2433 2474 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); 2475 2476 if (!triggeredSlowPathToStartCompilation) { 2477 auto tierUpHierarchyEntry = jitCode->tierUpInLoopHierarchy.find(osrEntryBytecodeIndex); 2478 if (tierUpHierarchyEntry != jitCode->tierUpInLoopHierarchy.end()) { 2479 for (unsigned osrEntryCandidate : tierUpHierarchyEntry->value) { 2480 if (jitCode->tierUpEntrySeen.contains(osrEntryCandidate)) { 2481 // Ask an enclosing loop to compile, instead of doing so here. 2482 if (Options::verboseOSR()) 2483 dataLog("Inner-loop bc#", originBytecodeIndex, " in ", *codeBlock, " setting parent loop bc#", osrEntryCandidate, "'s trigger and backing off.\n"); 2484 jitCode->tierUpEntryTriggers.set(osrEntryCandidate, JITCode::TriggerReason::StartCompilation); 2485 jitCode->setOptimizationThresholdBasedOnCompilationResult(codeBlock, CompilationDeferred); 2486 return nullptr; 2487 } 2440 2488 } 2441 2489 } … … 2446 2494 auto triggerIterator = jitCode->tierUpEntryTriggers.find(osrEntryBytecodeIndex); 2447 2495 RELEASE_ASSERT(triggerIterator != jitCode->tierUpEntryTriggers.end()); 2448 uint8_t* triggerAddress = &(triggerIterator->value);2496 JITCode::TriggerReason* triggerAddress = &(triggerIterator->value); 2449 2497 2450 2498 Operands<JSValue> mustHandleValues; -
trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
r211247 r211658 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); 5784 JITCode::TriggerReason* forceEntryTrigger = &(m_jit.jitCode()->tierUpEntryTriggers.find(bytecodeIndex)->value); 5785 static_assert(!static_cast<uint8_t>(JITCode::TriggerReason::DontTrigger), "the JIT code assumes non-zero means 'enter'"); 5786 static_assert(sizeof(JITCode::TriggerReason) == 1, "branchTest8 assumes this size"); 5785 5787 5786 5788 MacroAssembler::Jump forceOSREntry = m_jit.branchTest8(MacroAssembler::NonZero, MacroAssembler::AbsoluteAddress(forceEntryTrigger)); -
trunk/Source/JavaScriptCore/dfg/DFGToFTLForOSREntryDeferredCompilationCallback.cpp
r211245 r211658 36 36 namespace JSC { namespace DFG { 37 37 38 ToFTLForOSREntryDeferredCompilationCallback::ToFTLForOSREntryDeferredCompilationCallback( uint8_t* forcedOSREntryTrigger)38 ToFTLForOSREntryDeferredCompilationCallback::ToFTLForOSREntryDeferredCompilationCallback(JITCode::TriggerReason* 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(JITCode::TriggerReason* forcedOSREntryTrigger) 48 48 { 49 49 return adoptRef(*new ToFTLForOSREntryDeferredCompilationCallback(forcedOSREntryTrigger)); … … 59 59 } 60 60 61 *m_forcedOSREntryTrigger = 1;61 *m_forcedOSREntryTrigger = JITCode::TriggerReason::CompilationDone; 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, JITCode::TriggerReason::CompilationDone); 80 80 break; 81 81 } -
trunk/Source/JavaScriptCore/dfg/DFGToFTLForOSREntryDeferredCompilationCallback.h
r211245 r211658 28 28 #if ENABLE(FTL_JIT) 29 29 30 #include "DFGJITCode.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(JITCode::TriggerReason* 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(JITCode::TriggerReason* forcedOSREntryTrigger); 47 48 48 49 virtual void compilationDidBecomeReadyAsynchronously(CodeBlock*, CodeBlock* profiledDFGCodeBlock); … … 50 51 51 52 private: 52 uint8_t* m_forcedOSREntryTrigger;53 JITCode::TriggerReason* m_forcedOSREntryTrigger; 53 54 }; 54 55
Note: See TracChangeset
for help on using the changeset viewer.