Bug 1383467 - Only cancel Ion compilations that use nursery pointers when performing a minor GC, r=jonco.
authorBrian Hackett <bhackett1024@gmail.com>
Mon, 24 Jul 2017 07:34:40 -0600
changeset 419447 09632f4493ef526bbbcda486cf18bd06188e8a89
parent 419446 a9c11adcdfc7bada2745817f159cb23a7d65be5c
child 419448 4be5c2ff3c1ea1d28469dc472b0189adeafe0014
push id7566
push usermtabara@mozilla.com
push dateWed, 02 Aug 2017 08:25:16 +0000
treeherdermozilla-beta@86913f512c3c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjonco
bugs1383467
milestone56.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 1383467 - Only cancel Ion compilations that use nursery pointers when performing a minor GC, r=jonco.
js/src/gc/Nursery.cpp
js/src/vm/HelperThreads.cpp
js/src/vm/HelperThreads.h
--- a/js/src/gc/Nursery.cpp
+++ b/js/src/gc/Nursery.cpp
@@ -696,20 +696,21 @@ js::Nursery::doCollection(JS::gcreason::
 
     // Move objects pointed to by roots from the nursery to the major heap.
     TenuringTracer mover(rt, this);
 
     // Mark the store buffer. This must happen first.
     StoreBuffer& sb = runtime()->gc.storeBuffer();
 
     // The MIR graph only contains nursery pointers if cancelIonCompilations()
-    // is set on the store buffer, in which case we cancel all compilations.
+    // is set on the store buffer, in which case we cancel all compilations
+    // of such graphs.
     startProfile(ProfileKey::CancelIonCompilations);
     if (sb.cancelIonCompilations())
-        js::CancelOffThreadIonCompile(rt);
+        js::CancelOffThreadIonCompilesUsingNurseryPointers(rt);
     endProfile(ProfileKey::CancelIonCompilations);
 
     startProfile(ProfileKey::TraceValues);
     sb.traceValues(mover);
     endProfile(ProfileKey::TraceValues);
 
     startProfile(ProfileKey::TraceCells);
     sb.traceCells(mover);
--- a/js/src/vm/HelperThreads.cpp
+++ b/js/src/vm/HelperThreads.cpp
@@ -143,54 +143,60 @@ GetSelectorRuntime(const CompilationSele
 {
     struct Matcher
     {
         JSRuntime* match(JSScript* script)    { return script->runtimeFromActiveCooperatingThread(); }
         JSRuntime* match(JSCompartment* comp) { return comp->runtimeFromActiveCooperatingThread(); }
         JSRuntime* match(ZonesInState zbs)    { return zbs.runtime; }
         JSRuntime* match(JSRuntime* runtime)  { return runtime; }
         JSRuntime* match(AllCompilations all) { return nullptr; }
+        JSRuntime* match(CompilationsUsingNursery cun) { return cun.runtime; }
     };
 
     return selector.match(Matcher());
 }
 
 static bool
 JitDataStructuresExist(const CompilationSelector& selector)
 {
     struct Matcher
     {
         bool match(JSScript* script)    { return !!script->compartment()->jitCompartment(); }
         bool match(JSCompartment* comp) { return !!comp->jitCompartment(); }
         bool match(ZonesInState zbs)    { return zbs.runtime->hasJitRuntime(); }
         bool match(JSRuntime* runtime)  { return runtime->hasJitRuntime(); }
         bool match(AllCompilations all) { return true; }
+        bool match(CompilationsUsingNursery cun) { return cun.runtime->hasJitRuntime(); }
     };
 
     return selector.match(Matcher());
 }
 
 static bool
-CompiledScriptMatches(const CompilationSelector& selector, JSScript* target)
+IonBuilderMatches(const CompilationSelector& selector, jit::IonBuilder* builder)
 {
-    struct ScriptMatches
+    struct BuilderMatches
     {
-        JSScript* target_;
+        jit::IonBuilder* builder_;
 
-        bool match(JSScript* script)    { return script == target_; }
-        bool match(JSCompartment* comp) { return comp == target_->compartment(); }
-        bool match(JSRuntime* runtime)  { return runtime == target_->runtimeFromAnyThread(); }
+        bool match(JSScript* script)    { return script == builder_->script(); }
+        bool match(JSCompartment* comp) { return comp == builder_->script()->compartment(); }
+        bool match(JSRuntime* runtime)  { return runtime == builder_->script()->runtimeFromAnyThread(); }
         bool match(AllCompilations all) { return true; }
         bool match(ZonesInState zbs)    {
-            return zbs.runtime == target_->runtimeFromAnyThread() &&
-                   zbs.state == target_->zoneFromAnyThread()->gcState();
+            return zbs.runtime == builder_->script()->runtimeFromAnyThread() &&
+                   zbs.state == builder_->script()->zoneFromAnyThread()->gcState();
+        }
+        bool match(CompilationsUsingNursery cun) {
+            return cun.runtime == builder_->script()->runtimeFromAnyThread() &&
+                   !builder_->safeForMinorGC();
         }
     };
 
-    return selector.match(ScriptMatches{target});
+    return selector.match(BuilderMatches{builder});
 }
 
 void
 js::CancelOffThreadIonCompile(const CompilationSelector& selector, bool discardLazyLinkList)
 {
     if (!JitDataStructuresExist(selector))
         return;
 
@@ -198,30 +204,30 @@ js::CancelOffThreadIonCompile(const Comp
 
     if (!HelperThreadState().threads)
         return;
 
     /* Cancel any pending entries for which processing hasn't started. */
     GlobalHelperThreadState::IonBuilderVector& worklist = HelperThreadState().ionWorklist(lock);
     for (size_t i = 0; i < worklist.length(); i++) {
         jit::IonBuilder* builder = worklist[i];
-        if (CompiledScriptMatches(selector, builder->script())) {
+        if (IonBuilderMatches(selector, builder)) {
             FinishOffThreadIonCompile(builder, lock);
             HelperThreadState().remove(worklist, &i);
         }
     }
 
     /* Wait for in progress entries to finish up. */
     bool cancelled;
     do {
         cancelled = false;
         bool unpaused = false;
         for (auto& helper : *HelperThreadState().threads) {
             if (helper.ionBuilder() &&
-                CompiledScriptMatches(selector, helper.ionBuilder()->script()))
+                IonBuilderMatches(selector, helper.ionBuilder()))
             {
                 helper.ionBuilder()->cancel();
                 if (helper.pause) {
                     helper.pause = false;
                     unpaused = true;
                 }
                 cancelled = true;
             }
@@ -231,32 +237,32 @@ js::CancelOffThreadIonCompile(const Comp
         if (cancelled)
             HelperThreadState().wait(lock, GlobalHelperThreadState::CONSUMER);
     } while (cancelled);
 
     /* Cancel code generation for any completed entries. */
     GlobalHelperThreadState::IonBuilderVector& finished = HelperThreadState().ionFinishedList(lock);
     for (size_t i = 0; i < finished.length(); i++) {
         jit::IonBuilder* builder = finished[i];
-        if (CompiledScriptMatches(selector, builder->script())) {
+        if (IonBuilderMatches(selector, builder)) {
             builder->script()->zone()->group()->numFinishedBuilders--;
             jit::FinishOffThreadBuilder(nullptr, builder, lock);
             HelperThreadState().remove(finished, &i);
         }
     }
 
     /* Cancel lazy linking for pending builders (attached to the ionScript). */
     if (discardLazyLinkList) {
         MOZ_ASSERT(!selector.is<AllCompilations>());
         JSRuntime* runtime = GetSelectorRuntime(selector);
         for (ZoneGroupsIter group(runtime); !group.done(); group.next()) {
             jit::IonBuilder* builder = group->ionLazyLinkList().getFirst();
             while (builder) {
                 jit::IonBuilder* next = builder->getNext();
-                if (CompiledScriptMatches(selector, builder->script()))
+                if (IonBuilderMatches(selector, builder))
                     jit::FinishOffThreadBuilder(runtime, builder, lock);
                 builder = next;
             }
         }
     }
 }
 
 #ifdef DEBUG
--- a/js/src/vm/HelperThreads.h
+++ b/js/src/vm/HelperThreads.h
@@ -489,21 +489,23 @@ StartOffThreadIonCompile(JSContext* cx, 
 /*
  * Schedule deletion of Ion compilation data.
  */
 bool
 StartOffThreadIonFree(jit::IonBuilder* builder, const AutoLockHelperThreadState& lock);
 
 struct AllCompilations {};
 struct ZonesInState { JSRuntime* runtime; JS::Zone::GCState state; };
+struct CompilationsUsingNursery { JSRuntime* runtime; };
 
 using CompilationSelector = mozilla::Variant<JSScript*,
                                              JSCompartment*,
                                              ZonesInState,
                                              JSRuntime*,
+                                             CompilationsUsingNursery,
                                              AllCompilations>;
 
 /*
  * Cancel scheduled or in progress Ion compilations.
  */
 void
 CancelOffThreadIonCompile(const CompilationSelector& selector, bool discardLazyLinkList);
 
@@ -527,16 +529,22 @@ CancelOffThreadIonCompile(JSRuntime* run
 
 inline void
 CancelOffThreadIonCompile(JSRuntime* runtime)
 {
     CancelOffThreadIonCompile(CompilationSelector(runtime), true);
 }
 
 inline void
+CancelOffThreadIonCompilesUsingNurseryPointers(JSRuntime* runtime)
+{
+    CancelOffThreadIonCompile(CompilationSelector(CompilationsUsingNursery{runtime}), true);
+}
+
+inline void
 CancelOffThreadIonCompile()
 {
     CancelOffThreadIonCompile(CompilationSelector(AllCompilations()), false);
 }
 
 #ifdef DEBUG
 bool
 HasOffThreadIonCompile(JSCompartment* comp);