Bug 1575071 - Add onPop handlers to blackboxed frames r=jlast
authorwartmanm <wartmanm@tutanota.com>
Thu, 02 Jan 2020 18:42:46 +0000
changeset 508629 e954fcf487195136c45423a5a6a079d69a7db630
parent 508628 7d0cec2c6c40d070d643112bc348e632d19d4cc8
child 508630 acc8cae5b23f98ed8189ac1688ccd4e04bb3c755
push id36974
push userncsoregi@mozilla.com
push dateFri, 03 Jan 2020 03:58:21 +0000
treeherdermozilla-central@4d34e06619ed [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjlast
bugs1575071
milestone73.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 1575071 - Add onPop handlers to blackboxed frames r=jlast Differential Revision: https://phabricator.services.mozilla.com/D57203
devtools/server/actors/thread.js
devtools/server/tests/unit/test_stepping-15.js
devtools/server/tests/unit/test_stepping-16.js
devtools/server/tests/unit/xpcshell.ini
--- a/devtools/server/actors/thread.js
+++ b/devtools/server/actors/thread.js
@@ -889,25 +889,21 @@ const ThreadActor = ActorClassWithSpec(t
       // onPop is called when we temporarily leave an async/generator
       if (completion.await || completion.yield) {
         thread.suspendedFrame = this;
         this.waitingOnStep = true;
         thread.dbg.onEnterFrame = undefined;
         return undefined;
       }
 
-      if (thread.sources.isFrameBlackBoxed(this)) {
-        return undefined;
-      }
-
       // Note that we're popping this frame; we need to watch for
       // subsequent step events on its caller.
       this.reportedPop = true;
 
-      if (steppingType != "finish") {
+      if (steppingType != "finish" && !thread.sources.isFrameBlackBoxed(this)) {
         return pauseAndRespond(this, packet =>
           thread.createCompletionGrip(packet, completion)
         );
       }
 
       const parentFrame = thread._getNextStepFrame(this);
       if (parentFrame && parentFrame.script) {
         const { onStep, onPop } = thread._makeSteppingHooks({
@@ -988,17 +984,17 @@ const ThreadActor = ActorClassWithSpec(t
     };
   },
 
   _validFrameStepOffset: function(frame, startFrame, offset) {
     const meta = frame.script.getOffsetMetadata(offset);
 
     // Continue if:
     // 1. the location is not a valid breakpoint position
-    // 2. the source is not blackboxed
+    // 2. the source is blackboxed
     // 3. we have not moved since the last pause
     if (
       !meta.isBreakpoint ||
       this.sources.isFrameBlackBoxed(frame) ||
       !this.hasMoved(frame)
     ) {
       return false;
     }
new file mode 100644
--- /dev/null
+++ b/devtools/server/tests/unit/test_stepping-15.js
@@ -0,0 +1,79 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+/**
+ * Test stepping from inside a blackboxed function
+ * test-page: https://dbg-blackbox-stepping.glitch.me/
+ */
+
+async function invokeAndPause({ global, threadFront }, expression, url) {
+  return executeOnNextTickAndWaitForPause(
+    () => Cu.evalInSandbox(expression, global, "1.8", url, 1),
+    threadFront
+  );
+}
+add_task(
+  threadFrontTest(async ({ threadFront, targetFront, debuggee }) => {
+    const consoleFront = await targetFront.getFront("console");
+    const dbg = { global: debuggee, threadFront };
+
+    // Test stepping from a blackboxed location
+    async function testStepping(action, expectedLine) {
+      consoleFront.evaluateJSAsync(`outermost()`);
+      await waitForPause(threadFront);
+      await blackBox(blackboxedSourceFront);
+      const packet = await action(threadFront);
+      const { line, actor } = packet.frame.where;
+      equal(actor, unblackboxedActor, "paused in unblackboxed source");
+      equal(line, expectedLine, "paused at correct line");
+      await threadFront.resume();
+      await unBlackBox(blackboxedSourceFront);
+    }
+
+    invokeAndPause(
+      dbg,
+      `function outermost() {
+        const value = blackboxed1();
+        return value + 1;
+      }
+      function innermost() {
+        return 1;
+      }`,
+      "http://example.com/unblackboxed.js"
+    );
+    invokeAndPause(
+      dbg,
+      `function blackboxed1() {
+        return blackboxed2();
+      }
+      function blackboxed2() {
+        return innermost();
+      }`,
+      "http://example.com/blackboxed.js"
+    );
+
+    const { sources } = await getSources(threadFront);
+    const blackboxedSourceFront = threadFront.source(
+      sources.find(source => source.url == "http://example.com/blackboxed.js")
+    );
+    const unblackboxedActor = sources.find(
+      source => source.url == "http://example.com/unblackboxed.js"
+    ).actor;
+
+    await setBreakpoint(threadFront, {
+      sourceUrl: blackboxedSourceFront.url,
+      line: 5,
+    });
+
+    info("Step Out to outermost");
+    await testStepping(stepOut, 3);
+
+    info("Step Over to outermost");
+    await testStepping(stepOver, 3);
+
+    info("Step In to innermost");
+    await testStepping(stepIn, 6);
+  })
+);
new file mode 100644
--- /dev/null
+++ b/devtools/server/tests/unit/test_stepping-16.js
@@ -0,0 +1,82 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+/**
+ * Test stepping from inside a blackboxed function
+ * test-page: https://dbg-blackbox-stepping2.glitch.me/
+ */
+
+async function invokeAndPause({ global, threadFront }, expression, url) {
+  return executeOnNextTickAndWaitForPause(
+    () => Cu.evalInSandbox(expression, global, "1.8", url, 1),
+    threadFront
+  );
+}
+
+add_task(
+  threadFrontTest(async ({ threadFront, targetFront, debuggee }) => {
+    const consoleFront = await targetFront.getFront("console");
+    const dbg = { global: debuggee, threadFront, consoleFront };
+    invokeAndPause(
+      dbg,
+      `function outermost() {
+        blackboxed(
+          function inner1() {
+            return 1;
+          },
+          function inner2() {
+            return 2;
+          }
+        );
+      }`,
+      "http://example.com/unblackboxed.js"
+    );
+    invokeAndPause(
+      dbg,
+      `function blackboxed(...args) {
+        for (const arg of args) {
+          arg();
+        }
+      }`,
+      "http://example.com/blackboxed.js"
+    );
+
+    const { sources } = await getSources(threadFront);
+    const blackboxedSourceFront = threadFront.source(
+      sources.find(source => source.url == "http://example.com/blackboxed.js")
+    );
+    const unblackboxedSource = sources.find(
+      source => source.url == "http://example.com/unblackboxed.js"
+    );
+    const unblackboxedActor = unblackboxedSource.actor;
+    const unblackboxedSourceFront = threadFront.source(unblackboxedSource);
+
+    await setBreakpoint(threadFront, {
+      sourceUrl: unblackboxedSourceFront.url,
+      line: 4,
+    });
+    blackBox(blackboxedSourceFront);
+
+    async function testStepping(action, expectedLine) {
+      consoleFront.evaluateJSAsync("outermost()");
+      await waitForPause(threadFront);
+      await stepOver(threadFront);
+      const packet = await action(threadFront);
+      const { actor, line } = packet.frame.where;
+      equal(actor, unblackboxedActor, "Paused in unblackboxed source");
+      equal(line, expectedLine, "Paused at correct line");
+      await threadFront.resume();
+    }
+
+    info("Step Out to outermost");
+    await testStepping(stepOut, 10);
+
+    info("Step Over to outermost");
+    await testStepping(stepOver, 10);
+
+    info("Step In to inner2");
+    await testStepping(stepIn, 7);
+  })
+);
--- a/devtools/server/tests/unit/xpcshell.ini
+++ b/devtools/server/tests/unit/xpcshell.ini
@@ -181,16 +181,18 @@ skip-if = true # breakpoint sliding is n
 [test_stepping-07.js]
 [test_stepping-08.js]
 [test_stepping-09.js]
 [test_stepping-10.js]
 [test_stepping-11.js]
 [test_stepping-12.js]
 [test_stepping-13.js]
 [test_stepping-14.js]
+[test_stepping-15.js]
+[test_stepping-16.js]
 [test_stepping-with-skip-breakpoints.js]
 [test_framebindings-01.js]
 [test_framebindings-02.js]
 [test_framebindings-03.js]
 [test_framebindings-04.js]
 [test_framebindings-05.js]
 [test_framebindings-06.js]
 [test_framebindings-07.js]