Bug 820012 - unable to debug scripts loaded via loadSubScript in Browser Debugger; r=past
authorEddy Bruel <ejpbruel@mozilla.com>
Thu, 14 Mar 2013 15:21:00 -0700
changeset 124793 b832bfd6fc24a52d5a0488706d62ae5abbd135a3
parent 124792 7cc974e3a6a3a8e3fb08cbef3638e0685d0481c4
child 124794 4b35a698dae2d00f83b6e5bc11ffb421cf409ca6
push id1430
push userpastithas@mozilla.com
push dateFri, 15 Mar 2013 22:12:29 +0000
treeherderfx-team@4b35a698dae2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspast
bugs820012
milestone22.0a1
Bug 820012 - unable to debug scripts loaded via loadSubScript in Browser Debugger; r=past
toolkit/devtools/debugger/server/dbg-script-actors.js
toolkit/devtools/debugger/tests/unit/test_breakpoint-02.js
--- a/toolkit/devtools/debugger/server/dbg-script-actors.js
+++ b/toolkit/devtools/debugger/server/dbg-script-actors.js
@@ -515,115 +515,107 @@ ThreadActor.prototype = {
    * next line that has runnable code. In this case the server breakpoint cache
    * will be updated, so callers that iterate over the breakpoint cache should
    * take that into account.
    *
    * @param object aLocation
    *        The location of the breakpoint as specified in the protocol.
    */
   _setBreakpoint: function TA__setBreakpoint(aLocation) {
-    // Fetch the list of scripts in that url.
-    let scripts = this._scripts[aLocation.url];
-    // Fetch the outermost script in that list.
-    let script = null;
-    for (let i = 0; i <= aLocation.line; i++) {
-      // Stop when the first script that contains this location is found.
-      if (scripts[i]) {
-        // If that first script does not contain the line specified, it's no
-        // good. Note that |i === scripts[i].startLine| in this case, so the
-        // following check makes sure we are not considering a script that does
-        // not include |aLocation.line|.
-        if (i + scripts[i].lineCount < aLocation.line) {
-          continue;
-        }
-        script = scripts[i];
-        break;
-      }
+    let breakpoints = this._breakpointStore[aLocation.url];
+
+    let actor;
+    if (breakpoints[aLocation.line].actor) {
+      actor = breakpoints[aLocation.line].actor;
+    } else {
+      actor = breakpoints[aLocation.line].actor = new BreakpointActor(this, {
+        url: aLocation.url,
+        line: aLocation.line
+      });
+      this._hooks.addToParentPool(actor);
     }
 
-    let location = { url: aLocation.url, line: aLocation.line };
-    // Get the list of cached breakpoints in this URL.
-    let scriptBreakpoints = this._breakpointStore[location.url];
-    let bpActor;
-    if (scriptBreakpoints &&
-        scriptBreakpoints[location.line] &&
-        scriptBreakpoints[location.line].actor) {
-      bpActor = scriptBreakpoints[location.line].actor;
-    }
-    if (!bpActor) {
-      bpActor = new BreakpointActor(this, location);
-      this._hooks.addToParentPool(bpActor);
-      if (scriptBreakpoints[location.line]) {
-        scriptBreakpoints[location.line].actor = bpActor;
-      }
-    }
-
-    if (!script) {
-      return { error: "noScript", actor: bpActor.actorID };
+    let scripts = this.dbg.findScripts(aLocation);
+    if (scripts.length == 0) {
+      return {
+        error: "noScript",
+        actor: actor.actorID
+      };
     }
 
-    let inner, codeFound = false;
-    // We need to set the breakpoint in every script that has bytecode in the
-    // specified line.
-    for (let s of this._getContainers(script, aLocation.line)) {
-      // The first result of the iteration is the innermost script.
-      if (!inner) {
-        inner = s;
-      }
-
-      let offsets = s.getLineOffsets(aLocation.line);
-      if (offsets.length) {
-        bpActor.addScript(s, this);
-        for (let i = 0; i < offsets.length; i++) {
-          s.setBreakpoint(offsets[i], bpActor);
-          codeFound = true;
+    let found = false;
+    for (let script of scripts) {
+      let offsets = script.getLineOffsets(aLocation.line);
+      if (offsets.length > 0) {
+        for (let offset of offsets) {
+          script.setBreakpoint(offset, actor);
         }
+        actor.addScript(script, this);
+        found = true;
       }
     }
+    if (found) {
+      return {
+        actor: actor.actorID
+      };
+    }
+
+    let scripts = this.dbg.findScripts({
+      url: aLocation.url,
+      line: aLocation.line,
+      innermost: true
+    });
 
     let actualLocation;
-    if (!codeFound) {
-      // No code at that line in any script, skipping forward in the innermost
-      // script.
-      let lines = inner.getAllOffsets();
-      let oldLine = aLocation.line;
-      for (let line = oldLine; line < lines.length; ++line) {
-        if (lines[line]) {
-          for (let i = 0; i < lines[line].length; i++) {
-            inner.setBreakpoint(lines[line][i], bpActor);
-            codeFound = true;
+    let found = false;
+    for (let script of scripts) {
+      let offsets = script.getAllOffsets();
+      for (let line = aLocation.line; line < offsets.length; ++line) {
+        if (offsets[line]) {
+          for (let offset of offsets[line]) {
+            script.setBreakpoint(offset, actor);
           }
-          bpActor.addScript(inner, this);
-          actualLocation = {
-            url: aLocation.url,
-            line: line,
-            column: aLocation.column
-          };
-          // If there wasn't already a breakpoint at that line, update the cache
-          // as well.
-          if (scriptBreakpoints[line] && scriptBreakpoints[line].actor) {
-            let existing = scriptBreakpoints[line].actor;
-            bpActor.onDelete();
-            delete scriptBreakpoints[oldLine];
-            return { actor: existing.actorID, actualLocation: actualLocation };
+          actor.addScript(script, this);
+          if (!actualLocation) {
+            actualLocation = {
+              url: aLocation.url,
+              line: line,
+              column: aLocation.column
+            };
           }
-          bpActor.location = actualLocation;
-          scriptBreakpoints[line] = scriptBreakpoints[oldLine];
-          scriptBreakpoints[line].line = line;
-          delete scriptBreakpoints[oldLine];
+          found = true;
           break;
         }
       }
     }
-
-    if (!codeFound) {
-      return  { error: "noCodeAtLineColumn", actor: bpActor.actorID };
+    if (found) {
+      if (breakpoints[actualLocation.line] &&
+          breakpoints[actualLocation.line].actor) {
+        actor.onDelete();
+        delete breakpoints[aLocation.line];
+        return {
+          actor: breakpoints[actualLocation.line].actor.actorID,
+          actualLocation: actualLocation
+        };
+      } else {
+        actor.location = actualLocation;
+        breakpoints[actualLocation.line] = breakpoints[aLocation.line];
+        breakpoints[actualLocation.line].line = actualLocation.line;
+        delete breakpoints[aLocation.line];
+        return {
+          actor: actor.actorID,
+          actualLocation: actualLocation
+        };
+      }
     }
 
-    return { actor: bpActor.actorID, actualLocation: actualLocation };
+    return {
+      error: "noCodeAtLineColumn",
+      actor: actor.actorID
+    };
   },
 
   /**
    * A recursive generator function for iterating over the scripts that contain
    * the specified line, by looking through child scripts of the supplied
    * script. As an example, an inline <script> tag has the top-level functions
    * declared in it as its children.
    *
--- a/toolkit/devtools/debugger/tests/unit/test_breakpoint-02.js
+++ b/toolkit/devtools/debugger/tests/unit/test_breakpoint-02.js
@@ -22,31 +22,31 @@ function run_test()
       test_breakpoint_running();
     });
   });
   do_test_pending();
 }
 
 function test_breakpoint_running()
 {
-  let path = getFilePath('test_breakpoint-02.js');
-  let location = { url: path, line: gDebuggee.line0 + 2};
-
   gDebuggee.eval("var line0 = Error().lineNumber;\n" +
                  "var a = 1;\n" +  // line0 + 1
                  "var b = 2;\n");  // line0 + 2
 
+  let path = getFilePath('test_breakpoint-02.js');
+  let location = { url: path, line: gDebuggee.line0 + 2};
+
   // Setting the breakpoint later should interrupt the debuggee.
   gThreadClient.addOneTimeListener("paused", function (aEvent, aPacket) {
     do_check_eq(aPacket.type, "paused");
     do_check_eq(aPacket.why.type, "interrupted");
   });
 
   gThreadClient.setBreakpoint(location, function(aResponse) {
     // Eval scripts don't stick around long enough for the breakpoint to be set,
     // so just make sure we got the expected response from the actor.
-    do_check_eq(aResponse.error, "noScript");
+    do_check_neq(aResponse.error, "noScript");
 
     do_execute_soon(function() {
       finishClient(gClient);
     });
   });
 }