Bug 1447244 Part 8 - Generate source actors for internal source IDs on demand, r=lsmyth.
authorBrian Hackett <bhackett1024@gmail.com>
Thu, 21 Feb 2019 09:42:14 -1000
changeset 518732 72038435352d512bb17cc12c24c7912667dfac09
parent 518731 15b57a09f35f5a27eae250ca93bf2770ebfafcbd
child 518733 8891e6a6c18b94f801a5c98b254cf60b9a3915aa
push id10862
push userffxbld-merge
push dateMon, 11 Mar 2019 13:01:11 +0000
treeherdermozilla-beta@a2e7f5c935da [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerslsmyth
bugs1447244
milestone67.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 1447244 Part 8 - Generate source actors for internal source IDs on demand, r=lsmyth.
devtools/client/debugger/new/panel.js
devtools/client/debugger/new/src/reducers/sources.js
devtools/client/shared/view-source.js
devtools/server/actors/utils/TabSources.js
--- a/devtools/client/debugger/new/panel.js
+++ b/devtools/client/debugger/new/panel.js
@@ -127,22 +127,26 @@ DebuggerPanel.prototype = {
   getMappedExpression(expression) {
     return this._actions.getMappedExpression(expression);
   },
 
   isPaused() {
     return this._selectors.isPaused(this._getState());
   },
 
+  selectSourceURL(url, line) {
+    this._actions.selectSourceURL(url, { line });
+  },
+
   selectSource(sourceId, line) {
     this._actions.selectSource(sourceId, { line });
   },
 
-  getSourceById(sourceId) {
-    return this._selectors.getSource(this._getState(), sourceId);
+  getSourceByActorId(sourceId) {
+    return this._selectors.getSourceByActorId(this._getState(), sourceId);
   },
 
   getSourceByURL(sourceURL) {
     return this._selectors.getSourceByURL(this._getState(), sourceURL);
   },
 
   destroy: function() {
     this.panelWin.Debugger.destroy();
--- a/devtools/client/debugger/new/src/reducers/sources.js
+++ b/devtools/client/debugger/new/src/reducers/sources.js
@@ -373,16 +373,27 @@ export function getSource(state: OuterSt
 export function getSourceFromId(state: OuterState, id: string): Source {
   const source = getSource(state, id);
   if (!source) {
     throw new Error(`source ${id} does not exist`);
   }
   return source;
 }
 
+export function getSourceByActorId(state: OuterState, actorId: string): Source {
+  // We don't index the sources by actor IDs, so this method should be used
+  // sparingly.
+  for (const source of Object.values(getSources(state))) {
+    if (source.actors.some(({ actor }) => actor == actorId)) {
+      return source;
+    }
+  }
+  return null;
+}
+
 export function getSourcesByURLInSources(
   sources: SourcesMap,
   urls: UrlsMap,
   url: string
 ): Source[] {
   if (!url || !urls[url]) {
     return [];
   }
--- a/devtools/client/shared/view-source.js
+++ b/devtools/client/shared/view-source.js
@@ -47,21 +47,27 @@ exports.viewSourceInStyleEditor = async 
  * @param {string} sourceID
  * @param {string} [reason=unknown]
  *
  * @return {Promise<boolean>}
  */
 exports.viewSourceInDebugger = async function(toolbox, sourceURL, sourceLine, sourceId,
                                               reason = "unknown") {
   const dbg = await toolbox.loadTool("jsdebugger");
-  const source = sourceId ? dbg.getSourceById(sourceId) : dbg.getSourceByURL(sourceURL);
-  if (source || await toolbox.sourceMapService.hasOriginalURL(sourceURL)) {
+  const source = dbg.getSourceByURL(sourceURL) || dbg.getSourceByActorId(sourceId);
+  if (source) {
     await toolbox.selectTool("jsdebugger", reason);
     dbg.selectSource(source.id, sourceLine);
     return true;
+  } else if (await toolbox.sourceMapService.hasOriginalURL(sourceURL)) {
+    // We have seen a source map for the URL but no source. The debugger will
+    // still be able to load the source.
+    await toolbox.selectTool("jsdebugger", reason);
+    dbg.selectSourceURL(sourceURL, sourceLine);
+    return true;
   }
 
   exports.viewSource(toolbox, sourceURL, sourceLine);
   return false;
 };
 
 /**
  * Tries to open a JavaScript file in the corresponding Scratchpad.
--- a/devtools/server/actors/utils/TabSources.js
+++ b/devtools/server/actors/utils/TabSources.js
@@ -26,23 +26,24 @@ function TabSources(threadActor, allowSo
   };
 
   this.blackBoxedSources = new Map();
   this.neverAutoBlackBoxSources = new Set();
 
   // Debugger.Source -> SourceActor
   this._sourceActors = new Map();
 
-  // DebuggerSource.id -> SourceActor
+  // Debugger.Source.id -> Debugger.Source
   //
   // The IDs associated with ScriptSources and available via DebuggerSource.id
   // are internal to this process and should not be exposed to the client. This
-  // map associates these IDs with the corresponding source actor, provided the
-  // source has not been GC'ed and the actor has been created.
-  this._sourceActorsByInternalSourceId = new Map();
+  // map associates these IDs with the corresponding source, provided the source
+  // has not been GC'ed and the actor has been created. This is lazily populated
+  // the first time it is needed.
+  this._sourcesByInternalSourceId = null;
 }
 
 /**
  * Matches strings of the form "foo.min.js" or "foo-min.js", etc. If the regular
  * expression matches, we can be fairly sure that the source is minified, and
  * treat it as such.
  */
 const MINIFIED_SOURCE_REGEXP = /\bmin\.js$/;
@@ -64,17 +65,17 @@ TabSources.prototype = {
     }
   },
 
   /**
    * Clear existing sources so they are recreated on the next access.
    */
   reset: function() {
     this._sourceActors = new Map();
-    this._sourceActorsByInternalSourceId = new Map();
+    this._sourcesByInternalSourceId = null;
   },
 
   /**
    * Return the source actor representing the `source` (or
    * `originalUrl`), creating one if none exists already. May return
    * null if the source is disallowed.
    *
    * @param Debugger.Source source
@@ -110,18 +111,18 @@ TabSources.prototype = {
     if (this._autoBlackBox &&
         !this.neverAutoBlackBoxSources.has(actor.url) &&
         this._isMinifiedURL(actor.url)) {
       this.blackBox(actor.url);
       this.neverAutoBlackBoxSources.add(actor.url);
     }
 
     this._sourceActors.set(source, actor);
-    if (source.id) {
-      this._sourceActorsByInternalSourceId.set(source.id, actor);
+    if (this._sourcesByInternalSourceId && source.id) {
+      this._sourcesByInternalSourceId.set(source.id, source);
     }
 
     this.emit("newSource", actor);
     return actor;
   },
 
   _getSourceActor: function(source) {
     if (this._sourceActors.has(source)) {
@@ -142,17 +143,32 @@ TabSources.prototype = {
       throw new Error("getSource: could not find source actor for " +
                       (source.url || "source"));
     }
 
     return sourceActor;
   },
 
   getSourceActorByInternalSourceId: function(id) {
-    return this._sourceActorsByInternalSourceId.get(id) || null;
+    if (!this._sourcesByInternalSourceId) {
+      this._sourcesByInternalSourceId = new Map();
+      for (const source of this._thread.dbg.findSources()) {
+        if (source.id) {
+          this._sourcesByInternalSourceId.set(source.id, source);
+        }
+      }
+    }
+    const source = this._sourcesByInternalSourceId.get(id);
+    if (source) {
+      if (this.hasSourceActor(source)) {
+        return this.getSourceActor(source);
+      }
+      return this.createSourceActor(source);
+    }
+    return null;
   },
 
   getSourceActorsByURL: function(url) {
     const rv = [];
     if (url) {
       for (const [source, actor] of this._sourceActors) {
         if (source.url === url) {
           rv.push(actor);