diff --git a/js/src/ion/Ion.cpp b/js/src/ion/Ion.cpp index ab1443f7c879..821bcbfb348c 100644 --- a/js/src/ion/Ion.cpp +++ b/js/src/ion/Ion.cpp @@ -1198,6 +1198,28 @@ IonCompile(JSContext *cx, HandleScript script, HandleFunction fun, jsbytecode *o 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) @@ -1214,16 +1236,8 @@ SequentialCompileContext::compile(IonBuilder *builder, MIRGraph *graph, } 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)) { @@ -1332,27 +1346,47 @@ CheckScript(UnrootedScript script) 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 @@ -1366,11 +1400,17 @@ Compile(JSContext *cx, HandleScript script, HandleFunction fun, jsbytecode *osrP 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; diff --git a/js/src/jsworkers.cpp b/js/src/jsworkers.cpp index cf2cca5bd4e9..6acfd84fd4d3 100644 --- a/js/src/jsworkers.cpp +++ b/js/src/jsworkers.cpp @@ -19,12 +19,6 @@ 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) { @@ -360,10 +354,4 @@ js::CancelOffThreadIonCompile(JSCompartment *compartment, JSScript *script) { } -bool -js::OffThreadCompilationAvailable(JSContext *cx) -{ - return false; -} - #endif /* JS_PARALLEL_COMPILATION */ diff --git a/js/src/jsworkers.h b/js/src/jsworkers.h index 1b4c8237511c..04f76b083595 100644 --- a/js/src/jsworkers.h +++ b/js/src/jsworkers.h @@ -120,10 +120,6 @@ StartOffThreadIonCompile(JSContext *cx, ion::IonBuilder *builder); void CancelOffThreadIonCompile(JSCompartment *compartment, JSScript *script); -/* Return true iff off-thread compilation is possible. */ -bool -OffThreadCompilationAvailable(JSContext *cx); - class AutoLockWorkerThreadState { JSRuntime *rt;