Bug 1537779 - Improve column breakpoint UI performance. r=loganfsmyth
authorJason Laster <jlaster@mozilla.com>
Wed, 08 May 2019 17:18:38 +0000
changeset 531912 0ec8134b1b62b3a3115e3b8ae939b49c1340dfc6
parent 531911 264fe248bca56c113116bd5cfde490ebb554e56a
child 531913 0da5ad89c60ef6b5652edc179f16ba2cf7ce8499
push id11265
push userffxbld-merge
push dateMon, 13 May 2019 10:53:39 +0000
treeherdermozilla-beta@77e0fe8dbdd3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersloganfsmyth
bugs1537779
milestone68.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 1537779 - Improve column breakpoint UI performance. r=loganfsmyth Differential Revision: https://phabricator.services.mozilla.com/D28552
devtools/client/debugger/packages/devtools-source-map/src/index.js
devtools/client/debugger/packages/devtools-source-map/src/source-map.js
devtools/client/debugger/src/actions/breakpoints/breakpointPositions.js
devtools/client/shared/source-map/worker.js
--- a/devtools/client/debugger/packages/devtools-source-map/src/index.js
+++ b/devtools/client/debugger/packages/devtools-source-map/src/index.js
@@ -11,17 +11,17 @@ const {
 import type {
   OriginalFrame,
   Range,
   SourceLocation,
   Source,
   SourceId
 } from "../../../src/types";
 import type { SourceMapConsumer } from "source-map";
-import type { locationOptions } from "./source-map";
+import type { LocationOptions } from "./source-map";
 
 export const dispatcher = new WorkerDispatcher();
 
 const _getGeneratedRanges = dispatcher.task("getGeneratedRanges", {
   queue: true
 });
 
 const _getGeneratedLocation = dispatcher.task("getGeneratedLocation", {
@@ -75,22 +75,23 @@ export const getGeneratedLocation = asyn
 export const getAllGeneratedLocations = async (
   location: SourceLocation,
   originalSource: Source
 ): Promise<Array<SourceLocation>> =>
   _getAllGeneratedLocations(location, originalSource);
 
 export const getOriginalLocation = async (
   location: SourceLocation,
-  options: locationOptions = {}
+  options: LocationOptions = {}
 ): Promise<SourceLocation> => _getOriginalLocation(location, options);
 
 export const getOriginalLocations = async (
+  sourceId: SourceId,
   locations: SourceLocation[],
-  options: locationOptions = {}
+  options: LocationOptions = {}
 ): Promise<SourceLocation[]> =>
   dispatcher.invoke("getOriginalLocations", locations, options);
 
 export const getGeneratedRangesForOriginal = async (
   sourceId: SourceId,
   url: string,
   mergeUnmappedRegions?: boolean
 ): Promise<Range[]> =>
--- a/devtools/client/debugger/packages/devtools-source-map/src/source-map.js
+++ b/devtools/client/debugger/packages/devtools-source-map/src/source-map.js
@@ -41,17 +41,17 @@ type Range = {
     column: number
   },
   end: {
     line: number,
     column: number
   }
 };
 
-export type locationOptions = {
+export type LocationOptions = {
   search?: "LEAST_UPPER_BOUND" | "GREATEST_LOWER_BOUND"
 };
 
 async function getOriginalURLs(
   generatedSource: Source
 ): Promise<SourceMapConsumer> {
   const map = await fetchSourceMap(generatedSource);
   return map && map.sources;
@@ -256,38 +256,40 @@ async function getAllGeneratedLocations(
 
   return positions.map(({ line, column }) => ({
     sourceId: generatedSourceId,
     line,
     column
   }));
 }
 
-function getOriginalLocations(
+async function getOriginalLocations(
+  sourceId: string,
   locations: SourceLocation[],
-  options: locationOptions = {}
-) {
-  return Promise.all(
-    locations.map(location => getOriginalLocation(location, options))
+  options: LocationOptions = {}
+): Promise<SourceLocation[]> {
+  if (locations.some(location => location.sourceId != sourceId)) {
+    throw new Error("Generated locations must belong to the same source");
+  }
+
+  const map = await getSourceMap(sourceId);
+  if (!map) {
+    return locations;
+  }
+
+  return locations.map(location =>
+    getOriginalLocationSync(map, location, options)
   );
 }
 
-async function getOriginalLocation(
+function getOriginalLocationSync(
+  map,
   location: SourceLocation,
-  { search }: locationOptions = {}
-): Promise<SourceLocation> {
-  if (!isGeneratedId(location.sourceId)) {
-    return location;
-  }
-
-  const map = await getSourceMap(location.sourceId);
-  if (!map) {
-    return location;
-  }
-
+  { search }: LocationOptions = {}
+): SourceLocation {
   // First check for an exact match
   let match = map.originalPositionFor({
     line: location.line,
     column: location.column == null ? 0 : location.column
   });
 
   // If there is not an exact match, look for a match with a bias at the
   // current location and then on subsequent lines
@@ -316,16 +318,32 @@ async function getOriginalLocation(
   return {
     sourceId: generatedToOriginalId(location.sourceId, sourceUrl),
     sourceUrl,
     line,
     column
   };
 }
 
+async function getOriginalLocation(
+  location: SourceLocation,
+  options: LocationOptions = {}
+): Promise<SourceLocation> {
+  if (!isGeneratedId(location.sourceId)) {
+    return location;
+  }
+
+  const map = await getSourceMap(location.sourceId);
+  if (!map) {
+    return location;
+  }
+
+  return getOriginalLocationSync(map, location, options);
+}
+
 async function getOriginalSourceText(
   originalSource: Source
 ): Promise<?{
   text: string,
   contentType: string
 }> {
   assert(isOriginalId(originalSource.id), "Source is not an original source");
 
--- a/devtools/client/debugger/src/actions/breakpoints/breakpointPositions.js
+++ b/devtools/client/debugger/src/actions/breakpoints/breakpointPositions.js
@@ -34,17 +34,23 @@ import {
   type MemoizedAction
 } from "../../utils/memoizableAction";
 import type { ThunkArgs } from "../../actions/types";
 
 async function mapLocations(
   generatedLocations: SourceLocation[],
   { sourceMaps }: ThunkArgs
 ) {
+  if (generatedLocations.length == 0) {
+    return [];
+  }
+
+  const { sourceId } = generatedLocations[0];
   const originalLocations = await sourceMaps.getOriginalLocations(
+    sourceId,
     generatedLocations
   );
 
   return zip(originalLocations, generatedLocations).map(
     ([location, generatedLocation]) => ({ location, generatedLocation })
   );
 }
 
--- a/devtools/client/shared/source-map/worker.js
+++ b/devtools/client/shared/source-map/worker.js
@@ -4106,30 +4106,30 @@ async function getAllGeneratedLocations(
 
   return positions.map(({ line, column }) => ({
     sourceId: generatedSourceId,
     line,
     column
   }));
 }
 
-function getOriginalLocations(locations, options = {}) {
-  return Promise.all(locations.map(location => getOriginalLocation(location, options)));
-}
-
-async function getOriginalLocation(location, { search } = {}) {
-  if (!isGeneratedId(location.sourceId)) {
-    return location;
-  }
-
-  const map = await getSourceMap(location.sourceId);
+async function getOriginalLocations(sourceId, locations, options = {}) {
+  if (locations.some(location => location.sourceId != sourceId)) {
+    throw new Error("Generated locations must belong to the same source");
+  }
+
+  const map = await getSourceMap(sourceId);
   if (!map) {
-    return location;
-  }
-
+    return locations;
+  }
+
+  return locations.map(location => getOriginalLocationSync(map, location, options));
+}
+
+function getOriginalLocationSync(map, location, { search } = {}) {
   // First check for an exact match
   let match = map.originalPositionFor({
     line: location.line,
     column: location.column == null ? 0 : location.column
   });
 
   // If there is not an exact match, look for a match with a bias at the
   // current location and then on subsequent lines
@@ -4158,16 +4158,29 @@ async function getOriginalLocation(locat
   return {
     sourceId: generatedToOriginalId(location.sourceId, sourceUrl),
     sourceUrl,
     line,
     column
   };
 }
 
+async function getOriginalLocation(location, options = {}) {
+  if (!isGeneratedId(location.sourceId)) {
+    return location;
+  }
+
+  const map = await getSourceMap(location.sourceId);
+  if (!map) {
+    return location;
+  }
+
+  return getOriginalLocationSync(map, location, options);
+}
+
 async function getOriginalSourceText(originalSource) {
   assert(isOriginalId(originalSource.id), "Source is not an original source");
 
   const generatedSourceId = originalToGeneratedId(originalSource.id);
   const map = await getSourceMap(generatedSourceId);
   if (!map) {
     return null;
   }