[JSC] Be aggressive with OSR Entry to FTL if the DFG function was only used for OSR Entry itself
https://bugs.webkit.org/show_bug.cgi?id=154575

Patch by Benjamin Poulain <bpoulain@apple.com> on 2016-02-25
Reviewed by Filip Pizlo.

I noticed that imaging-gaussian-blur spends most of its
samples in DFG code despite executing most of the loop
iterations in FTL.

On this particular test, the main function is only entered
once and have a very heavy loop there. What happens is DFG
starts by compiling the full function in FTL. That takes about
8 to 10 milliseconds during which the DFG code makes very little
progress. The calls to triggerOSREntryNow() try to OSR Enter
for a while then finally start compiling something. By the time
the function is ready, we have wasted a lot of time in DFG code.

What this patch does is set a flag when a DFG function is entered.
If we try to triggerOSREntryNow() and the flag was never set,
we start compiling both the full function and the one for OSR Entry.

* dfg/DFGJITCode.h:
* dfg/DFGJITCompiler.cpp:
(JSC::DFG::JITCompiler::compileEntryExecutionFlag):
(JSC::DFG::JITCompiler::compile):
(JSC::DFG::JITCompiler::compileFunction):
* dfg/DFGJITCompiler.h:
* dfg/DFGOperations.cpp:
* dfg/DFGPlan.cpp:
(JSC::DFG::Plan::Plan): Deleted.
* dfg/DFGPlan.h:
* dfg/DFGTierUpCheckInjectionPhase.cpp:
(JSC::DFG::TierUpCheckInjectionPhase::run):

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@197159 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/dfg/DFGOperations.cpp b/Source/JavaScriptCore/dfg/DFGOperations.cpp
index 06d16ad9..942b4ad 100644
--- a/Source/JavaScriptCore/dfg/DFGOperations.cpp
+++ b/Source/JavaScriptCore/dfg/DFGOperations.cpp
@@ -1432,21 +1432,26 @@
 }
 
 #if ENABLE(FTL_JIT)
