Bug 1142669 part 2 - Lower the script inlining size limit if off-thread compilation is not available. r=h4writer
authorJan de Mooij <jdemooij@mozilla.com>
Fri, 20 Mar 2015 13:45:35 +0100
changeset 263581 310b3af47e938a352a28bb3b31ebbaf8d9c30967
parent 263580 1c9568d7d26f6e3c005f4a68c5ca9d0fabd7657d
child 263582 157929ef51b3b8e63bc3dae44e881297d7003616
push id4718
push userraliiev@mozilla.com
push dateMon, 11 May 2015 18:39:53 +0000
treeherdermozilla-beta@c20c4ef55f08 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersh4writer
bugs1142669
milestone39.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 1142669 part 2 - Lower the script inlining size limit if off-thread compilation is not available. r=h4writer
js/src/jit/CompileWrappers.cpp
js/src/jit/CompileWrappers.h
js/src/jit/Ion.cpp
js/src/jit/Ion.h
js/src/jit/IonBuilder.cpp
js/src/jit/IonOptimizationLevels.cpp
js/src/jit/IonOptimizationLevels.h
--- a/js/src/jit/CompileWrappers.cpp
+++ b/js/src/jit/CompileWrappers.cpp
@@ -271,19 +271,21 @@ CompileCompartment::hasObjectMetadataCal
 void
 CompileCompartment::setSingletonsAsValues()
 {
     return JS::CompartmentOptionsRef(compartment()).setSingletonsAsValues();
 }
 
 JitCompileOptions::JitCompileOptions()
   : cloneSingletons_(false),
-    spsSlowAssertionsEnabled_(false)
+    spsSlowAssertionsEnabled_(false),
+    offThreadCompilationAvailable_(false)
 {
 }
 
 JitCompileOptions::JitCompileOptions(JSContext *cx)
 {
     JS::CompartmentOptions &options = cx->compartment()->options();
     cloneSingletons_ = options.cloneSingletons();
     spsSlowAssertionsEnabled_ = cx->runtime()->spsProfiler.enabled() &&
                                 cx->runtime()->spsProfiler.slowAssertionsEnabled();
+    offThreadCompilationAvailable_ = OffThreadCompilationAvailable(cx);
 }
--- a/js/src/jit/CompileWrappers.h
+++ b/js/src/jit/CompileWrappers.h
@@ -130,17 +130,22 @@ class JitCompileOptions
     bool cloneSingletons() const {
         return cloneSingletons_;
     }
 
     bool spsSlowAssertionsEnabled() const {
         return spsSlowAssertionsEnabled_;
     }
 
+    bool offThreadCompilationAvailable() const {
+        return offThreadCompilationAvailable_;
+    }
+
   private:
     bool cloneSingletons_;
     bool spsSlowAssertionsEnabled_;
+    bool offThreadCompilationAvailable_;
 };
 
 } // namespace jit
 } // namespace js
 
 #endif // jit_CompileWrappers_h
--- a/js/src/jit/Ion.cpp
+++ b/js/src/jit/Ion.cpp
@@ -1768,18 +1768,18 @@ MarkOffThreadNurseryObjects::mark(JSTrac
     jit::IonBuilder *builder = HelperThreadState().ionLazyLinkList().getFirst();
     while (builder) {
         if (builder->script()->runtimeFromAnyThread() == rt)
             builder->traceNurseryObjects(trc);
         builder = builder->getNext();
     }
 }
 
-static inline bool
-OffThreadCompilationAvailable(JSContext *cx)
+bool
+jit::OffThreadCompilationAvailable(JSContext *cx)
 {
     // Even if off thread compilation is enabled, compilation must still occur
     // on the main thread in some cases.
     //
     // Require cpuCount > 1 so that Ion compilation jobs and main-thread
     // execution are not competing for the same resources.
     return cx->runtime()->canUseOffthreadIonCompilation()
         && HelperThreadState().cpuCount > 1
@@ -1962,17 +1962,17 @@ IonCompile(JSContext *cx, JSScript *scri
             builder->actionableAbortLocationAndMessage(&abortScript, &abortPc, &abortMessage);
             TrackIonAbort(cx, abortScript, abortPc, abortMessage);
         }
 
         return reason;
     }
 
     // If possible, compile the script off thread.
