Bug 820583 - Use a larger script size limit when compiling off thread, r=dvander.
authorBrian Hackett <bhackett1024@gmail.com>
Tue, 08 Jan 2013 13:42:03 -0700
changeset 118139 cb1f63ecc1cd690fe9c4a46fcbdce34c62e1fe5a
parent 118138 63cbf8539eac85de59f81a0ab2641b5762d39b01
child 118140 fe88a7f31340f8a5d27f2676ec9765dc16788231
push id24153
push useremorley@mozilla.com
push dateWed, 09 Jan 2013 13:34:18 +0000
treeherdermozilla-central@be151be0cf60 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdvander
bugs820583
milestone21.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 820583 - Use a larger script size limit when compiling off thread, r=dvander.
js/src/ion/Ion.cpp
js/src/jsworkers.cpp
js/src/jsworkers.h
--- a/js/src/ion/Ion.cpp
+++ b/js/src/ion/Ion.cpp
@@ -1193,42 +1193,56 @@ IonCompile(JSContext *cx, HandleScript s
 
     AbortReason abortReason  = compileContext.compile(builder, graph, autoDestroy);
     if (abortReason != AbortReason_NoAbort)
         IonSpew(IonSpew_Abort, "IM Compilation failed.");
 
     return abortReason;
 }
 