-static void triggerFTLReplacementCompile(VM* vm, CodeBlock* codeBlock, JITCode* jitCode)
+static bool shouldTriggerFTLCompile(CodeBlock* codeBlock, JITCode* jitCode)
 {
     if (codeBlock->baselineVersion()->m_didFailFTLCompilation) {
         if (Options::verboseOSR())
             dataLog("Deferring FTL-optimization of ", *codeBlock, " indefinitely because there was an FTL failure.\n");
         jitCode->dontOptimizeAnytimeSoon(codeBlock);
-        return;
+        return false;
     }
-    
-    if (!jitCode->checkIfOptimizationThresholdReached(codeBlock)) {
+
+    if (!codeBlock->hasOptimizedReplacement()
+        && !jitCode->checkIfOptimizationThresholdReached(codeBlock)) {
         if (Options::verboseOSR())
             dataLog("Choosing not to FTL-optimize ", *codeBlock, " yet.\n");
-        return;
+        return false;
     }
-    
+    return true;
+}
+
+static void triggerFTLReplacementCompile(VM* vm, CodeBlock* codeBlock, JITCode* jitCode)
+{
     Worklist::State worklistState;
     if (Worklist* worklist = existingGlobalFTLWorklistOrNull()) {
         worklistState = worklist->completeAllReadyPlansForVM(
@@ -1479,6 +1484,10 @@
     compile(
         *vm, codeBlock->newReplacement(), codeBlock, FTLMode, UINT_MAX,
         Operands<JSValue>(), ToFTLDeferredCompilationCallback::create());
+
+    // If we reached here, the counter has not be reset. Do that now.
+    jitCode->setOptimizationThresholdBasedOnCompilationResult(
+        codeBlock, CompilationDeferred);
 }
 
 static void triggerTierUpNowCommon(ExecState* exec, bool inLoop)
@@ -1503,7 +1512,8 @@
     if (inLoop)
         jitCode->nestedTriggerIsSet = 1;
 
-    triggerFTLReplacementCompile(vm, codeBlock, jitCode);
+    if (shouldTriggerFTLCompile(codeBlock, jitCode))
+        triggerFTLReplacementCompile(vm, codeBlock, jitCode);
 }
 
 void JIT_OPERATION triggerTierUpNow(ExecState* exec)
@@ -1541,15 +1551,15 @@
     // - If we don't have an FTL code block, then try to compile one.
     // - If we do have an FTL code block, then try to enter for a while.
     // - If we couldn't enter for a while, then trigger OSR entry.
-    
-    triggerFTLReplacementCompile(vm, codeBlock, jitCode);
 
-    if (!codeBlock->hasOptimizedReplacement())
-        return 0;
-    
-    if (jitCode->osrEntryRetry < Options::ftlOSREntryRetryThreshold()) {
-        jitCode->osrEntryRetry++;
-        return 0;
+    if (!shouldTriggerFTLCompile(codeBlock, jitCode))
+        return nullptr;
+
+    if (!jitCode->neverExecutedEntry) {
+        triggerFTLReplacementCompile(vm, codeBlock, jitCode);
+
+        if (!codeBlock->hasOptimizedReplacement())
+            return nullptr;
     }
     
     // It's time to try to compile code for OSR entry.
@@ -1560,33 +1570,43 @@
     } else
         worklistState = Worklist::NotKnown;
     
-    if (worklistState == Worklist::Compiling)
-        return 0;
+    if (worklistState == Worklist::Compiling) {
+        jitCode->setOptimizationThresholdBasedOnCompilationResult(
+            codeBlock, CompilationDeferred);
+        return nullptr;
+    }
     
     if (CodeBlock* entryBlock = jitCode->osrEntryBlock()) {
         void* address = FTL::prepareOSREntry(
             exec, codeBlock, entryBlock, bytecodeIndex, streamIndex);
         if (address)
             return static_cast<char*>(address);
-        
+
+        if (jitCode->osrEntryRetry < Options::ftlOSREntryRetryThreshold()) {
+            jitCode->osrEntryRetry++;
+            return nullptr;
+        }
+
         FTL::ForOSREntryJITCode* entryCode = entryBlock->jitCode()->ftlForOSREntry();
         entryCode->countEntryFailure();
         if (entryCode->entryFailureCount() <
-            Options::ftlOSREntryFailureCountForReoptimization())
-            return 0;
+            Options::ftlOSREntryFailureCountForReoptimization()) {
+            jitCode->optimizeSoon(codeBlock);
+            return nullptr;
+        }
         
         // OSR entry failed. Oh no! This implies that we need to retry. We retry
         // without exponential backoff and we only do this for the entry code block.
         jitCode->clearOSREntryBlock();
         jitCode->osrEntryRetry = 0;
-        return 0;
+        return nullptr;
     }
     
     if (worklistState == Worklist::Compiled) {
         // This means that compilation failed and we already set the thresholds.
         if (Options::verboseOSR())
             dataLog("Code block ", *codeBlock, " was compiled but it doesn't have an optimized replacement.\n");
-        return 0;
+        return nullptr;
     }
 
     // We aren't compiling and haven't compiled anything for OSR entry. So, try to compile
@@ -1598,9 +1618,15 @@
     CompilationResult forEntryResult = compile(
         *vm, replacementCodeBlock, codeBlock, FTLForOSREntryMode, bytecodeIndex,
         mustHandleValues, ToFTLForOSREntryDeferredCompilationCallback::create());
-    
-    if (forEntryResult != CompilationSuccessful)
-        return 0;
+
+    if (jitCode->neverExecutedEntry)
+        triggerFTLReplacementCompile(vm, codeBlock, jitCode);
+
+    if (forEntryResult != CompilationSuccessful) {
+        jitCode->setOptimizationThresholdBasedOnCompilationResult(
+            codeBlock, CompilationDeferred);
+        return nullptr;
+    }
 
     // It's possible that the for-entry compile already succeeded. In that case OSR
     // entry will succeed unless we ran out of stack. It's not clear what we should do.
@@ -1609,6 +1635,7 @@
         exec, codeBlock, jitCode->osrEntryBlock(), bytecodeIndex, streamIndex);
     return static_cast<char*>(address);
 }
+
 #endif // ENABLE(FTL_JIT)
 
 } // extern "C"