Commit 338e8c0c authored by Jon Coppeard's avatar Jon Coppeard
Browse files

Bug 1672760 - Add an API to wait for parse tasks to complete without cancelling them r=sfink

The problem here was cancelling parse tasks without the browser's knowledge (I
didn't realise that the cancel method did anything beyond waiting).

Differential Revision: https://phabricator.services.mozilla.com/D94819
parent 891cb2a2
Loading
Loading
Loading
Loading
+23 −17
Original line number Diff line number Diff line
@@ -879,24 +879,12 @@ void MultiScriptsDecodeTask::parse(JSContext* cx) {
  }
}

void js::CancelOffThreadParses(JSRuntime* rt) {
  AutoLockHelperThreadState lock;

static void WaitForOffThreadParses(JSRuntime* rt,
                                   AutoLockHelperThreadState& lock) {
  if (HelperThreadState().threads(lock).empty()) {
    return;
  }

#ifdef DEBUG
  GlobalHelperThreadState::ParseTaskVector& waitingOnGC =
      HelperThreadState().parseWaitingOnGC(lock);
  for (size_t i = 0; i < waitingOnGC.length(); i++) {
    MOZ_ASSERT(!waitingOnGC[i]->runtimeMatches(rt));
  }
#endif

  // Instead of forcibly canceling pending parse tasks, just wait for all
  // scheduled and in progress ones to complete. Otherwise the final GC may not
  // collect everything due to zones being used off thread.
  while (true) {
    bool pending = false;
    GlobalHelperThreadState::ParseTaskVector& worklist =
@@ -923,6 +911,26 @@ void js::CancelOffThreadParses(JSRuntime* rt) {
    }
    HelperThreadState().wait(lock, GlobalHelperThreadState::CONSUMER);
  }
}

void js::WaitForOffThreadParses(JSRuntime* rt) {
  AutoLockHelperThreadState lock;
  WaitForOffThreadParses(rt, lock);
}

void js::CancelOffThreadParses(JSRuntime* rt) {
  AutoLockHelperThreadState lock;

#ifdef DEBUG
  for (const auto& task : HelperThreadState().parseWaitingOnGC(lock)) {
    MOZ_ASSERT(!task->runtimeMatches(rt));
  }
#endif

  // Instead of forcibly canceling pending parse tasks, just wait for all
  // scheduled and in progress ones to complete. Otherwise the final GC may not
  // collect everything due to zones being used off thread.
  WaitForOffThreadParses(rt, lock);

  // Clean up any parse tasks which haven't been finished by the main thread.
  auto& finished = HelperThreadState().parseFinishedList(lock);
@@ -945,9 +953,7 @@ void js::CancelOffThreadParses(JSRuntime* rt) {
  }

#ifdef DEBUG
  GlobalHelperThreadState::ParseTaskVector& worklist =
      HelperThreadState().parseWorklist(lock);
  for (const auto& task : worklist) {
  for (const auto& task : HelperThreadState().parseWorklist(lock)) {
    MOZ_ASSERT(!task->runtimeMatches(rt));
  }
#endif
+6 −0
Original line number Diff line number Diff line
@@ -177,6 +177,12 @@ inline void CancelOffThreadIonCompilesUsingNurseryPointers(JSRuntime* runtime) {
bool HasOffThreadIonCompile(JS::Realm* realm);
#endif

/*
 * Wait for all scheduled, in progress or finished parse tasks for the runtime
 * to complete.
 */
void WaitForOffThreadParses(JSRuntime* runtime);

/* Cancel all scheduled, in progress or finished parses for runtime. */
void CancelOffThreadParses(JSRuntime* runtime);

+1 −1
Original line number Diff line number Diff line
@@ -625,7 +625,7 @@ static bool CollectRuntimeStatsHelper(JSContext* cx, RuntimeStats* rtStats,
  // Wait for any off-thread parsing to finish, as that currently allocates GC
  // things.
  JSRuntime* rt = cx->runtime();
  CancelOffThreadParses(rt);
  WaitForOffThreadParses(rt);

  // Finish any ongoing incremental GC that may change the data we're gathering
  // and ensure that we don't do anything that could start another one.