-    if (OffThreadCompilationAvailable(cx)) {
+    if (options.offThreadCompilationAvailable()) {
         if (!recompile)
             builderScript->setIonScript(cx, ION_COMPILING_SCRIPT);
 
         JitSpew(JitSpew_IonLogs, "Can't log script %s:%" PRIuSIZE ". (Compiled on background thread.)",
                 builderScript->filename(), builderScript->lineno());
 
         JSRuntime *rt = cx->runtime();
         if (!builder->nurseryObjects().empty() && !rt->jitRuntime()->hasIonNurseryObjects()) {
--- a/js/src/jit/Ion.h
+++ b/js/src/jit/Ion.h
@@ -185,16 +185,18 @@ inline size_t
 NumLocalsAndArgs(JSScript *script)
 {
     size_t num = 1 /* this */ + script->nfixed();
     if (JSFunction *fun = script->functionNonDelazifying())
         num += fun->nargs();
     return num;
 }
 
+bool OffThreadCompilationAvailable(JSContext *cx);
+
 void ForbidCompilation(JSContext *cx, JSScript *script);
 
 void PurgeCaches(JSScript *script);
 size_t SizeOfIonData(JSScript *script, mozilla::MallocSizeOf mallocSizeOf);
 void DestroyJitScripts(FreeOp *fop, JSScript *script);
 void TraceJitScripts(JSTracer* trc, JSScript *script);
 
 bool JitSupportsFloatingPoint();
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -4887,17 +4887,18 @@ IonBuilder::makeInliningDecision(JSObjec
         if (script()->length() >= optimizationInfo().inliningMaxCallerBytecodeLength()) {
             trackOptimizationOutcome(TrackedOutcome::CantInlineBigCaller);
             return DontInline(targetScript, "Vetoed: caller excessively large");
         }
     }
 
     // Callee must not be excessively large.
     // This heuristic also applies to the callsite as a whole.
-    if (targetScript->length() > optimizationInfo().inlineMaxTotalBytecodeLength()) {
+    bool offThread = options.offThreadCompilationAvailable();
+    if (targetScript->length() > optimizationInfo().inlineMaxBytecodePerCallSite(offThread)) {
         trackOptimizationOutcome(TrackedOutcome::CantInlineBigCallee);
         return DontInline(targetScript, "Vetoed: callee excessively large");
     }
 
     // Callee must have been called a few times to have somewhat stable
     // type information, except for definite properties analysis,
     // as the caller has not run yet.
     if (targetScript->getWarmUpCount() < optimizationInfo().inliningWarmUpThreshold() &&
@@ -4954,17 +4955,18 @@ IonBuilder::selectInliningTargets(const 
           default:
             MOZ_CRASH("Unhandled InliningDecision value!");
         }
 
         if (target->is<JSFunction>()) {
             // Enforce a maximum inlined bytecode limit at the callsite.
             if (inlineable && target->as<JSFunction>().isInterpreted()) {
                 totalSize += target->as<JSFunction>().nonLazyScript()->length();
-                if (totalSize > optimizationInfo().inlineMaxTotalBytecodeLength())
+                bool offThread = options.offThreadCompilationAvailable();
+                if (totalSize > optimizationInfo().inlineMaxBytecodePerCallSite(offThread))
                     inlineable = false;
             }
         } else {
             // Non-function targets are not supported by polymorphic inlining.
             inlineable = false;
         }
 
         choiceSet.append(inlineable);
--- a/js/src/jit/IonOptimizationLevels.cpp
+++ b/js/src/jit/IonOptimizationLevels.cpp
@@ -32,17 +32,18 @@ OptimizationInfo::initNormalOptimization
     gvn_ = true;
     licm_ = true;
     rangeAnalysis_ = true;
     loopUnrolling_ = true;
     autoTruncate_ = true;
     sink_ = true;
     registerAllocator_ = RegisterAllocator_Backtracking;
 
-    inlineMaxTotalBytecodeLength_ = 1000;
+    inlineMaxBytecodePerCallSiteMainThread_ = 500;
+    inlineMaxBytecodePerCallSiteOffThread_ = 1000;
     inliningMaxCallerBytecodeLength_ = 10000;
     maxInlineDepth_ = 3;
     scalarReplacement_ = true;
     smallFunctionMaxInlineDepth_ = 10;
     compilerWarmUpThreshold_ = CompilerWarmupThreshold;
     inliningWarmUpThresholdFactor_ = 0.125;
     inliningRecompileThresholdFactor_ = 4;
 }
--- a/js/src/jit/IonOptimizationLevels.h
+++ b/js/src/jit/IonOptimizationLevels.h
@@ -83,18 +83,21 @@ class OptimizationInfo
     bool autoTruncate_;
 
     // Toggles whether sink is used.
     bool sink_;
 
     // Describes which register allocator to use.
     IonRegisterAllocator registerAllocator_;
 
-    // The maximum total bytecode size of an inline call site.
-    uint32_t inlineMaxTotalBytecodeLength_;
+    // The maximum total bytecode size of an inline call site. We use a lower
+    // value if off-thread compilation is not available, to avoid stalling the
+    // main thread.
+    uint32_t inlineMaxBytecodePerCallSiteOffThread_;
+    uint32_t inlineMaxBytecodePerCallSiteMainThread_;
 
     // The maximum bytecode length the caller may have,
     // before we stop inlining large functions in that caller.
     uint32_t inliningMaxCallerBytecodeLength_;
 
     // The maximum inlining depth.
     uint32_t maxInlineDepth_;
 
@@ -204,18 +207,20 @@ class OptimizationInfo
     }
 
     bool isSmallFunction(JSScript *script) const;
 
     uint32_t maxInlineDepth() const {
         return maxInlineDepth_;
     }
 
-    uint32_t inlineMaxTotalBytecodeLength() const {
-        return inlineMaxTotalBytecodeLength_;
+    uint32_t inlineMaxBytecodePerCallSite(bool offThread) const {
+        return (offThread || !js_JitOptions.limitScriptSize)
+               ? inlineMaxBytecodePerCallSiteOffThread_
+               : inlineMaxBytecodePerCallSiteMainThread_;
     }
 
     uint32_t inliningMaxCallerBytecodeLength() const {
         return inliningMaxCallerBytecodeLength_;
     }
 
     uint32_t inliningWarmUpThreshold() const {
         uint32_t compilerWarmUpThreshold = compilerWarmUpThreshold_;