Bug 1774937 - [devtools] Fix breaking on slow scripts. r=jdescottes
authorAlexandre Poirot <poirot.alex@gmail.com>
Thu, 30 Jun 2022 17:18:54 +0000
changeset 622739 a472404e52f7ce605f6d7ba9d66bc3728529c77d
parent 622738 39fe8edd4b83dc3e9b784db22ef8b74179ff21e3
child 622740 a545a227cec13b94a14cd1ce2f0b6f7ee5b8fcbb
push id165545
push userapoirot@mozilla.com
push dateThu, 30 Jun 2022 17:21:31 +0000
treeherderautoland@a545a227cec1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjdescottes
bugs1774937
milestone104.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 1774937 - [devtools] Fix breaking on slow scripts. r=jdescottes We weren't waiting for interrupt to have fully paused the thread before trying to resume when the state was "attached". Differential Revision: https://phabricator.services.mozilla.com/D150154
devtools/client/debugger/test/mochitest/browser.ini
devtools/client/debugger/test/mochitest/browser_dbg-slow-script.js
devtools/client/debugger/test/mochitest/examples/doc-slow-script.html
devtools/client/framework/devtools-browser.js
--- a/devtools/client/debugger/test/mochitest/browser.ini
+++ b/devtools/client/debugger/test/mochitest/browser.ini
@@ -264,8 +264,9 @@ skip-if =
 skip-if = asan || !nightly_build || fission # Bug 1591064, parent intercept mode is needed bug 1588154, Disable frequent fission intermittents Bug 1675020
 [browser_dbg-wrong-fetch.js]
 [browser_dbg-worker-nested.js]
 [browser_dbg-step-in-navigate.js]
 [browser_dbg-settings-disable-javascript.js]
 [browser_dbg-restart-frame.js]
 [browser_dbg-many-breakpoints-same-line.js]
 [browser_dbg-unselected-pause.js]
+[browser_dbg-slow-script.js]
new file mode 100644
--- /dev/null
+++ b/devtools/client/debugger/test/mochitest/browser_dbg-slow-script.js
@@ -0,0 +1,41 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
+
+"use strict";
+
+// Tests the slow script warning
+
+add_task(async function openDebuggerFirst() {
+  // In mochitest, the timeout is disable, so set it to a short, but non zero duration
+  await pushPref("dom.max_script_run_time", 1);
+  // Prevents having to click on the page to have the dialog to appear
+  await pushPref("dom.max_script_run_time.require_critical_input", false);
+
+  const dbg = await initDebugger("doc-slow-script.html");
+
+  const alert = BrowserTestUtils.waitForGlobalNotificationBar(
+    window,
+    "process-hang"
+  );
+
+  info("Execute an infinite loop");
+  invokeInTab("infiniteLoop");
+
+  info("Wait for the slow script warning");
+  const notification = await alert;
+
+  info("Click on the debug script button");
+  const buttons = notification.buttonContainer.getElementsByTagName("button");
+  // The first button is "stop", the second is "debug script"
+  buttons[1].click();
+
+  info("Waiting for the debugger to be paused");
+  await waitForPaused(dbg);
+  const source = findSource(dbg, "doc-slow-script.html");
+  assertPausedAtSourceAndLine(dbg, source.id, 14);
+
+  info("Close toolbox and tab");
+  await dbg.toolbox.closeToolbox();
+  await removeTab(gBrowser.selectedTab);
+});
new file mode 100644
--- /dev/null
+++ b/devtools/client/debugger/test/mochitest/examples/doc-slow-script.html
@@ -0,0 +1,18 @@
+ <!-- This Source Code Form is subject to the terms of the Mozilla Public
+    - License, v. 2.0. If a copy of the MPL was not distributed with this
+    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8"/>
+    <title>Test page with an infinite loop</title>
+  </head>
+
+  <body>
+    <script>
+      function infiniteLoop() {
+        while(true) {}
+      }
+    </script>
+  </body>
+</html>
--- a/devtools/client/framework/devtools-browser.js
+++ b/devtools/client/framework/devtools-browser.js
@@ -470,52 +470,49 @@ var gDevToolsBrowser = (exports.gDevTool
    * dialog.
    */
   setSlowScriptDebugHandler() {
     const debugService = Cc["@mozilla.org/dom/slow-script-debug;1"].getService(
       Ci.nsISlowScriptDebug
     );
 
     async function slowScriptDebugHandler(tab, callback) {
-      gDevTools
-        .showToolboxForTab(tab, { toolId: "jsdebugger" })
-        .then(toolbox => {
-          const threadFront = toolbox.threadFront;
+      const toolbox = await gDevTools.showToolboxForTab(tab, {
+        toolId: "jsdebugger",
+      });
+      const threadFront = toolbox.threadFront;
 
-          // Break in place, which means resuming the debuggee thread and pausing
-          // right before the next step happens.
-          switch (threadFront.state) {
-            case "paused":
-              // When the debugger is already paused.
-              threadFront.resumeThenPause();
-              callback();
-              break;
-            case "attached":
-              // When the debugger is already open.
-              threadFront.interrupt().then(() => {
-                threadFront.resumeThenPause();
-                callback();
-              });
-              break;
-            case "resuming":
-              // The debugger is newly opened.
-              threadFront.once("resumed", () => {
-                threadFront.interrupt().then(() => {
-                  threadFront.resumeThenPause();
-                  callback();
-                });
-              });
-              break;
-            default:
-              throw Error(
-                "invalid thread front state in slow script debug handler: " +
-                  threadFront.state
-              );
-          }
-        });
+      // Break in place, which means resuming the debuggee thread and pausing
+      // right before the next step happens.
+      switch (threadFront.state) {
+        case "paused":
+          // When the debugger is already paused.
+          threadFront.resumeThenPause();
+          break;
+        case "attached":
+          // When the debugger is already open.
+          const onPaused = threadFront.once("paused");
+          threadFront.interrupt();
+          await onPaused;
+          threadFront.resumeThenPause();
+          break;
+        case "resuming":
+          // The debugger is newly opened.
+          const onResumed = threadFront.once("resumed");
+          await threadFront.interrupt();
+          await onResumed;
+          threadFront.resumeThenPause();
+          break;
+        default:
+          throw Error(
+            "invalid thread front state in slow script debug handler: " +
+              threadFront.state
+          );
+      }
+      callback();
     }
 
     debugService.activationHandler = function(window) {
       const chromeWindow = window.browsingContext.topChromeWindow;
 
       let setupFinished = false;
       slowScriptDebugHandler(chromeWindow.gBrowser.selectedTab, () => {
         setupFinished = true;