Bug 852792 - load sources from the sourcesContent field in a source map, if available; r=robcee
☠☠ backed out by b80fd5c9f47a ☠ ☠
authorNick Fitzgerald <nfitzgerald@mozilla.com>
Sat, 11 May 2013 10:22:36 +0100
changeset 142520 6ebf2274acf584eaa18252c7f399f134497ae6cf
parent 142519 781650c07e8c30d32f4510d04d55a85757479d78
child 142521 752dca088d7191495c86a495b3efebcbde74cfec
push id2579
push userakeybl@mozilla.com
push dateMon, 24 Jun 2013 18:52:47 +0000
treeherdermozilla-beta@b69b7de8a05a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersrobcee
bugs852792
milestone23.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 852792 - load sources from the sourcesContent field in a source map, if available; r=robcee
toolkit/devtools/debugger/server/dbg-script-actors.js
toolkit/devtools/debugger/tests/unit/test_sourcemaps-06.js
toolkit/devtools/debugger/tests/unit/xpcshell.ini
--- a/toolkit/devtools/debugger/server/dbg-script-actors.js
+++ b/toolkit/devtools/debugger/server/dbg-script-actors.js
@@ -1376,20 +1376,23 @@ PauseScopedActor.prototype = {
 
 /**
  * A SourceActor provides information about the source of a script.
  *
  * @param aUrl String
  *        The url of the source we are representing.
  * @param aThreadActor ThreadActor
  *        The current thread actor.
+ * @param aSourceContent String
+ *        Optional. The contents of the source, if we already know it.
  */
-function SourceActor(aUrl, aThreadActor) {
+function SourceActor(aUrl, aThreadActor, aSourceContent=null) {
   this._threadActor = aThreadActor;
   this._url = aUrl;
+  this._sourceContent = aSourceContent;
 }
 
 SourceActor.prototype = {
   constructor: SourceActor,
   actorPrefix: "source",
 
   get threadActor() this._threadActor,
   get url() this._url,
@@ -1407,16 +1410,24 @@ SourceActor.prototype = {
       delete this.registeredPool.sourceActors[this.actorID];
     }
   },
 
   /**
    * Handler for the "source" packet.
    */
   onSource: function SA_onSource(aRequest) {
+    if (this._sourceContent) {
+      return {
+        from: this.actorID,
+        source: this.threadActor.createValueGrip(
+          this._sourceContent, this.threadActor.threadLifetimePool)
+      };
+    }
+
     return fetch(this._url)
       .then(function(aSource) {
         return this.threadActor.createValueGrip(
           aSource, this.threadActor.threadLifetimePool);
       }.bind(this))
       .then(function (aSourceGrip) {
         return {
           from: this.actorID,
@@ -2426,29 +2437,32 @@ function ThreadSources(aThreadActor, aUs
 
 ThreadSources.prototype = {
   /**
    * Add a source to the current set of sources.
    *
    * Right now this takes a URL, but in the future it should
    * take a Debugger.Source. See bug 637572.
    *
-   * @param string the source URL.
+   * @param String aURL
+   *        The source URL.
+   * @param String aSourceContent
+   *        Optional. The content of the source, if we already know it.
    * @returns a SourceActor representing the source or null.
    */
-  source: function TS_source(aURL) {
+  source: function TS_source(aURL, aSourceContent=null) {
     if (!this._allow(aURL)) {
       return null;
     }
 
     if (aURL in this._sourceActors) {
       return this._sourceActors[aURL];
     }
 
-    let actor = new SourceActor(aURL, this._thread);
+    let actor = new SourceActor(aURL, this._thread, aSourceContent);
     this._thread.threadLifetimePool.addActor(actor);
     this._sourceActors[aURL] = actor;
     try {
       this._onNewSource(actor);
     } catch (e) {
       reportError(e);
     }
     return actor;
@@ -2460,17 +2474,18 @@ ThreadSources.prototype = {
   sourcesForScript: function TS_sourcesForScript(aScript) {
     if (!this._useSourceMaps || !aScript.sourceMapURL) {
       return resolve([this.source(aScript.url)].filter(isNotNull));
     }
 
     return this.sourceMap(aScript)
       .then((aSourceMap) => {
         return [
-          this.source(s) for (s of aSourceMap.sources)
+          this.source(s, aSourceMap.sourceContentFor(s))
+          for (s of aSourceMap.sources)
         ];
       }, (e) => {
         reportError(e);
         delete this._sourceMaps[this._normalize(aScript.sourceMapURL, aScript.url)];
         delete this._sourceMapsByGeneratedSource[aScript.url];
         return [this.source(aScript.url)];
       })
       .then(function (aSources) {
new file mode 100644
--- /dev/null
+++ b/toolkit/devtools/debugger/tests/unit/test_sourcemaps-06.js
@@ -0,0 +1,86 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Check that we can load sources whose content is embedded in the
+ * "sourcesContent" field of a source map.
+ */
+
+var gDebuggee;
+var gClient;
+var gThreadClient;
+
+Components.utils.import("resource:///modules/devtools/SourceMap.jsm");
+
+function run_test()
+{
+  initTestDebuggerServer();
+  gDebuggee = addTestGlobal("test-source-map");
+  gClient = new DebuggerClient(DebuggerServer.connectPipe());
+  gClient.connect(function() {
+    attachTestGlobalClientAndResume(gClient, "test-source-map", function(aResponse, aThreadClient) {
+      gThreadClient = aThreadClient;
+      test_source_content();
+    });
+  });
+  do_test_pending();
+}
+
+function test_source_content()
+{
+  let numNewSources = 0;
+
+  gClient.addListener("newSource", function _onNewSource(aEvent, aPacket) {
+    if (++numNewSources !== 3) {
+      return;
+    }
+    gClient.removeListener("newSource", _onNewSource);
+
+    gThreadClient.getSources(function (aResponse) {
+      do_check_true(!aResponse.error, "Should not get an error");
+
+      testContents(aResponse.sources, () => {
+        finishClient(gClient);
+      });
+    });
+  });
+
+  let node = new SourceNode(null, null, null, [
+    new SourceNode(1, 0, "a.js", "function a() { return 'a'; }\n"),
+    new SourceNode(1, 0, "b.js", "function b() { return 'b'; }\n"),
+    new SourceNode(1, 0, "c.js", "function c() { return 'c'; }\n"),
+  ]);
+
+  node.setSourceContent("a.js", "content for a.js");
+  node.setSourceContent("b.js", "content for b.js");
+  node.setSourceContent("c.js", "content for c.js");
+
+  let { code, map } = node.toStringWithSourceMap({
+    file: "abc.js"
+  });
+
+  code += "//@ sourceMappingURL=data:text/json;base64," + btoa(map.toString());
+
+  Components.utils.evalInSandbox(code, gDebuggee, "1.8",
+                                 "http://example.com/www/js/abc.js", 1);
+}
+
+function testContents(aSources, aCallback) {
+  if (aSources.length === 0) {
+    return aCallback();
+  }
+
+  let source = aSources[0];
+  let sourceClient = gThreadClient.source(aSources[0]);
+
+  sourceClient.source((aResponse) => {
+    do_check_true(!aResponse.error,
+                  "Should not get an error loading the source from sourcesContent");
+
+    let expectedContent = "content for " + source.url;
+    do_check_eq(aResponse.source, expectedContent,
+                "Should have the expected source content");
+
+    testContents(aSources.slice(1), aCallback);
+  });
+}
--- a/toolkit/devtools/debugger/tests/unit/xpcshell.ini
+++ b/toolkit/devtools/debugger/tests/unit/xpcshell.ini
@@ -82,16 +82,17 @@ reason = bug 820380
 [test_sourcemaps-02.js]
 [test_sourcemaps-03.js]
 [test_sourcemaps-04.js]
 skip-if = toolkit == "gonk"
 reason = bug 820380
 [test_sourcemaps-05.js]
 skip-if = toolkit == "gonk"
 reason = bug 820380
+[test_sourcemaps-06.js]
 [test_objectgrips-01.js]
 [test_objectgrips-02.js]
 [test_objectgrips-03.js]
 [test_objectgrips-04.js]
 [test_interrupt.js]
 [test_stepping-01.js]
 [test_stepping-02.js]
 [test_stepping-03.js]