+static inline bool
+OffThreadCompilationEnabled(JSContext *cx)
+{
+    return js_IonOptions.parallelCompilation
+        && cx->runtime->useHelperThreads()
+        && cx->runtime->helperThreadCount() != 0;
+}
+
+static inline bool
+OffThreadCompilationAvailable(JSContext *cx)
+{
+    // Even if off thread compilation is enabled, compilation must still occur
+    // on the main thread in some cases. Do not compile off thread during an
+    // incremental GC, as this may trip incremental read barriers. Also skip
+    // off thread compilation if script execution is being profiled, as
+    // CodeGenerator::maybeCreateScriptCounts will not attach script profiles
+    // when running off thread.
+    return OffThreadCompilationEnabled(cx)
+        && cx->runtime->gcIncrementalState == gc::NO_INCREMENTAL
+        && !cx->runtime->profilingScripts;
+}
+
 AbortReason
 SequentialCompileContext::compile(IonBuilder *builder, MIRGraph *graph,
                                   AutoDestroyAllocator &autoDestroy)
 {
     JS_ASSERT(!builder->script()->ion);
     JSContext *cx = GetIonContext()->cx;
 
     RootedScript builderScript(cx, builder->script());
     IonSpewNewFunction(graph, builderScript);
 
     if (!builder->build()) {
         IonSpew(IonSpew_Abort, "Builder failed to build.");
         return builder->abortReason();
     }
     builder->clearForBackEnd();
 
-    // Try to compile the script off thread, if possible. Compilation cannot be
-    // performed off thread during an incremental GC, as doing so may trip
-    // incremental read barriers. Also skip off thread compilation if script
-    // execution is being profiled, as CodeGenerator::maybeCreateScriptCounts
-    // will not attach script profiles when running off thread.
-    if (js_IonOptions.parallelCompilation &&
-        OffThreadCompilationAvailable(cx) &&
-        cx->runtime->gcIncrementalState == gc::NO_INCREMENTAL &&
-        !cx->runtime->profilingScripts)
-    {
+    // If possible, compile the script off thread.
+    if (OffThreadCompilationAvailable(cx)) {
         builder->script()->ion = ION_COMPILING_SCRIPT;
 
         if (!StartOffThreadIonCompile(cx, builder)) {
             IonSpew(IonSpew_Abort, "Unable to start off-thread ion compilation.");
             return AbortReason_Alloc;
         }
 
         // The allocator and associated data will be destroyed after being
@@ -1327,55 +1341,81 @@ CheckScript(UnrootedScript script)
     if (!script->compileAndGo) {
         IonSpew(IonSpew_Abort, "not compile-and-go");
         return false;
     }
 
     return true;
 }
 
-static bool
-CheckScriptSize(UnrootedScript script)
+static MethodStatus
+CheckScriptSize(JSContext *cx, UnrootedScript script)
 {
     if (!js_IonOptions.limitScriptSize)
-        return true;
+        return Method_Compiled;
 
-    static const uint32_t MAX_SCRIPT_SIZE = 2000;
+    // Longer scripts can only be compiled off thread, as these compilations
+    // can be expensive and stall the main thread for too long.
+    static const uint32_t MAX_MAIN_THREAD_SCRIPT_SIZE = 2000;
+    static const uint32_t MAX_OFF_THREAD_SCRIPT_SIZE = 20000;
     static const uint32_t MAX_LOCALS_AND_ARGS = 256;
 
-    if (script->length > MAX_SCRIPT_SIZE) {
+    if (script->length > MAX_OFF_THREAD_SCRIPT_SIZE) {
         IonSpew(IonSpew_Abort, "Script too large (%u bytes)", script->length);
-        return false;
+        return Method_CantCompile;
+    }
+
+    if (script->length > MAX_MAIN_THREAD_SCRIPT_SIZE) {
+        if (OffThreadCompilationEnabled(cx)) {
+            // Even if off thread compilation is enabled, there are cases where
+            // compilation must still occur on the main thread. Don't compile
+            // in these cases (except when profiling scripts, as compilations
+            // occurring with profiling should reflect those without), but do
+            // not forbid compilation so that the script may be compiled later.
+            if (!OffThreadCompilationAvailable(cx) && !cx->runtime->profilingScripts) {
+                IonSpew(IonSpew_Abort, "Script too large for main thread, skipping (%u bytes)", script->length);
+                return Method_Skipped;
+            }
+        } else {
+            IonSpew(IonSpew_Abort, "Script too large (%u bytes)", script->length);
+            return Method_CantCompile;
+        }
     }
 
     uint32_t numLocalsAndArgs = analyze::TotalSlots(script);
     if (numLocalsAndArgs > MAX_LOCALS_AND_ARGS) {
         IonSpew(IonSpew_Abort, "Too many locals and arguments (%u)", numLocalsAndArgs);
-        return false;
+        return Method_CantCompile;
     }
 
-    return true;
+    return Method_Compiled;
 }
 
 static MethodStatus
 Compile(JSContext *cx, HandleScript script, HandleFunction fun, jsbytecode *osrPc, bool constructing)
 {
     JS_ASSERT(ion::IsEnabled(cx));
     JS_ASSERT_IF(osrPc != NULL, (JSOp)*osrPc == JSOP_LOOPENTRY);
 
     if (cx->compartment->debugMode()) {
         IonSpew(IonSpew_Abort, "debugging");
         return Method_CantCompile;
     }
 
-    if (!CheckScript(script) || !CheckScriptSize(script)) {
+    if (!CheckScript(script)) {
         IonSpew(IonSpew_Abort, "Aborted compilation of %s:%d", script->filename, script->lineno);
         return Method_CantCompile;
     }
 
+    MethodStatus status = CheckScriptSize(cx, script);
+    if (status != Method_Compiled) {
+        IonSpew(IonSpew_Abort, "Aborted compilation of %s:%d", script->filename, script->lineno);
+        return status;
+    }
+
     if (script->ion) {
         if (!script->ion->method())
             return Method_CantCompile;
         return Method_Compiled;
     }
 
     if (cx->methodJitEnabled) {
         // If JM is enabled we use getUseCount instead of incUseCount to avoid
--- a/js/src/jsworkers.cpp
+++ b/js/src/jsworkers.cpp
@@ -15,22 +15,16 @@
 
 using namespace js;
 
 using mozilla::DebugOnly;
 
 #ifdef JS_PARALLEL_COMPILATION
 
 bool
-js::OffThreadCompilationAvailable(JSContext *cx)
-{
-    return cx->runtime->useHelperThreads() && cx->runtime->helperThreadCount() > 0;
-}
-
-bool
 js::StartOffThreadIonCompile(JSContext *cx, ion::IonBuilder *builder)
 {
     JSRuntime *rt = cx->runtime;
     if (!rt->workerThreadState) {
         rt->workerThreadState = rt->new_<WorkerThreadState>();
         if (!rt->workerThreadState)
             return false;
         if (!rt->workerThreadState->init(rt)) {
@@ -355,15 +349,9 @@ js::StartOffThreadIonCompile(JSContext *
     return false;
 }
 
 void
 js::CancelOffThreadIonCompile(JSCompartment *compartment, JSScript *script)
 {
 }
 
-bool
-js::OffThreadCompilationAvailable(JSContext *cx)
-{
-    return false;
-}
-
 #endif /* JS_PARALLEL_COMPILATION */
--- a/js/src/jsworkers.h
+++ b/js/src/jsworkers.h
@@ -115,20 +115,16 @@ StartOffThreadIonCompile(JSContext *cx, 
 
 /*
  * Cancel a scheduled or in progress Ion compilation for script. If script is
  * NULL, all compilations for the compartment are cancelled.
  */
 void
 CancelOffThreadIonCompile(JSCompartment *compartment, JSScript *script);
 
-/* Return true iff off-thread compilation is possible. */
-bool
-OffThreadCompilationAvailable(JSContext *cx);
-
 class AutoLockWorkerThreadState
 {
     JSRuntime *rt;
     MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
 
   public:
 
     AutoLockWorkerThreadState(JSRuntime *rt