Bug 1531350 - Add column breakpoints (w/ fix for sourcemaps-reload). r=loganfsmyth
authorJason Laster <jlaster@mozilla.com>
Wed, 06 Mar 2019 17:00:37 +0000
changeset 520547 e9364ffb92a61f92c6c0989f546ac899b08fb3cf
parent 520546 7b44e98a5576d5805fb642c47efa2ba28a999347
child 520548 af3e74a36fecd705da30496a44865a3a25d4ef6b
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)
reviewersloganfsmyth
bugs1531350
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 1531350 - Add column breakpoints (w/ fix for sourcemaps-reload). r=loganfsmyth Differential Revision: https://phabricator.services.mozilla.com/D22329
devtools/client/debugger/new/packages/devtools-source-map/src/source-map.js
devtools/client/debugger/new/src/actions/ast.js
devtools/client/debugger/new/src/actions/breakpoints/addBreakpoint.js
devtools/client/debugger/new/src/actions/breakpoints/breakpointPositions.js
devtools/client/debugger/new/src/actions/breakpoints/syncBreakpoint.js
devtools/client/debugger/new/src/actions/breakpoints/tests/__snapshots__/breakpoints.spec.js.snap
devtools/client/debugger/new/src/actions/breakpoints/tests/__snapshots__/syncing.spec.js.snap
devtools/client/debugger/new/src/actions/breakpoints/tests/breakpointPositions.spec.js
devtools/client/debugger/new/src/actions/breakpoints/tests/breakpoints.spec.js
devtools/client/debugger/new/src/actions/breakpoints/tests/syncing.spec.js
devtools/client/debugger/new/src/actions/pause/tests/pause.spec.js
devtools/client/debugger/new/src/actions/sources/loadSourceText.js
devtools/client/debugger/new/src/actions/sources/prettyPrint.js
devtools/client/debugger/new/src/actions/sources/select.js
devtools/client/debugger/new/src/actions/sources/tests/loadSource.spec.js
devtools/client/debugger/new/src/actions/sources/tests/select.spec.js
devtools/client/debugger/new/src/actions/tests/__snapshots__/pending-breakpoints.spec.js.snap
devtools/client/debugger/new/src/actions/tests/ast.spec.js
devtools/client/debugger/new/src/actions/tests/helpers/breakpoints.js
devtools/client/debugger/new/src/actions/tests/helpers/threadClient.js
devtools/client/debugger/new/src/actions/tests/navigation.spec.js
devtools/client/debugger/new/src/actions/tests/pending-breakpoints.spec.js
devtools/client/debugger/new/src/actions/tests/project-text-search.spec.js
devtools/client/debugger/new/src/actions/utils/middleware/log.js
devtools/client/debugger/new/src/client/firefox/commands.js
devtools/client/debugger/new/src/client/firefox/types.js
devtools/client/debugger/new/src/components/SecondaryPanes/Breakpoints/tests/BreakpointsContextMenu.spec.js
devtools/client/debugger/new/src/reducers/tests/breakpoints.spec.js
devtools/client/debugger/new/src/selectors/breakpointSources.js
devtools/client/debugger/new/src/selectors/index.js
devtools/client/debugger/new/src/selectors/test/__snapshots__/visibleColumnBreakpoints.spec.js.snap
devtools/client/debugger/new/src/selectors/test/visibleColumnBreakpoints.spec.js
devtools/client/debugger/new/src/selectors/visibleBreakpoints.js
devtools/client/debugger/new/src/selectors/visibleColumnBreakpoints.js
devtools/client/debugger/new/src/utils/breakpoint/astBreakpointLocation.js
devtools/client/debugger/new/src/utils/breakpoint/breakpointPositions.js
devtools/client/debugger/new/src/utils/breakpoint/index.js
devtools/client/debugger/new/src/utils/breakpoint/moz.build
devtools/client/debugger/new/src/utils/location.js
devtools/client/debugger/new/src/utils/source-maps.js
devtools/client/debugger/new/src/utils/test-head.js
devtools/client/debugger/new/src/utils/test-mockup.js
devtools/client/debugger/new/test/mochitest/browser_dbg-breaking.js
devtools/client/debugger/new/test/mochitest/browser_dbg-breakpoint-skipping.js
devtools/client/debugger/new/test/mochitest/browser_dbg-breakpoints-cond.js
devtools/client/debugger/new/test/mochitest/browser_dbg-debugger-buttons.js
devtools/client/debugger/new/test/mochitest/browser_dbg-editor-gutter.js
devtools/client/debugger/new/test/mochitest/browser_dbg-editor-select.js
devtools/client/debugger/new/test/mochitest/browser_dbg-navigation.js
devtools/client/debugger/new/test/mochitest/browser_dbg-pause-ux.js
devtools/client/debugger/new/test/mochitest/browser_dbg-pretty-print.js
devtools/client/debugger/new/test/mochitest/browser_dbg-react-app.js
devtools/client/debugger/new/test/mochitest/browser_dbg-reload.js
devtools/client/debugger/new/test/mochitest/browser_dbg-sourcemapped-breakpoint-console.js
devtools/client/debugger/new/test/mochitest/browser_dbg-sourcemapped-scopes.js
devtools/client/debugger/new/test/mochitest/browser_dbg-sourcemaps-reload.js
devtools/client/debugger/new/test/mochitest/browser_dbg-sourcemaps-reloading.js
devtools/client/debugger/new/test/mochitest/browser_dbg-sourcemaps.js
devtools/client/debugger/new/test/mochitest/browser_dbg-windowless-workers-early-breakpoint.js
devtools/client/debugger/new/test/mochitest/browser_dbg-windowless-workers.js
devtools/client/debugger/new/test/mochitest/examples/doc-scripts.html
devtools/client/debugger/new/test/mochitest/examples/sourcemaps-reload/v1.bundle.js
devtools/client/debugger/new/test/mochitest/examples/sourcemaps-reload/v1.bundle.js.map
devtools/client/debugger/new/test/mochitest/examples/sourcemaps-reload/v1.js
devtools/client/debugger/new/test/mochitest/examples/sourcemaps-reload/v2.bundle.js
devtools/client/debugger/new/test/mochitest/examples/sourcemaps-reload/v2.bundle.js.map
devtools/client/debugger/new/test/mochitest/examples/sourcemaps-reload/v2.js
devtools/client/debugger/new/test/mochitest/examples/sourcemaps-reload/v3.bundle.js
devtools/client/debugger/new/test/mochitest/examples/sourcemaps-reload/v3.bundle.js.map
devtools/client/debugger/new/test/mochitest/examples/sourcemaps-reload/v3.js
devtools/client/debugger/new/test/mochitest/helpers.js
devtools/client/framework/test/test_browser_toolbox_debugger.js
devtools/client/shared/source-map/worker.js
devtools/client/webconsole/test/mochitest/browser_webconsole_optimized_out_vars.js
testing/talos/talos/tests/devtools/addon/content/tests/debugger/debugger-helpers.js
--- a/devtools/client/debugger/new/packages/devtools-source-map/src/source-map.js
+++ b/devtools/client/debugger/new/packages/devtools-source-map/src/source-map.js
@@ -30,16 +30,27 @@ const {
   isGeneratedId,
   isOriginalId,
   getContentType
 } = require("./utils");
 const { clearWasmXScopes } = require("./utils/wasmXScopes");
 
 import type { SourceLocation, Source, SourceId } from "debugger-html";
 
+type Range = {
+  start: {
+    line: number,
+    column: number
+  },
+  end: {
+    line: number,
+    column: number
+  }
+};
+
 async function getOriginalURLs(
   generatedSource: Source
 ): Promise<SourceMapConsumer> {
   const map = await fetchSourceMap(generatedSource);
   return map && map.sources;
 }
 
 const COMPUTED_SPANS = new WeakSet();
@@ -338,43 +349,43 @@ async function getOriginalSourceText(
  *   contiguous ranges associated with a file, rather than the specifics of
  *   the ranges provided by the sourcemap.
  */
 const GENERATED_MAPPINGS = new WeakMap();
 async function getGeneratedRangesForOriginal(
   sourceId: SourceId,
   url: string,
   mergeUnmappedRegions: boolean = false
-): Promise<
-  Array<{
-    start: {
-      line: number,
-      column: number
-    },
-    end: {
-      line: number,
-      column: number
-    }
-  }>
-> {
+): Promise<Range[]> {
   assert(isOriginalId(sourceId), "Source is not an original source");
 
   const map = await getSourceMap(originalToGeneratedId(sourceId));
+
+  // NOTE: this is only needed for Flow
   if (!map) {
     return [];
   }
 
   if (!COMPUTED_SPANS.has(map)) {
     COMPUTED_SPANS.add(map);
     map.computeColumnSpans();
   }
 
-  const cachedGeneratedMappingsForOriginal = GENERATED_MAPPINGS.get(map);
-  if (cachedGeneratedMappingsForOriginal) {
-    return cachedGeneratedMappingsForOriginal;
+  if (!GENERATED_MAPPINGS.has(map)) {
+    GENERATED_MAPPINGS.set(map, new Map());
+  }
+
+  const generatedRangesMap = GENERATED_MAPPINGS.get(map);
+  if (!generatedRangesMap) {
+    return [];
+  }
+
+  if (generatedRangesMap.has(sourceId)) {
+    // NOTE we need to coerce the result to an array for Flow
+    return generatedRangesMap.get(sourceId) || [];
   }
 
   // Gather groups of mappings on the generated file, with new groups created
   // if we cross a mapping for a different file.
   let currentGroup = [];
   const originalGroups = [currentGroup];
   map.eachMapping(
     mapping => {
@@ -440,17 +451,17 @@ async function getGeneratedRangesForOrig
           const newEntry = { start, end };
           generatedMappingsForOriginal.push(newEntry);
           lastEntry = newEntry;
         }
       }
     }
   }
 
-  GENERATED_MAPPINGS.set(map, generatedMappingsForOriginal);
+  generatedRangesMap.set(sourceId, generatedMappingsForOriginal);
   return generatedMappingsForOriginal;
 }
 
 function wrappedMappingPosition(pos: {
   line: number,
   column: number
 }): {
   line: number,
--- a/devtools/client/debugger/new/src/actions/ast.js
+++ b/devtools/client/debugger/new/src/actions/ast.js
@@ -76,16 +76,20 @@ export function setOutOfScopeLocations()
   return async ({ dispatch, getState }: ThunkArgs) => {
     const location = getSelectedLocation(getState());
     if (!location) {
       return;
     }
 
     const source = getSourceFromId(getState(), location.sourceId);
 
+    if (!isLoaded(source)) {
+      return;
+    }
+
     let locations = null;
     if (location.line && source && !source.isWasm && isPaused(getState())) {
       locations = await parser.findOutOfScopeLocations(
         source.id,
         ((location: any): parser.AstPosition)
       );
     }
 
--- a/devtools/client/debugger/new/src/actions/breakpoints/addBreakpoint.js
+++ b/devtools/client/debugger/new/src/actions/breakpoints/addBreakpoint.js
@@ -4,70 +4,43 @@
 
 // @flow
 
 import {
   breakpointExists,
   assertBreakpoint,
   createBreakpoint,
   getASTLocation,
-  assertLocation,
   makeBreakpointId,
-  makeBreakpointLocation
+  makeBreakpointLocation,
+  findPosition
 } from "../../utils/breakpoint";
 import { PROMISE } from "../utils/middleware/promise";
 import {
-  getSource,
   getSymbols,
-  getFirstVisibleBreakpointPosition
+  getFirstVisibleBreakpointPosition,
+  getBreakpointPositionsForSource,
+  getSourceFromId
 } from "../../selectors";
-import { getGeneratedLocation } from "../../utils/source-maps";
+
 import { getTextAtPosition } from "../../utils/source";
 import { recordEvent } from "../../utils/telemetry";
-import { features } from "../../utils/prefs";
-import { setBreakpointPositions } from "./breakpointPositions";
 
 import type {
   BreakpointOptions,
   Breakpoint,
   SourceLocation
 } from "../../types";
 import type { ThunkArgs } from "../types";
 
 async function addBreakpointPromise(getState, client, sourceMaps, breakpoint) {
   const state = getState();
-  const source = getSource(state, breakpoint.location.sourceId);
-
-  if (!source) {
-    throw new Error(`Unable to find source: ${breakpoint.location.sourceId}`);
-  }
-
-  const location = {
-    ...breakpoint.location,
-    sourceId: source.id,
-    sourceUrl: source.url
-  };
-
-  const generatedLocation = await getGeneratedLocation(
-    state,
-    source,
-    location,
-    sourceMaps
-  );
-
-  const generatedSource = getSource(state, generatedLocation.sourceId);
-
-  if (!generatedSource) {
-    throw new Error(
-      `Unable to find generated source: ${generatedLocation.sourceId}`
-    );
-  }
-
-  assertLocation(location);
-  assertLocation(generatedLocation);
+  const { location, generatedLocation } = breakpoint;
+  const source = getSourceFromId(state, location.sourceId);
+  const generatedSource = getSourceFromId(state, generatedLocation.sourceId);
 
   if (breakpointExists(state, location)) {
     const newBreakpoint = { ...breakpoint, location, generatedLocation };
     assertBreakpoint(newBreakpoint);
     return newBreakpoint;
   }
 
   const breakpointLocation = makeBreakpointLocation(
@@ -123,30 +96,31 @@ export function enableBreakpoint(breakpo
 }
 
 export function addBreakpoint(
   location: SourceLocation,
   options: BreakpointOptions = {}
 ) {
   return async ({ dispatch, getState, sourceMaps, client }: ThunkArgs) => {
     recordEvent("add_breakpoint");
-    let breakpointPosition = location;
-    if (features.columnBreakpoints && location.column === undefined) {
-      await dispatch(setBreakpointPositions(location.sourceId));
-      breakpointPosition = getFirstVisibleBreakpointPosition(
-        getState(),
-        location
-      );
+    let position;
+    const { sourceId, column } = location;
+
+    if (column === undefined) {
+      position = getFirstVisibleBreakpointPosition(getState(), location);
+    } else {
+      const positions = getBreakpointPositionsForSource(getState(), sourceId);
+      position = findPosition(positions, location);
     }
 
-    if (!breakpointPosition) {
+    if (!position) {
       return;
     }
 
-    const breakpoint = createBreakpoint(breakpointPosition, { options });
+    const breakpoint = createBreakpoint(position, { options });
 
     return dispatch({
       type: "ADD_BREAKPOINT",
       breakpoint,
       [PROMISE]: addBreakpointPromise(getState, client, sourceMaps, breakpoint)
     });
   };
 }
--- a/devtools/client/debugger/new/src/actions/breakpoints/breakpointPositions.js
+++ b/devtools/client/debugger/new/src/actions/breakpoints/breakpointPositions.js
@@ -1,110 +1,127 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
 
 // @flow
 
 import { isOriginalId, originalToGeneratedId } from "devtools-source-map";
+import { uniqBy } from "lodash";
 
-import { getSourceFromId, hasBreakpointPositions } from "../../selectors";
+import {
+  getSource,
+  getSourceFromId,
+  hasBreakpointPositions,
+  getBreakpointPositionsForSource
+} from "../../selectors";
 
+import type { MappedLocation, SourceLocation } from "../../types";
 import type { ThunkArgs } from "../../actions/types";
 import { getOriginalLocation } from "../../utils/source-maps";
+import { makeBreakpointId } from "../../utils/breakpoint";
+import typeof SourceMaps from "../../../packages/devtools-source-map/src";
 
 const requests = new Map();
 
-async function mapLocations(generatedLocations, state, source, sourceMaps) {
+async function mapLocations(
+  generatedLocations: SourceLocation[],
+  { sourceMaps }: { sourceMaps: SourceMaps }
+) {
   return Promise.all(
-    generatedLocations.map(async generatedLocation => {
-      const location = await getOriginalLocation(
-        generatedLocation,
-        source,
-        sourceMaps
-      );
+    (generatedLocations: any).map(async (generatedLocation: SourceLocation) => {
+      const location = await getOriginalLocation(generatedLocation, sourceMaps);
 
       return { location, generatedLocation };
     })
   );
 }
 
-function convertToList(results, sourceId) {
+function filterByUniqLocation(positions: MappedLocation[]) {
+  return uniqBy(positions, ({ location }) => makeBreakpointId(location));
+}
+
+function convertToList(results, source) {
+  const { id, url } = source;
   const positions = [];
 
   for (const line in results) {
     for (const column of results[line]) {
-      positions.push({ line: Number(line), column: column, sourceId });
+      positions.push({
+        line: Number(line),
+        column: column,
+        sourceId: id,
+        sourceUrl: url
+      });
     }
   }
 
   return positions;
 }
 
-async function getBreakpointPositions(
-  sourceId,
-  { client, dispatch, getState, sourceMaps }
-) {
-  let source = getSourceFromId(getState(), sourceId);
+async function _setBreakpointPositions(sourceId, thunkArgs) {
+  const { client, dispatch, getState, sourceMaps } = thunkArgs;
+  let generatedSource = getSource(getState(), sourceId);
+  if (!generatedSource) {
+    return;
+  }
 
   let results = {};
   if (isOriginalId(sourceId)) {
     const ranges = await sourceMaps.getGeneratedRangesForOriginal(
       sourceId,
-      source.url,
+      generatedSource.url,
       true
     );
-    sourceId = originalToGeneratedId(sourceId);
-    source = getSourceFromId(getState(), sourceId);
+    const generatedSourceId = originalToGeneratedId(sourceId);
+    generatedSource = getSourceFromId(getState(), generatedSourceId);
 
     // Note: While looping here may not look ideal, in the vast majority of
     // cases, the number of ranges here should be very small, and is quite
     // likely to only be a single range.
     for (const range of ranges) {
       // Wrap infinite end positions to the next line to keep things simple
       // and because we know we don't care about the end-line whitespace
       // in this case.
       if (range.end.column === Infinity) {
         range.end.line += 1;
         range.end.column = 0;
       }
 
-      const bps = await client.getBreakpointPositions(source.actors[0], range);
+      const bps = await client.getBreakpointPositions(generatedSource, range);
       for (const line in bps) {
         results[line] = (results[line] || []).concat(bps[line]);
       }
     }
   } else {
-    results = await client.getBreakpointPositions(source.actors[0]);
+    results = await client.getBreakpointPositions(generatedSource);
   }
 
-  const positions = convertToList(results, sourceId);
-  return mapLocations(positions, getState(), source, sourceMaps);
+  let positions = convertToList(results, generatedSource);
+  positions = await mapLocations(positions, thunkArgs);
+  positions = filterByUniqLocation(positions);
+  dispatch({ type: "ADD_BREAKPOINT_POSITIONS", sourceId, positions });
 }
 
 export function setBreakpointPositions(sourceId: string) {
   return async (thunkArgs: ThunkArgs) => {
-    const { dispatch, getState } = thunkArgs;
-
+    const { getState } = thunkArgs;
     if (hasBreakpointPositions(getState(), sourceId)) {
-      return;
+      return getBreakpointPositionsForSource(getState(), sourceId);
     }
 
     if (!requests.has(sourceId)) {
       requests.set(
         sourceId,
         (async () => {
           try {
-            dispatch({
-              type: "ADD_BREAKPOINT_POSITIONS",
-              sourceId,
-              positions: await getBreakpointPositions(sourceId, thunkArgs)
-            });
+            await _setBreakpointPositions(sourceId, thunkArgs);
           } finally {
             requests.delete(sourceId);
           }
         })()
       );
     }
 
     await requests.get(sourceId);
+    return getBreakpointPositionsForSource(getState(), sourceId);
   };
 }
--- a/devtools/client/debugger/new/src/actions/breakpoints/syncBreakpoint.js
+++ b/devtools/client/debugger/new/src/actions/breakpoints/syncBreakpoint.js
@@ -1,68 +1,67 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
 
 // @flow
 
 import { setBreakpointPositions } from "./breakpointPositions";
 import {
-  locationMoved,
   createBreakpoint,
   assertBreakpoint,
   assertPendingBreakpoint,
-  findScopeByName,
+  findFunctionByName,
+  findPosition,
   makeBreakpointLocation
 } from "../../utils/breakpoint";
 
-import { getGeneratedLocation } from "../../utils/source-maps";
 import { getTextAtPosition } from "../../utils/source";
+import { comparePosition } from "../../utils/location";
+
 import { originalToGeneratedId, isOriginalId } from "devtools-source-map";
-import { getSource, getBreakpointPositionsForSource } from "../../selectors";
-import { features } from "../../utils/prefs";
+import { getSource } from "../../selectors";
 
 import type { ThunkArgs, Action } from "../types";
 
 import type {
   SourceLocation,
   ASTLocation,
   PendingBreakpoint,
   SourceId,
   Breakpoint
 } from "../../types";
 
 type BreakpointSyncData = {
   previousLocation: SourceLocation,
   breakpoint: ?Breakpoint
 };
 
-async function isPossiblePosition(state, location, dispatch) {
-  if (!features.columnBreakpoints || location.column != undefined) {
-    return true;
-  }
-
-  await dispatch(setBreakpointPositions(location.sourceId));
-  const positions = getBreakpointPositionsForSource(state, location.sourceId);
-  return (
-    positions &&
-    positions.some(({ generatedLocation }) => generatedLocation.column)
-  );
+async function findBreakpointPosition(
+  { getState, dispatch },
+  location: SourceLocation
+) {
+  const positions = await dispatch(setBreakpointPositions(location.sourceId));
+  const position = findPosition(positions, location);
+  return position && position.generatedLocation;
 }
 
-async function makeScopedLocation(
+async function findNewLocation(
   { name, offset, index }: ASTLocation,
   location: SourceLocation,
   source
 ) {
-  const scope = await findScopeByName(source, name, index);
-  // fallback onto the location line, if the scope is not found
-  // note: we may at some point want to delete the breakpoint if the scope
-  // disappears
-  const line = scope ? scope.location.start.line + offset.line : location.line;
+  const func = await findFunctionByName(source, name, index);
+
+  // Fallback onto the location line, if we do not find a function is not found
+  let line = location.line;
+  if (func) {
+    line = func.location.start.line + offset.line;
+  }
+
   return {
     line,
     column: location.column,
     sourceUrl: source.url,
     sourceId: source.id
   };
 }
 
@@ -71,173 +70,143 @@ function createSyncData(
   location: SourceLocation,
   generatedLocation: SourceLocation,
   previousLocation: SourceLocation,
   text: string,
   originalText: string
 ): BreakpointSyncData {
   const overrides = {
     ...pendingBreakpoint,
-    generatedLocation,
     text,
     originalText
   };
-  const breakpoint = createBreakpoint(location, overrides);
+  const breakpoint = createBreakpoint(
+    { generatedLocation, location },
+    overrides
+  );
 
   assertBreakpoint(breakpoint);
   return { breakpoint, previousLocation };
 }
 
 // we have three forms of syncing: disabled syncing, existing server syncing
 // and adding a new breakpoint
 export async function syncBreakpointPromise(
-  getState: Function,
-  client: Object,
-  sourceMaps: Object,
-  dispatch: Function,
+  thunkArgs: ThunkArgs,
   sourceId: SourceId,
   pendingBreakpoint: PendingBreakpoint
-): Promise<BreakpointSyncData | null> {
+): Promise<?BreakpointSyncData> {
+  const { getState, client } = thunkArgs;
   assertPendingBreakpoint(pendingBreakpoint);
 
   const source = getSource(getState(), sourceId);
 
   const generatedSourceId = isOriginalId(sourceId)
     ? originalToGeneratedId(sourceId)
     : sourceId;
 
   const generatedSource = getSource(getState(), generatedSourceId);
 
-  if (!source) {
-    return null;
+  if (!source || !generatedSource) {
+    return;
   }
 
-  const { location, astLocation } = pendingBreakpoint;
+  const { location, generatedLocation, astLocation } = pendingBreakpoint;
   const previousLocation = { ...location, sourceId };
 
-  const scopedLocation = await makeScopedLocation(
+  const newLocation = await findNewLocation(
     astLocation,
     previousLocation,
     source
   );
 
-  const scopedGeneratedLocation = await getGeneratedLocation(
-    getState(),
-    source,
-    scopedLocation,
-    sourceMaps
+  const newGeneratedLocation = await findBreakpointPosition(
+    thunkArgs,
+    newLocation
   );
 
-  // this is the generatedLocation of the pending breakpoint, with
-  // the source id updated to reflect the new connection
-  const generatedLocation = {
-    ...pendingBreakpoint.generatedLocation,
-    sourceId: generatedSourceId
-  };
-
-  const isSameLocation = !locationMoved(
+  const isSameLocation = comparePosition(
     generatedLocation,
-    scopedGeneratedLocation
-  );
-
-  // makeBreakpointLocation requires the source to still exist, which might not
-  // be the case if we navigated.
-  if (!getSource(getState(), generatedSourceId)) {
-    return null;
-  }
-
-  const breakpointLocation = makeBreakpointLocation(
-    getState(),
-    generatedLocation
-  );
-
-  const possiblePosition = await isPossiblePosition(
-    getState(),
-    generatedLocation,
-    dispatch
+    newGeneratedLocation
   );
 
   /** ******* CASE 1: No server change ***********/
   // early return if breakpoint is disabled or we are in the sameLocation
-  if (possiblePosition && (pendingBreakpoint.disabled || isSameLocation)) {
+  if (newGeneratedLocation && (pendingBreakpoint.disabled || isSameLocation)) {
     // Make sure the breakpoint is installed on all source actors.
     if (!pendingBreakpoint.disabled) {
-      await client.setBreakpoint(breakpointLocation, pendingBreakpoint.options);
+      await client.setBreakpoint(
+        makeBreakpointLocation(getState(), newGeneratedLocation),
+        pendingBreakpoint.options
+      );
     }
 
     const originalText = getTextAtPosition(source, previousLocation);
-    const text = getTextAtPosition(generatedSource, generatedLocation);
+    const text = getTextAtPosition(generatedSource, newGeneratedLocation);
 
     return createSyncData(
       pendingBreakpoint,
-      scopedLocation,
-      scopedGeneratedLocation,
+      newLocation,
+      newGeneratedLocation,
       previousLocation,
       text,
       originalText
     );
   }
 
   // clear server breakpoints if they exist and we have moved
-  await client.removeBreakpoint(breakpointLocation);
+  await client.removeBreakpoint(generatedLocation);
 
-  if (!possiblePosition || !scopedGeneratedLocation.line) {
+  if (!newGeneratedLocation) {
     return { previousLocation, breakpoint: null };
   }
 
   /** ******* Case 2: Add New Breakpoint ***********/
   // If we are not disabled, set the breakpoint on the server and get
   // that info so we can set it on our breakpoints.
   await client.setBreakpoint(
-    scopedGeneratedLocation,
+    makeBreakpointLocation(getState(), newGeneratedLocation),
     pendingBreakpoint.options
   );
 
-  const originalText = getTextAtPosition(source, scopedLocation);
-  const text = getTextAtPosition(generatedSource, scopedGeneratedLocation);
+  const originalText = getTextAtPosition(source, newLocation);
+  const text = getTextAtPosition(generatedSource, newGeneratedLocation);
 
   return createSyncData(
     pendingBreakpoint,
-    scopedLocation,
-    scopedGeneratedLocation,
+    newLocation,
+    newGeneratedLocation,
     previousLocation,
     text,
     originalText
   );
 }
 
 /**
  * Syncing a breakpoint add breakpoint information that is stored, and
  * contact the server for more data.
- *
- * @memberof actions/breakpoints
- * @static
- * @param {String} $1.sourceId String  value
- * @param {PendingBreakpoint} $1.location PendingBreakpoint  value
  */
 export function syncBreakpoint(
   sourceId: SourceId,
   pendingBreakpoint: PendingBreakpoint
 ) {
-  return async ({ dispatch, getState, client, sourceMaps }: ThunkArgs) => {
+  return async (thunkArgs: ThunkArgs) => {
+    const { dispatch } = thunkArgs;
+
     const response = await syncBreakpointPromise(
-      getState,
-      client,
-      sourceMaps,
-      dispatch,
+      thunkArgs,
       sourceId,
       pendingBreakpoint
     );
 
     if (!response) {
       return;
     }
 
     const { breakpoint, previousLocation } = response;
-
     return dispatch(
       ({
         type: "SYNC_BREAKPOINT",
         breakpoint,
         previousLocation
       }: Action)
     );
   };
--- a/devtools/client/debugger/new/src/actions/breakpoints/tests/__snapshots__/breakpoints.spec.js.snap
+++ b/devtools/client/debugger/new/src/actions/breakpoints/tests/__snapshots__/breakpoints.spec.js.snap
@@ -4,30 +4,33 @@ exports[`breakpoints should add a breakp
 Array [
   Object {
     "breakpoints": Array [
       Object {
         "astLocation": Object {
           "index": 0,
           "name": undefined,
           "offset": Object {
+            "column": 1,
             "line": 2,
             "sourceId": "a",
             "sourceUrl": "http://localhost:8000/examples/a",
           },
         },
         "disabled": false,
         "generatedLocation": Object {
+          "column": 1,
           "line": 2,
           "sourceId": "a",
           "sourceUrl": "http://localhost:8000/examples/a",
         },
-        "id": "a:2:",
+        "id": "a:2:1",
         "loading": false,
         "location": Object {
+          "column": 1,
           "line": 2,
           "sourceId": "a",
           "sourceUrl": "http://localhost:8000/examples/a",
         },
         "options": Object {
           "condition": null,
           "hidden": false,
           "logValue": null,
@@ -59,23 +62,25 @@ Array [
 exports[`breakpoints should not show a breakpoint that does not have text 1`] = `Array []`;
 
 exports[`breakpoints should remap breakpoints on pretty print 1`] = `
 Object {
   "astLocation": Object {
     "index": 0,
     "name": undefined,
     "offset": Object {
+      "column": 0,
       "line": 1,
       "sourceId": "a.js",
       "sourceUrl": "http://localhost:8000/examples/a.js",
     },
   },
   "disabled": false,
   "generatedLocation": Object {
+    "column": 0,
     "line": 1,
     "sourceId": "a.js",
     "sourceUrl": "http://localhost:8000/examples/a.js",
   },
   "id": "a.js:1:",
   "loading": false,
   "location": Object {
     "column": 0,
@@ -97,30 +102,33 @@ exports[`breakpoints should show a disab
 Array [
   Object {
     "breakpoints": Array [
       Object {
         "astLocation": Object {
           "index": 0,
           "name": undefined,
           "offset": Object {
+            "column": 1,
             "line": 5,
             "sourceId": "a",
             "sourceUrl": "http://localhost:8000/examples/a",
           },
         },
         "disabled": true,
         "generatedLocation": Object {
+          "column": 1,
           "line": 5,
           "sourceId": "a",
           "sourceUrl": "http://localhost:8000/examples/a",
         },
-        "id": "a:5:",
+        "id": "a:5:1",
         "loading": false,
         "location": Object {
+          "column": 1,
           "line": 5,
           "sourceId": "a",
           "sourceUrl": "http://localhost:8000/examples/a",
         },
         "options": Object {
           "condition": null,
           "hidden": false,
           "logValue": null,
deleted file mode 100644
--- a/devtools/client/debugger/new/src/actions/breakpoints/tests/__snapshots__/syncing.spec.js.snap
+++ /dev/null
@@ -1,199 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`loading the debugger loads the initial breakpoint state 1`] = `
-Object {
-  "breakpoint": Object {
-    "astLocation": Object {
-      "index": 0,
-      "name": undefined,
-      "offset": Object {
-        "line": 3,
-      },
-    },
-    "disabled": false,
-    "generatedLocation": Object {
-      "column": undefined,
-      "line": 3,
-      "sourceId": "gen.js",
-      "sourceUrl": "http://localhost:8000/gen.js",
-    },
-    "id": "magic.js:3:",
-    "loading": false,
-    "location": Object {
-      "column": undefined,
-      "line": 3,
-      "sourceId": "magic.js",
-      "sourceUrl": "http://localhost:8000/examples/magic.js",
-    },
-    "options": Object {
-      "condition": null,
-      "hidden": false,
-      "logValue": null,
-    },
-    "originalText": "",
-    "text": "",
-  },
-  "previousLocation": Object {
-    "column": undefined,
-    "line": 3,
-    "sourceId": "magic.js",
-    "sourceUrl": "http://localhost:8000/magic.js",
-  },
-}
-`;
-
-exports[`loading the debugger loads the initial breakpoint state with a changed file 1`] = `
-Object {
-  "breakpoint": Object {
-    "astLocation": Object {
-      "index": 0,
-      "name": undefined,
-      "offset": Object {
-        "line": 3,
-      },
-    },
-    "disabled": false,
-    "generatedLocation": Object {
-      "column": undefined,
-      "line": 3,
-      "sourceId": "gen.js",
-      "sourceUrl": "http://localhost:8000/gen.js",
-    },
-    "id": "magic.js:12:",
-    "loading": false,
-    "location": Object {
-      "column": undefined,
-      "line": 12,
-      "sourceId": "magic.js",
-      "sourceUrl": "http://localhost:8000/examples/magic.js",
-    },
-    "options": Object {
-      "condition": null,
-      "hidden": false,
-      "logValue": null,
-    },
-    "originalText": "",
-    "text": "",
-  },
-  "previousLocation": Object {
-    "column": undefined,
-    "line": 3,
-    "sourceId": "magic.js",
-    "sourceUrl": "http://localhost:8000/magic.js",
-  },
-}
-`;
-
-exports[`reloading debuggee syncs with changed source and an existing disabled BP 1`] = `
-Object {
-  "http://localhost:8000/examples/magic.js:3:": Object {
-    "astLocation": Object {
-      "index": 0,
-      "name": undefined,
-      "offset": Object {
-        "line": 3,
-      },
-    },
-    "disabled": true,
-    "generatedLocation": Object {
-      "column": undefined,
-      "line": 1,
-      "sourceUrl": "http://localhost:8000/gen.js",
-    },
-    "location": Object {
-      "column": undefined,
-      "line": 3,
-      "sourceUrl": "http://localhost:8000/examples/magic.js",
-    },
-    "options": Object {
-      "condition": null,
-      "hidden": false,
-      "logValue": null,
-    },
-  },
-}
-`;
-
-exports[`reloading debuggee syncs with unchanged source with an existing BP 1`] = `
-Object {
-  "breakpoint": Object {
-    "astLocation": Object {
-      "index": 0,
-      "name": undefined,
-      "offset": Object {
-        "line": 3,
-      },
-    },
-    "disabled": false,
-    "generatedLocation": Object {
-      "column": undefined,
-      "line": 3,
-      "sourceId": "gen.js",
-      "sourceUrl": "http://localhost:8000/gen.js",
-    },
-    "id": "magic.js:3:",
-    "loading": false,
-    "location": Object {
-      "column": undefined,
-      "line": 3,
-      "sourceId": "magic.js",
-      "sourceUrl": "http://localhost:8000/examples/magic.js",
-    },
-    "options": Object {
-      "condition": null,
-      "hidden": false,
-      "logValue": null,
-    },
-    "originalText": "",
-    "text": "",
-  },
-  "previousLocation": Object {
-    "column": undefined,
-    "line": 3,
-    "sourceId": "magic.js",
-    "sourceUrl": "http://localhost:8000/magic.js",
-  },
-}
-`;
-
-exports[`reloading debuggee updates a corresponding breakpoint for a changed source 1`] = `
-Object {
-  "breakpoint": Object {
-    "astLocation": Object {
-      "index": 0,
-      "name": undefined,
-      "offset": Object {
-        "line": 3,
-      },
-    },
-    "disabled": false,
-    "generatedLocation": Object {
-      "column": undefined,
-      "line": 5,
-      "sourceId": "gen.js",
-      "sourceUrl": "http://localhost:8000/gen.js",
-    },
-    "id": "magic.js:3:",
-    "loading": false,
-    "location": Object {
-      "column": undefined,
-      "line": 3,
-      "sourceId": "magic.js",
-      "sourceUrl": "http://localhost:8000/examples/magic.js",
-    },
-    "options": Object {
-      "condition": null,
-      "hidden": false,
-      "logValue": null,
-    },
-    "originalText": "",
-    "text": "",
-  },
-  "previousLocation": Object {
-    "column": undefined,
-    "line": 3,
-    "sourceId": "magic.js",
-    "sourceUrl": "http://localhost:8000/magic.js",
-  },
-}
-`;
--- a/devtools/client/debugger/new/src/actions/breakpoints/tests/breakpointPositions.spec.js
+++ b/devtools/client/debugger/new/src/actions/breakpoints/tests/breakpointPositions.spec.js
@@ -26,18 +26,28 @@ describe("breakpointPositions", () => {
     await waitForState(store, state =>
       selectors.hasBreakpointPositions(state, "foo")
     );
 
     expect(
       selectors.getBreakpointPositionsForSource(getState(), "foo")
     ).toEqual([
       {
-        location: { line: 9, column: 1, sourceId: "foo" },
-        generatedLocation: { line: 9, column: 1, sourceId: "foo" }
+        location: {
+          line: 9,
+          column: 1,
+          sourceId: "foo",
+          sourceUrl: "http://localhost:8000/examples/foo"
+        },
+        generatedLocation: {
+          line: 9,
+          column: 1,
+          sourceId: "foo",
+          sourceUrl: "http://localhost:8000/examples/foo"
+        }
       }
     ]);
   });
 
   it("doesn't re-fetch positions", async () => {
     let resolve = _ => {};
     let count = 0;
     const store = createStore({
@@ -58,16 +68,26 @@ describe("breakpointPositions", () => {
     await waitForState(store, state =>
       selectors.hasBreakpointPositions(state, "foo")
     );
 
     expect(
       selectors.getBreakpointPositionsForSource(getState(), "foo")
     ).toEqual([
       {
-        location: { line: 9, column: 1, sourceId: "foo" },
-        generatedLocation: { line: 9, column: 1, sourceId: "foo" }
+        location: {
+          line: 9,
+          column: 1,
+          sourceId: "foo",
+          sourceUrl: "http://localhost:8000/examples/foo"
+        },
+        generatedLocation: {
+          line: 9,
+          column: 1,
+          sourceId: "foo",
+          sourceUrl: "http://localhost:8000/examples/foo"
+        }
       }
     ]);
 
     expect(count).toEqual(1);
   });
 });
--- a/devtools/client/debugger/new/src/actions/breakpoints/tests/breakpoints.spec.js
+++ b/devtools/client/debugger/new/src/actions/breakpoints/tests/breakpoints.spec.js
@@ -9,144 +9,202 @@ import {
   selectors,
   actions,
   makeSource,
   getTelemetryEvents
 } from "../../../utils/test-head";
 
 import { simpleMockThreadClient } from "../../tests/helpers/threadClient.js";
 
+function mockClient(positionsResponse = {}) {
+  return {
+    ...simpleMockThreadClient,
+    getBreakpointPositions: async () => positionsResponse
+  };
+}
+
 describe("breakpoints", () => {
   it("should add a breakpoint", async () => {
-    const { dispatch, getState } = createStore(simpleMockThreadClient);
+    const { dispatch, getState } = createStore(mockClient({ "2": [1] }));
     const loc1 = {
       sourceId: "a",
       line: 2,
+      column: 1,
       sourceUrl: "http://localhost:8000/examples/a"
     };
 
     const source = makeSource("a");
     await dispatch(actions.newSource(source));
     await dispatch(actions.loadSourceText(source));
+    await dispatch(
+      actions.setSelectedLocation(source, {
+        line: 1,
+        column: 1,
+        sourceId: source.id
+      })
+    );
+
     await dispatch(actions.addBreakpoint(loc1));
 
     expect(selectors.getBreakpointCount(getState())).toEqual(1);
     const bp = selectors.getBreakpoint(getState(), loc1);
     expect(bp && bp.location).toEqual(loc1);
     expect(getTelemetryEvents("add_breakpoint")).toHaveLength(1);
 
     const bpSources = selectors.getBreakpointSources(getState());
     expect(bpSources).toMatchSnapshot();
   });
 
   it("should not show a breakpoint that does not have text", async () => {
-    const { dispatch, getState } = createStore(simpleMockThreadClient);
+    const { dispatch, getState } = createStore(mockClient({ "5": [1] }));
     const loc1 = {
       sourceId: "a",
       line: 5,
+      column: 1,
       sourceUrl: "http://localhost:8000/examples/a"
     };
     const source = makeSource("a");
     await dispatch(actions.newSource(source));
     await dispatch(actions.loadSourceText(source));
+    await dispatch(
+      actions.setSelectedLocation(source, {
+        line: 1,
+        column: 1,
+        sourceId: source.id
+      })
+    );
+
     await dispatch(actions.addBreakpoint(loc1));
 
     expect(selectors.getBreakpointCount(getState())).toEqual(1);
     const bp = selectors.getBreakpoint(getState(), loc1);
     expect(bp && bp.location).toEqual(loc1);
     expect(selectors.getBreakpointSources(getState())).toMatchSnapshot();
   });
 
   it("should show a disabled breakpoint that does not have text", async () => {
-    const { dispatch, getState } = createStore(simpleMockThreadClient);
+    const { dispatch, getState } = createStore(mockClient({ "5": [1] }));
     const loc1 = {
       sourceId: "a",
       line: 5,
+      column: 1,
       sourceUrl: "http://localhost:8000/examples/a"
     };
     const source = makeSource("a");
     await dispatch(actions.newSource(source));
     await dispatch(actions.loadSourceText(source));
+    await dispatch(
+      actions.setSelectedLocation(source, {
+        line: 1,
+        column: 1,
+        sourceId: source.id
+      })
+    );
+
     const breakpoint = await dispatch(actions.addBreakpoint(loc1));
     await dispatch(actions.disableBreakpoint(breakpoint));
 
     expect(selectors.getBreakpointCount(getState())).toEqual(1);
     const bp = selectors.getBreakpoint(getState(), loc1);
     expect(bp && bp.location).toEqual(loc1);
     expect(selectors.getBreakpointSources(getState())).toMatchSnapshot();
   });
 
   it("should not re-add a breakpoint", async () => {
-    const { dispatch, getState } = createStore(simpleMockThreadClient);
+    const { dispatch, getState } = createStore(mockClient({ "5": [1] }));
     const loc1 = {
       sourceId: "a",
       line: 5,
+      column: 1,
       sourceUrl: "http://localhost:8000/examples/a"
     };
 
     const source = makeSource("a");
     await dispatch(actions.newSource(source));
     await dispatch(actions.loadSourceText(source));
+    await dispatch(
+      actions.setSelectedLocation(source, {
+        line: 1,
+        column: 1,
+        sourceId: source.id
+      })
+    );
 
     await dispatch(actions.addBreakpoint(loc1));
     expect(selectors.getBreakpointCount(getState())).toEqual(1);
     const bp = selectors.getBreakpoint(getState(), loc1);
     expect(bp && bp.location).toEqual(loc1);
 
     await dispatch(actions.addBreakpoint(loc1));
     expect(selectors.getBreakpointCount(getState())).toEqual(1);
   });
 
   it("should remove a breakpoint", async () => {
-    const { dispatch, getState } = createStore(simpleMockThreadClient);
+    const { dispatch, getState } = createStore(
+      mockClient({ "5": [1], "6": [2] })
+    );
 
     const loc1 = {
       sourceId: "a",
       line: 5,
+      column: 1,
       sourceUrl: "http://localhost:8000/examples/a"
     };
 
     const loc2 = {
       sourceId: "b",
       line: 6,
+      column: 2,
       sourceUrl: "http://localhost:8000/examples/b"
     };
 
     const aSource = makeSource("a");
     await dispatch(actions.newSource(aSource));
     await dispatch(actions.loadSourceText(aSource));
 
     const bSource = makeSource("b");
     await dispatch(actions.newSource(bSource));
     await dispatch(actions.loadSourceText(bSource));
 
+    await dispatch(
+      actions.setSelectedLocation(aSource, {
+        line: 1,
+        column: 1,
+        sourceId: aSource.id
+      })
+    );
+
     await dispatch(actions.addBreakpoint(loc1));
     await dispatch(actions.addBreakpoint(loc2));
 
     const bp = selectors.getBreakpoint(getState(), loc1);
     if (!bp) {
       throw new Error("no bp");
     }
     await dispatch(actions.removeBreakpoint(bp));
 
     expect(selectors.getBreakpointCount(getState())).toEqual(1);
   });
 
   it("should disable a breakpoint", async () => {
-    const { dispatch, getState } = createStore(simpleMockThreadClient);
+    const { dispatch, getState } = createStore(
+      mockClient({ "5": [1], "6": [2] })
+    );
 
     const loc1 = {
       sourceId: "a",
       line: 5,
+      column: 1,
       sourceUrl: "http://localhost:8000/examples/a"
     };
 
     const loc2 = {
       sourceId: "b",
       line: 6,
+      column: 2,
       sourceUrl: "http://localhost:8000/examples/b"
     };
 
     const aSource = makeSource("a");
     await dispatch(actions.newSource(aSource));
     await dispatch(actions.loadSourceText(aSource));
 
     const bSource = makeSource("b");
@@ -158,20 +216,23 @@ describe("breakpoints", () => {
 
     await dispatch(actions.disableBreakpoint(breakpoint));
 
     const bp = selectors.getBreakpoint(getState(), loc1);
     expect(bp && bp.disabled).toBe(true);
   });
 
   it("should enable breakpoint", async () => {
-    const { dispatch, getState } = createStore(simpleMockThreadClient);
+    const { dispatch, getState } = createStore(
+      mockClient({ "5": [1], "6": [2] })
+    );
     const loc = {
       sourceId: "a",
       line: 5,
+      column: 1,
       sourceUrl: "http://localhost:8000/examples/a"
     };
 
     const aSource = makeSource("a");
     await dispatch(actions.newSource(aSource));
     await dispatch(actions.loadSourceText(aSource));
 
     const breakpoint = await dispatch(actions.addBreakpoint(loc));
@@ -182,27 +243,31 @@ describe("breakpoints", () => {
 
     await dispatch(actions.enableBreakpoint(breakpoint));
 
     bp = selectors.getBreakpoint(getState(), loc);
     expect(bp && !bp.disabled).toBe(true);
   });
 
   it("should toggle all the breakpoints", async () => {
-    const { dispatch, getState } = createStore(simpleMockThreadClient);
+    const { dispatch, getState } = createStore(
+      mockClient({ "5": [1], "6": [2] })
+    );
 
     const loc1 = {
       sourceId: "a",
       line: 5,
+      column: 1,
       sourceUrl: "http://localhost:8000/examples/a"
     };
 
     const loc2 = {
       sourceId: "b",
       line: 6,
+      column: 2,
       sourceUrl: "http://localhost:8000/examples/b"
     };
 
     const aSource = makeSource("a");
     await dispatch(actions.newSource(aSource));
     await dispatch(actions.loadSourceText(aSource));
 
     const bSource = makeSource("b");
@@ -211,52 +276,53 @@ describe("breakpoints", () => {
 
     await dispatch(actions.addBreakpoint(loc1));
     await dispatch(actions.addBreakpoint(loc2));
 
     await dispatch(actions.toggleAllBreakpoints(true));
 
     let bp1 = selectors.getBreakpoint(getState(), loc1);
     let bp2 = selectors.getBreakpoint(getState(), loc2);
+
     expect(bp1 && bp1.disabled).toBe(true);
     expect(bp2 && bp2.disabled).toBe(true);
 
     await dispatch(actions.toggleAllBreakpoints(false));
 
     bp1 = selectors.getBreakpoint(getState(), loc1);
     bp2 = selectors.getBreakpoint(getState(), loc2);
     expect(bp1 && bp1.disabled).toBe(false);
     expect(bp2 && bp2.disabled).toBe(false);
   });
 
   it("should toggle a breakpoint at a location", async () => {
-    const location = { sourceId: "foo1", line: 5 };
-    const getBp = () => selectors.getBreakpoint(getState(), location);
+    const loc = { sourceId: "foo1", line: 5, column: 1 };
+    const getBp = () => selectors.getBreakpoint(getState(), loc);
 
-    const { dispatch, getState } = createStore(simpleMockThreadClient);
+    const { dispatch, getState } = createStore(mockClient({ "5": [1] }));
 
     const source = makeSource("foo1");
     await dispatch(actions.newSource(source));
     await dispatch(actions.loadSourceText(source));
 
-    await dispatch(actions.selectLocation({ sourceId: "foo1", line: 1 }));
+    await dispatch(actions.selectLocation(loc));
 
     await dispatch(actions.toggleBreakpointAtLine(5));
     const bp = getBp();
     expect(bp && !bp.disabled).toBe(true);
 
     await dispatch(actions.toggleBreakpointAtLine(5));
     expect(getBp()).toBe(undefined);
   });
 
   it("should disable/enable a breakpoint at a location", async () => {
-    const location = { sourceId: "foo1", line: 5 };
+    const location = { sourceId: "foo1", line: 5, column: 1 };
     const getBp = () => selectors.getBreakpoint(getState(), location);
 
-    const { dispatch, getState } = createStore(simpleMockThreadClient);
+    const { dispatch, getState } = createStore(mockClient({ "5": [1] }));
 
     const source = makeSource("foo1");
     await dispatch(actions.newSource(source));
     await dispatch(actions.loadSourceText(source));
 
     await dispatch(actions.selectLocation({ sourceId: "foo1", line: 1 }));
 
     await dispatch(actions.toggleBreakpointAtLine(5));
@@ -267,21 +333,22 @@ describe("breakpoints", () => {
       throw new Error("no bp");
     }
     await dispatch(actions.toggleDisabledBreakpoint(bp));
     bp = getBp();
     expect(bp && bp.disabled).toBe(true);
   });
 
   it("should set the breakpoint condition", async () => {
-    const { dispatch, getState } = createStore(simpleMockThreadClient);
+    const { dispatch, getState } = createStore(mockClient({ "5": [1] }));
 
     const loc = {
       sourceId: "a",
       line: 5,
+      column: 1,
       sourceUrl: "http://localhost:8000/examples/a"
     };
 
     const source = makeSource("a");
     await dispatch(actions.newSource(source));
     await dispatch(actions.loadSourceText(source));
 
     await dispatch(actions.addBreakpoint(loc));
@@ -296,25 +363,29 @@ describe("breakpoints", () => {
       })
     );
 
     bp = selectors.getBreakpoint(getState(), loc);
     expect(bp && bp.options.condition).toBe("const foo = 0");
   });
 
   it("should set the condition and enable a breakpoint", async () => {
-    const { dispatch, getState } = createStore(simpleMockThreadClient);
+    const { dispatch, getState } = createStore(mockClient({ "5": [1] }));
 
     const loc = {
       sourceId: "a",
       line: 5,
+      column: 1,
       sourceUrl: "http://localhost:8000/examples/a"
     };
 
-    await dispatch(actions.newSource(makeSource("a")));
+    const source = makeSource("a");
+    await dispatch(actions.newSource(source));
+    await dispatch(actions.loadSourceText(source));
+
     const breakpoint = await dispatch(actions.addBreakpoint(loc));
     await dispatch(actions.disableBreakpoint(breakpoint));
 
     const bp = selectors.getBreakpoint(getState(), loc);
     expect(bp && bp.options.condition).toBe(null);
 
     await dispatch(
       actions.setBreakpointOptions(loc, {
@@ -325,21 +396,22 @@ describe("breakpoints", () => {
     const newBreakpoint = selectors.getBreakpoint(getState(), loc);
     expect(newBreakpoint && !newBreakpoint.disabled).toBe(true);
     expect(newBreakpoint && newBreakpoint.options.condition).toBe(
       "const foo = 0"
     );
   });
 
   it("should remap breakpoints on pretty print", async () => {
-    const { dispatch, getState } = createStore(simpleMockThreadClient);
+    const { dispatch, getState } = createStore(mockClient({ "1": [0] }));
 
     const loc = {
       sourceId: "a.js",
       line: 1,
+      column: 0,
       sourceUrl: "http://localhost:8000/examples/a.js"
     };
 
     const source = makeSource("a.js");
     await dispatch(actions.newSource(source));
     await dispatch(actions.loadSourceText(source));
 
     await dispatch(actions.addBreakpoint(loc));
deleted file mode 100644
--- a/devtools/client/debugger/new/src/actions/breakpoints/tests/syncing.spec.js
+++ /dev/null
@@ -1,303 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
-
-// @flow
-
-jest.mock("../../../utils/source-maps", () => ({
-  getGeneratedLocation: jest.fn()
-}));
-import { getGeneratedLocation } from "../../../utils/source-maps";
-
-jest.mock("../../../utils/prefs", () => ({
-  prefs: {
-    expressions: [],
-    pendingBreakpoints: {}
-  },
-  features: {
-    replay: false
-  },
-  clear: jest.fn()
-}));
-
-import {
-  createStore,
-  selectors,
-  actions,
-  makeSource
-} from "../../../utils/test-head";
-
-import { makeBreakpointId } from "../../../utils/breakpoint";
-
-jest.mock("../../../utils/breakpoint/astBreakpointLocation", () => ({
-  findScopeByName: jest.fn(),
-  getASTLocation: jest.fn()
-}));
-
-// eslint-disable-next-line
-import { findScopeByName } from "../../../utils/breakpoint/astBreakpointLocation";
-
-import { syncBreakpointPromise } from "../../breakpoints/syncBreakpoint.js";
-
-function setBreakpoint(location, condition) {
-  const actualLocation = { ...location, line: location.line };
-
-  return Promise.resolve({
-    id: makeBreakpointId(location),
-    actualLocation,
-    condition
-  });
-}
-
-const clientBreakpoint = {
-  id: "foo",
-  actualLocation: {
-    sourceUrl: "http://localhost:8000/gen.js",
-    sourceId: "gen.js",
-    line: 3,
-    column: undefined
-  }
-};
-
-const threadClient = {
-  getBreakpointByLocation: () => clientBreakpoint,
-  setBreakpoint,
-  removeBreakpoint: jest.fn()
-};
-
-const sourceMaps = {
-  getOriginalLocation: () => ({
-    sourceId: "magic.js",
-    sourceUrl: "http://localhost:8000/magic.js",
-    line: 3,
-    column: undefined
-  }),
-  getOriginalURLs: () => {},
-  isOriginalId: () => true,
-  getGeneratedLocation: () => ({})
-};
-
-function pendingBreakpoint(overrides) {
-  return {
-    location: {
-      sourceId: "magic.js",
-      sourceUrl: "http://localhost:8000/magic.js",
-      line: 3,
-      column: undefined
-    },
-    generatedLocation: {
-      sourceId: "gen.js",
-      sourceUrl: "http://localhost:8000/gen.js",
-      line: 3,
-      column: undefined
-    },
-    astLocation: {
-      name: undefined,
-      offset: {
-        line: 3
-      },
-      index: 0
-    },
-    options: {
-      logValue: "",
-      hidden: false
-    },
-    disabled: false,
-    loading: false,
-    text: "",
-    ...overrides
-  };
-}
-
-function newGeneratedLocation(line) {
-  return {
-    sourceUrl: "http://localhost:8000/gen.js",
-    sourceId: "gen.js",
-    line,
-    column: undefined
-  };
-}
-
-describe("loading the debugger", () => {
-  it("loads the initial breakpoint state", async () => {
-    (getGeneratedLocation: any).mockImplementation(() =>
-      newGeneratedLocation(3)
-    );
-
-    const { dispatch, getState } = createStore(threadClient, {}, sourceMaps);
-
-    // add a source without the breakpoints
-    const reloadedSource = makeSource("magic.js");
-    await dispatch(actions.newSource(reloadedSource));
-
-    expect(selectors.getBreakpointCount(getState())).toEqual(0);
-    // manually sync
-    const update = await syncBreakpointPromise(
-      getState,
-      threadClient,
-      sourceMaps,
-      dispatch,
-      reloadedSource.id,
-      pendingBreakpoint()
-    );
-
-    expect(threadClient.removeBreakpoint.mock.calls).toHaveLength(0);
-    expect(update).toMatchSnapshot();
-  });
-
-  it("loads the initial breakpoint state with a changed file", async () => {
-    const location = { line: 9, column: 0 };
-    const generated = 3;
-    (getGeneratedLocation: any).mockImplementation(() =>
-      newGeneratedLocation(generated)
-    );
-    (findScopeByName: any).mockImplementation(() => ({
-      location: { start: location }
-    }));
-
-    const { dispatch, getState } = createStore(threadClient, {}, sourceMaps);
-
-    // add a source without the breakpoints
-    const reloadedSource = makeSource("magic.js");
-    await dispatch(actions.newSource(reloadedSource));
-
-    expect(selectors.getBreakpointCount(getState())).toEqual(0);
-    // manually sync
-    const update = await syncBreakpointPromise(
-      getState,
-      threadClient,
-      sourceMaps,
-      dispatch,
-      reloadedSource.id,
-      pendingBreakpoint()
-    );
-
-    expect(threadClient.removeBreakpoint.mock.calls).toHaveLength(0);
-    expect(update && update.breakpoint && update.breakpoint.location.line).toBe(
-      location.line + generated
-    );
-    expect(update).toMatchSnapshot();
-  });
-});
-
-describe("reloading debuggee", () => {
-  beforeEach(() => {
-    const location = { line: 0, column: 0 };
-    (getGeneratedLocation: any).mockImplementation(() =>
-      newGeneratedLocation(3)
-    );
-    (findScopeByName: any).mockImplementation(() => ({
-      location: { start: location }
-    }));
-  });
-
-  it("syncs with unchanged source with an existing BP", async () => {
-    const { dispatch, getState } = createStore(threadClient, {}, sourceMaps);
-
-    // add a source without the breakpoints
-    const reloadedSource = makeSource("magic.js");
-    const loc1 = {
-      sourceId: "magic.js",
-      sourceUrl: "http://localhost:8000/magic.js",
-      line: 3,
-      column: undefined
-    };
-    const generatedSource = makeSource("gen.js");
-    await dispatch(actions.newSource(reloadedSource));
-    await dispatch(actions.newSource(generatedSource));
-    await dispatch(actions.addBreakpoint(loc1));
-
-    // manually sync
-    const update = await syncBreakpointPromise(
-      getState,
-      threadClient,
-      sourceMaps,
-      dispatch,
-      reloadedSource.id,
-      pendingBreakpoint({ location: loc1 })
-    );
-    expect(threadClient.removeBreakpoint.mock.calls).toHaveLength(0);
-    expect(update).toMatchSnapshot();
-  });
-
-  it("updates a corresponding breakpoint for a changed source", async () => {
-    /*
-      This is a complicated test, so bear with us. In this scenario,
-
-      1. the user has a small app with a generated file gen.js
-      and original file magic.js.
-      2. The user adds a breakpoint in magic.js#3, which maps to gen.js#3
-      3. The user edits their code and reloads
-      4. when magic.js is added, the debugger syncs the saved breakpoint
-         4.a. the debugger checks to see if gen.js#3 still points to magic.js#3,
-              it now points to gen.js#1 so it removes the old
-              breakpoint and creates a new one
-    */
-
-    // here we are mocking out what happens when the source changed, and the
-    // new line for originalSource line 3, is the generated Source line 5
-
-    (getGeneratedLocation: any).mockImplementation(() =>
-      newGeneratedLocation(5)
-    );
-    // end mocking out
-
-    const { dispatch, getState } = createStore(threadClient, {}, sourceMaps);
-
-    // add a source without the breakpoints
-    const reloadedSource = makeSource("magic.js");
-    await dispatch(actions.newSource(reloadedSource));
-
-    const generatedSource = makeSource("gen.js");
-    await dispatch(actions.newSource(generatedSource));
-
-    // manually sync
-    const update = await syncBreakpointPromise(
-      getState,
-      threadClient,
-      sourceMaps,
-      dispatch,
-      reloadedSource.id,
-      pendingBreakpoint()
-    );
-    expect(threadClient.removeBreakpoint.mock.calls).toHaveLength(1);
-    expect(findScopeByName).toHaveBeenCalled();
-    expect(update).toMatchSnapshot();
-  });
-
-  it("syncs with changed source and an existing disabled BP", async () => {
-    (getGeneratedLocation: any).mockImplementationOnce(() =>
-      newGeneratedLocation(5)
-    );
-
-    const { dispatch, getState } = createStore(threadClient, {}, sourceMaps);
-
-    const reloadedSource = makeSource("magic.js");
-    await dispatch(actions.newSource(reloadedSource));
-
-    const generatedSource = makeSource("gen.js");
-    await dispatch(actions.newSource(generatedSource));
-
-    const location = {
-      sourceId: reloadedSource.id,
-      line: 3,
-      column: undefined
-    };
-
-    const breakpoint = await dispatch(actions.addBreakpoint(location));
-    await dispatch(actions.disableBreakpoint(breakpoint));
-
-    (getGeneratedLocation: any).mockImplementationOnce(() =>
-      newGeneratedLocation(1)
-    );
-
-    await dispatch(
-      actions.syncBreakpoint(
-        reloadedSource.id,
-        pendingBreakpoint({ disabled: true })
-      )
-    );
-
-    expect(selectors.getPendingBreakpoints(getState())).toMatchSnapshot();
-  });
-});
--- a/devtools/client/debugger/new/src/actions/pause/tests/pause.spec.js
+++ b/devtools/client/debugger/new/src/actions/pause/tests/pause.spec.js
@@ -25,17 +25,17 @@ const mockThreadClient = {
   stepIn: () =>
     new Promise(_resolve => {
       stepInResolve = _resolve;
     }),
   stepOver: () => new Promise(_resolve => _resolve),
   evaluate: async () => {},
   evaluateInFrame: async () => {},
   evaluateExpressions: async () => {},
-
+  resume: async () => {},
   getFrameScopes: async frame => frame.scope,
   setBreakpoint: () => new Promise(_resolve => {}),
   sourceContents: ({ source }) => {
     return new Promise((resolve, reject) => {
       switch (source) {
         case "foo1":
           return resolve({
             source: "function foo1() {\n  return 5;\n}",
@@ -64,17 +64,18 @@ const mockThreadClient = {
           });
         case "foo-wasm/originalSource":
           return resolve({
             source: "fn fooBar() {}\nfn barZoo() { fooBar() }",
             contentType: "text/rust"
           });
       }
     });
-  }
+  },
+  getBreakpointPositions: async () => ({})
 };
 
 const mockFrameId = "1";
 
 function createPauseInfo(
   frameLocation = { sourceId: "foo1", line: 2 },
   frameOpts = {}
 ) {
@@ -315,17 +316,18 @@ describe("pause", () => {
       ];
 
       const sourceMapsMock = {
         getOriginalStackFrames: loc => Promise.resolve(originStackFrames),
         getOriginalLocation: () => Promise.resolve(originalLocation),
         getOriginalSourceText: async () => ({
           source: "fn fooBar() {}\nfn barZoo() { fooBar() }",
           contentType: "text/rust"
-        })
+        }),
+        getGeneratedRangesForOriginal: async () => []
       };
 
       const store = createStore(mockThreadClient, {}, sourceMapsMock);
       const { dispatch, getState } = store;
       const mockPauseInfo = createPauseInfo(generatedLocation);
 
       const source = makeSource("foo-wasm", { isWasm: true });
       const originalSource = makeOriginalSource("foo-wasm");
--- a/devtools/client/debugger/new/src/actions/sources/loadSourceText.js
+++ b/devtools/client/debugger/new/src/actions/sources/loadSourceText.js
@@ -1,16 +1,18 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
 
 // @flow
 
 import { PROMISE } from "../utils/middleware/promise";
 import { getGeneratedSource, getSource } from "../../selectors";
+import { setBreakpointPositions } from "../breakpoints";
+
 import * as parser from "../../workers/parser";
 import { isLoaded, isOriginal } from "../../utils/source";
 import { Telemetry } from "devtools-modules";
 
 import defer from "../../utils/defer";
 import type { ThunkArgs } from "../types";
 
 import type { Source } from "../../types";
@@ -81,18 +83,19 @@ export function loadSourceText(source: ?
       return;
     }
 
     if (isOriginal(newSource) && !newSource.isWasm) {
       const generatedSource = getGeneratedSource(getState(), source);
       await dispatch(loadSourceText(generatedSource));
     }
 
-    if (!newSource.isWasm) {
+    if (!newSource.isWasm && isLoaded(newSource)) {
       await parser.setSource(newSource);
+      await dispatch(setBreakpointPositions(newSource.id));
     }
 
     // signal that the action is finished
     deferred.resolve();
     requests.delete(id);
 
     return source;
   };
--- a/devtools/client/debugger/new/src/actions/sources/prettyPrint.js
+++ b/devtools/client/debugger/new/src/actions/sources/prettyPrint.js
@@ -1,17 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
 
 // @flow
 
 import assert from "../../utils/assert";
 import { recordEvent } from "../../utils/telemetry";
-import { remapBreakpoints } from "../breakpoints";
+import { remapBreakpoints, setBreakpointPositions } from "../breakpoints";
 
 import { setSymbols } from "../ast";
 import { prettyPrint } from "../../workers/pretty-print";
 import { setSource } from "../../workers/parser";
 import { getPrettySourceURL, isLoaded } from "../../utils/source";
 import { loadSourceText } from "./loadSourceText";
 import { mapFrames } from "../pause";
 import { selectSpecificLocation } from "../sources";
@@ -61,18 +61,18 @@ export function createPrettySource(sourc
 
     const loadedPrettySource: JsSource = {
       ...prettySource,
       text: code,
       loadedState: "loaded"
     };
 
     setSource(loadedPrettySource);
-
     dispatch(({ type: "UPDATE_SOURCE", source: loadedPrettySource }: Action));
+    await dispatch(setBreakpointPositions(loadedPrettySource.id));
 
     return prettySource;
   };
 }
 
 /**
  * Toggle the pretty printing of a source's text. All subsequent calls to
  * |getText| will return the pretty-toggled text. Nothing will happen for
--- a/devtools/client/debugger/new/src/actions/sources/select.js
+++ b/devtools/client/debugger/new/src/actions/sources/select.js
@@ -18,17 +18,17 @@ import { closeActiveSearch, updateActive
 
 import { togglePrettyPrint } from "./prettyPrint";
 import { addTab, closeTab } from "../tabs";
 import { loadSourceText } from "./loadSourceText";
 
 import { prefs } from "../../utils/prefs";
 import { shouldPrettyPrint, isMinified } from "../../utils/source";
 import { createLocation } from "../../utils/location";
-import { getMappedLocation } from "../../utils/source-maps";
+import { mapLocation } from "../../utils/source-maps";
 
 import {
   getSource,
   getSourceByURL,
   getPrettySource,
   getActiveSearch,
   getSelectedLocation,
   getSelectedSource
@@ -128,17 +128,17 @@ export function selectLocation(
     // Preserve the current source map context (original / generated)
     // when navigting to a new location.
     const selectedSource = getSelectedSource(getState());
     if (
       keepContext &&
       selectedSource &&
       isOriginalId(selectedSource.id) != isOriginalId(location.sourceId)
     ) {
-      location = await getMappedLocation(getState(), sourceMaps, location);
+      location = await mapLocation(getState(), sourceMaps, location);
       source = getSourceFromId(getState(), location.sourceId);
     }
 
     const tabSources = getSourcesForTabs(getState());
     if (!tabSources.includes(source)) {
       dispatch(addTab(source));
     }
 
@@ -187,21 +187,17 @@ export function selectSpecificLocation(l
  * @static
  */
 export function jumpToMappedLocation(location: SourceLocation) {
   return async function({ dispatch, getState, client, sourceMaps }: ThunkArgs) {
     if (!client) {
       return;
     }
 
-    const pairedLocation = await getMappedLocation(
-      getState(),
-      sourceMaps,
-      location
-    );
+    const pairedLocation = await mapLocation(getState(), sourceMaps, location);
 
     return dispatch(selectSpecificLocation({ ...pairedLocation }));
   };
 }
 
 export function jumpToMappedSelectedLocation() {
   return async function({ dispatch, getState }: ThunkArgs) {
     const location = getSelectedLocation(getState());
--- a/devtools/client/debugger/new/src/actions/sources/tests/loadSource.spec.js
+++ b/devtools/client/debugger/new/src/actions/sources/tests/loadSource.spec.js
@@ -41,17 +41,18 @@ describe("loadSourceText", () => {
   it("loads two sources w/ one request", async () => {
     let resolve;
     let count = 0;
     const { dispatch, getState } = createStore({
       sourceContents: () =>
         new Promise(r => {
           count++;
           resolve = r;
-        })
+        }),
+      getBreakpointPositions: async () => ({})
     });
     const id = "foo";
     const baseSource = makeSource(id, { loadedState: "unloaded" });
 
     await dispatch(actions.newSource(baseSource));
 
     let source = selectors.getSource(getState(), id);
     dispatch(actions.loadSourceText(source));
@@ -73,17 +74,18 @@ describe("loadSourceText", () => {
   it("doesn't re-load loaded sources", async () => {
     let resolve;
     let count = 0;
     const { dispatch, getState } = createStore({
       sourceContents: () =>
         new Promise(r => {
           count++;
           resolve = r;
-        })
+        }),
+      getBreakpointPositions: async () => ({})
     });
     const id = "foo";
     const baseSource = makeSource(id, { loadedState: "unloaded" });
 
     await dispatch(actions.newSource(baseSource));
     let source = selectors.getSource(getState(), id);
     const loading = dispatch(actions.loadSourceText(source));
 
--- a/devtools/client/debugger/new/src/actions/sources/tests/select.spec.js
+++ b/devtools/client/debugger/new/src/actions/sources/tests/select.spec.js
@@ -225,17 +225,18 @@ describe("sources", () => {
 
   it("should keep the original the viewing context", async () => {
     const { dispatch, getState } = createStore(
       sourceThreadClient,
       {},
       {
         getOriginalLocation: async location => ({ ...location, line: 12 }),
         getGeneratedLocation: async location => ({ ...location, line: 12 }),
-        getOriginalSourceText: async () => ({ source: "" })
+        getOriginalSourceText: async () => ({ source: "" }),
+        getGeneratedRangesForOriginal: async () => []
       }
     );
 
     const baseSource = makeSource("base.js");
     await dispatch(actions.newSource(baseSource));
 
     const originalBaseSource = makeOriginalSource("base.js");
     await dispatch(actions.newSource(originalBaseSource));
@@ -249,20 +250,26 @@ describe("sources", () => {
     const selected = getSelectedLocation(getState());
     expect(selected && selected.line).toBe(12);
   });
 
   it("should change the original the viewing context", async () => {
     const { dispatch, getState } = createStore(
       sourceThreadClient,
       {},
-      { getOriginalLocation: async location => ({ ...location, line: 12 }) }
+      {
+        getOriginalLocation: async location => ({ ...location, line: 12 }),
+        getGeneratedRangesForOriginal: async () => [],
+        getOriginalSourceText: async () => ({ source: "" })
+      }
     );
 
+    await dispatch(actions.newSource(makeSource("base.js")));
     const baseSource = makeOriginalSource("base.js");
+
     await dispatch(actions.newSource(baseSource));
     await dispatch(actions.selectSource(baseSource.id));
 
     await dispatch(
       actions.selectSpecificLocation({
         sourceId: baseSource.id,
         line: 1
       })
--- a/devtools/client/debugger/new/src/actions/tests/__snapshots__/pending-breakpoints.spec.js.snap
+++ b/devtools/client/debugger/new/src/actions/tests/__snapshots__/pending-breakpoints.spec.js.snap
@@ -1,28 +1,28 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
 exports[`initializing when pending breakpoints exist in prefs syncs pending breakpoints 1`] = `
 Object {
-  "http://localhost:8000/examples/bar.js:5:": Object {
+  "http://localhost:8000/examples/bar.js:5:2": Object {
     "astLocation": Object {
       "index": 0,
       "name": undefined,
       "offset": Object {
         "line": 5,
       },
     },
     "disabled": false,
     "generatedLocation": Object {
-      "column": undefined,
+      "column": 2,
       "line": 5,
       "sourceUrl": "http://localhost:8000/examples/bar.js",
     },
     "location": Object {
-      "column": undefined,
+      "column": 2,
       "line": 5,
       "sourceId": "",
       "sourceUrl": "http://localhost:8000/examples/bar.js",
     },
     "options": Object {
       "condition": null,
       "hidden": false,
     },
@@ -31,30 +31,30 @@ Object {
 `;
 
 exports[`when adding breakpoints a corresponding pending breakpoint should be added 1`] = `
 Object {
   "astLocation": Object {
     "index": 0,
     "name": undefined,
     "offset": Object {
-      "column": 0,
+      "column": 1,
       "line": 5,
-      "sourceId": "foo.js/originalSource",
+      "sourceId": "foo.js",
       "sourceUrl": "http://localhost:8000/examples/foo.js",
     },
   },
   "disabled": false,
   "generatedLocation": Object {
-    "column": undefined,
+    "column": 1,
     "line": 5,
     "sourceUrl": "http://localhost:8000/examples/foo.js",
   },
   "location": Object {
-    "column": 0,
+    "column": 1,
     "line": 5,
     "sourceUrl": "http://localhost:8000/examples/foo.js",
   },
   "options": Object {
     "condition": null,
     "hidden": false,
     "logValue": null,
   },
@@ -64,23 +64,23 @@ Object {
 exports[`when adding breakpoints adding and deleting breakpoints add a corresponding pendingBreakpoint for each addition 1`] = `
 Object {
   "astLocation": Object {
     "index": 0,
     "name": undefined,
     "offset": Object {
       "column": 0,
       "line": 5,
-      "sourceId": "foo/originalSource",
+      "sourceId": "foo",
       "sourceUrl": "http://localhost:8000/examples/foo",
     },
   },
   "disabled": false,
   "generatedLocation": Object {
-    "column": undefined,
+    "column": 0,
     "line": 5,
     "sourceUrl": "http://localhost:8000/examples/foo",
   },
   "location": Object {
     "column": 0,
     "line": 5,
     "sourceUrl": "http://localhost:8000/examples/foo",
   },
@@ -95,23 +95,23 @@ Object {
 exports[`when adding breakpoints adding and deleting breakpoints add a corresponding pendingBreakpoint for each addition 2`] = `
 Object {
   "astLocation": Object {
     "index": 0,
     "name": undefined,
     "offset": Object {
       "column": 0,
       "line": 5,
-      "sourceId": "foo2/originalSource",
+      "sourceId": "foo2",
       "sourceUrl": "http://localhost:8000/examples/foo2",
     },
   },
   "disabled": false,
   "generatedLocation": Object {
-    "column": undefined,
+    "column": 0,
     "line": 5,
     "sourceUrl": "http://localhost:8000/examples/foo2",
   },
   "location": Object {
     "column": 0,
     "line": 5,
     "sourceUrl": "http://localhost:8000/examples/foo2",
   },
--- a/devtools/client/debugger/new/src/actions/tests/ast.spec.js
+++ b/devtools/client/debugger/new/src/actions/tests/ast.spec.js
@@ -30,25 +30,27 @@ import { prefs } from "../../utils/prefs
 const threadClient = {
   sourceContents: async ({ source }) => ({
     source: sourceTexts[source],
     contentType: "text/javascript"
   }),
   getFrameScopes: async () => {},
   evaluate: async expression => ({ result: evaluationResult[expression] }),
   evaluateExpressions: async expressions =>
-    expressions.map(expression => ({ result: evaluationResult[expression] }))
+    expressions.map(expression => ({ result: evaluationResult[expression] })),
+  getBreakpointPositions: async () => ({})
 };
 
 const sourceMaps = {
   getOriginalSourceText: async ({ id }) => ({
     id,
     text: sourceTexts[id],
     contentType: "text/javascript"
-  })
+  }),
+  getGeneratedRangesForOriginal: async () => []
 };
 
 const sourceTexts = {
   "base.js": "function base(boo) {}",
   "foo.js": "function base(boo) { return this.bazz; } outOfScope",
   "scopes.js": readFixture("scopes.js"),
   "reactComponent.js/originalSource": readFixture("reactComponent.js"),
   "reactFuncComponent.js/originalSource": readFixture("reactFuncComponent.js")
--- a/devtools/client/debugger/new/src/actions/tests/helpers/breakpoints.js
+++ b/devtools/client/debugger/new/src/actions/tests/helpers/breakpoints.js
@@ -6,22 +6,22 @@
 
 export function mockPendingBreakpoint(overrides: Object = {}) {
   const { sourceUrl, line, column, condition, disabled, hidden } = overrides;
   return {
     location: {
       sourceId: "",
       sourceUrl: sourceUrl || "http://localhost:8000/examples/bar.js",
       line: line || 5,
-      column: column || undefined
+      column: column || 1
     },
     generatedLocation: {
       sourceUrl: sourceUrl || "http://localhost:8000/examples/bar.js",
       line: line || 5,
-      column: column || undefined
+      column: column || 1
     },
     astLocation: {
       name: undefined,
       offset: {
         line: line || 5
       },
       index: 0
     },
--- a/devtools/client/debugger/new/src/actions/tests/helpers/threadClient.js
+++ b/devtools/client/debugger/new/src/actions/tests/helpers/threadClient.js
@@ -71,10 +71,11 @@ export const sourceThreadClient = {
         resolve(createSource(source));
       }
 
       reject(`unknown source: ${source}`);
     });
   },
   threadClient: async () => {},
   getFrameScopes: async () => {},
-  evaluateExpressions: async () => {}
+  evaluateExpressions: async () => {},
+  getBreakpointPositions: async () => ({})
 };
--- a/devtools/client/debugger/new/src/actions/tests/navigation.spec.js
+++ b/devtools/client/debugger/new/src/actions/tests/navigation.spec.js
@@ -18,21 +18,21 @@ const {
   getTextSearchQuery,
   getTextSearchResults,
   getTextSearchStatus,
   getFileSearchQuery,
   getFileSearchResults
 } = selectors;
 
 const threadClient = {
-  sourceContents: () =>
-    Promise.resolve({
-      source: "function foo1() {\n  const foo = 5; return foo;\n}",
-      contentType: "text/javascript"
-    })
+  sourceContents: async () => ({
+    source: "function foo1() {\n  const foo = 5; return foo;\n}",
+    contentType: "text/javascript"
+  }),
+  getBreakpointPositions: async () => ({})
 };
 
 describe("navigation", () => {
   it("connect sets the debuggeeUrl", async () => {
     const { dispatch, getState } = createStore({
       fetchWorkers: () => Promise.resolve([]),
       getMainThread: () => "FakeThread"
     });
--- a/devtools/client/debugger/new/src/actions/tests/pending-breakpoints.spec.js
+++ b/devtools/client/debugger/new/src/actions/tests/pending-breakpoints.spec.js
@@ -10,18 +10,18 @@ import {
   mockPendingBreakpoint
 } from "./helpers/breakpoints.js";
 
 import { simpleMockThreadClient } from "./helpers/threadClient.js";
 
 import { asyncStore } from "../../utils/prefs";
 
 function loadInitialState(opts = {}) {
-  const mockedPendingBreakpoint = mockPendingBreakpoint(opts);
-  const id = makePendingLocationId(mockedPendingBreakpoint.location);
+  const mockedPendingBreakpoint = mockPendingBreakpoint({...opts, column: 2});
+  const id = makePendingLocationId(mockedPendingBreakpoint.location)
   asyncStore.pendingBreakpoints = { [id]: mockedPendingBreakpoint };
 
   return { pendingBreakpoints: asyncStore.pendingBreakpoints };
 }
 
 jest.mock("../../utils/prefs", () => ({
   prefs: {
     clientSourceMapsEnabled: true,
@@ -42,31 +42,51 @@ import {
   createStore,
   selectors,
   actions,
   makeOriginalSource,
   makeSource,
   waitForState
 } from "../../utils/test-head";
 
+import sourceMaps from "devtools-source-map";
+
 import { makePendingLocationId } from "../../utils/breakpoint";
+function mockClient(bpPos = {}) {
+  return {
+    ...simpleMockThreadClient,
+
+    getBreakpointPositions: async () => bpPos
+  };
+}
+
+function mockSourceMaps() {
+  return {
+    ...sourceMaps,
+    getOriginalSourceText: async (source) => ({id: source.id, text: "", contentType: "text/javascript"}),
+    getGeneratedRangesForOriginal: async () => [
+      { start: { line: 0, column: 0 }, end: { line: 10, column: 10 } }
+    ]
+  };
+}
 
 describe("when adding breakpoints", () => {
   it("a corresponding pending breakpoint should be added", async () => {
     const { dispatch, getState } = createStore(
-      simpleMockThreadClient,
-      loadInitialState()
+      mockClient({ "5": [1] }),
+      loadInitialState(),
+      mockSourceMaps()
     );
 
     const source = makeOriginalSource("foo.js");
     await dispatch(actions.newSource(source));
     await dispatch(actions.newSource(makeSource("foo.js")));
     await dispatch(actions.loadSourceText(source));
 
-    const bp = generateBreakpoint("foo.js");
+    const bp = generateBreakpoint("foo.js", 5, 1);
     const id = makePendingLocationId(bp.location);
 
     await dispatch(actions.addBreakpoint(bp.location));
     const pendingBps = selectors.getPendingBreakpoints(getState());
 
     expect(selectors.getPendingBreakpointList(getState())).toHaveLength(2);
     expect(pendingBps[id]).toMatchSnapshot();
   });
@@ -81,18 +101,19 @@ describe("when adding breakpoints", () =
       breakpoint1 = generateBreakpoint("foo");
       breakpoint2 = generateBreakpoint("foo2");
       breakpointLocationId1 = makePendingLocationId(breakpoint1.location);
       breakpointLocationId2 = makePendingLocationId(breakpoint2.location);
     });
 
     it("add a corresponding pendingBreakpoint for each addition", async () => {
       const { dispatch, getState } = createStore(
-        simpleMockThreadClient,
-        loadInitialState()
+        mockClient({ "5": [0] }),
+        loadInitialState(),
+        mockSourceMaps()
       );
 
       const source1 = makeOriginalSource("foo");
       const source2 = makeOriginalSource("foo2");
 
       await dispatch(actions.newSource(makeSource("foo")));
       await dispatch(actions.newSource(makeSource("foo2")));
 
@@ -101,24 +122,29 @@ describe("when adding breakpoints", () =
 
       await dispatch(actions.loadSourceText(source1));
       await dispatch(actions.loadSourceText(source2));
 
       await dispatch(actions.addBreakpoint(breakpoint1.location));
       await dispatch(actions.addBreakpoint(breakpoint2.location));
 
       const pendingBps = selectors.getPendingBreakpoints(getState());
+
+      // NOTE the sourceId should be `foo2/originalSource`, but is `foo2`
+      // because we do not have a real source map for `getOriginalLocation`
+      // to map.
       expect(pendingBps[breakpointLocationId1]).toMatchSnapshot();
       expect(pendingBps[breakpointLocationId2]).toMatchSnapshot();
     });
 
     it("hidden breakponts do not create pending bps", async () => {
       const { dispatch, getState } = createStore(
-        simpleMockThreadClient,
-        loadInitialState()
+        mockClient({ "5": [0] }),
+        loadInitialState(),
+        mockSourceMaps()
       );
 
       const source = makeOriginalSource("foo");
       await dispatch(actions.newSource(makeSource("foo")));
       await dispatch(actions.newSource(source));
       await dispatch(actions.loadSourceText(source));
 
       await dispatch(
@@ -126,18 +152,19 @@ describe("when adding breakpoints", () =
       );
       const pendingBps = selectors.getPendingBreakpoints(getState());
 
       expect(pendingBps[breakpointLocationId1]).toBeUndefined();
     });
 
     it("remove a corresponding pending breakpoint when deleting", async () => {
       const { dispatch, getState } = createStore(
-        simpleMockThreadClient,
-        loadInitialState()
+        mockClient({ "5": [0] }),
+        loadInitialState(),
+        mockSourceMaps()
       );
 
       await dispatch(actions.newSource(makeSource("foo")));
       await dispatch(actions.newSource(makeSource("foo2")));
 
       const source1 = makeOriginalSource("foo");
       const source2 = makeOriginalSource("foo2");
 
@@ -156,18 +183,19 @@ describe("when adding breakpoints", () =
       expect(pendingBps.hasOwnProperty(breakpointLocationId2)).toBe(true);
     });
   });
 });
 
 describe("when changing an existing breakpoint", () => {
   it("updates corresponding pendingBreakpoint", async () => {
     const { dispatch, getState } = createStore(
-      simpleMockThreadClient,
-      loadInitialState()
+      mockClient({ "5": [0] }),
+      loadInitialState(),
+      mockSourceMaps()
     );
     const bp = generateBreakpoint("foo");
     const id = makePendingLocationId(bp.location);
 
     const source = makeOriginalSource("foo");
     await dispatch(actions.newSource(source));
     await dispatch(actions.newSource(makeSource("foo")));
     await dispatch(actions.loadSourceText(source));
@@ -178,18 +206,19 @@ describe("when changing an existing brea
     );
     const bps = selectors.getPendingBreakpoints(getState());
     const breakpoint = bps[id];
     expect(breakpoint.options.condition).toBe("2");
   });
 
   it("if disabled, updates corresponding pendingBreakpoint", async () => {
     const { dispatch, getState } = createStore(
-      simpleMockThreadClient,
-      loadInitialState()
+      mockClient({ "5": [0] }),
+      loadInitialState(),
+      mockSourceMaps()
     );
     const bp = generateBreakpoint("foo");
     const id = makePendingLocationId(bp.location);
 
     await dispatch(actions.newSource(makeSource("foo")));
 
     const source = makeOriginalSource("foo");
     await dispatch(actions.newSource(source));
@@ -199,18 +228,19 @@ describe("when changing an existing brea
     await dispatch(actions.disableBreakpoint(bp));
     const bps = selectors.getPendingBreakpoints(getState());
     const breakpoint = bps[id];
     expect(breakpoint.disabled).toBe(true);
   });
 
   it("does not delete the pre-existing pendingBreakpoint", async () => {
     const { dispatch, getState } = createStore(
-      simpleMockThreadClient,
-      loadInitialState()
+      mockClient({ "5": [0] }),
+      loadInitialState(),
+      mockSourceMaps()
     );
     const bp = generateBreakpoint("foo.js");
 
     const source = makeOriginalSource("foo.js");
     await dispatch(actions.newSource(source));
     await dispatch(actions.newSource(makeSource("foo.js")));
     await dispatch(actions.loadSourceText(source));
 
@@ -224,46 +254,48 @@ describe("when changing an existing brea
     const breakpoint = bps[id];
     expect(breakpoint.options.condition).toBe("2");
   });
 });
 
 describe("initializing when pending breakpoints exist in prefs", () => {
   it("syncs pending breakpoints", async () => {
     const { getState } = createStore(
-      simpleMockThreadClient,
-      loadInitialState()
+      mockClient({ "5": [0] }),
+      loadInitialState(),
+      mockSourceMaps()
     );
     const bps = selectors.getPendingBreakpoints(getState());
     expect(bps).toMatchSnapshot();
   });
 
   it("re-adding breakpoints update existing pending breakpoints", async () => {
     const { dispatch, getState } = createStore(
-      simpleMockThreadClient,
-      loadInitialState()
+      mockClient({ "5": [1, 2] }),
+      loadInitialState(),
+      mockSourceMaps()
     );
-    const bar = generateBreakpoint("bar.js");
+    const bar = generateBreakpoint("bar.js", 5, 1);
 
     await dispatch(actions.newSource(makeSource("bar.js")));
 
     const source = makeOriginalSource("bar.js");
     await dispatch(actions.newSource(source));
     await dispatch(actions.loadSourceText(source));
-
     await dispatch(actions.addBreakpoint(bar.location));
 
     const bps = selectors.getPendingBreakpointList(getState());
-    expect(bps).toHaveLength(1);
+    expect(bps).toHaveLength(2);
   });
 
   it("adding bps doesn't remove existing pending breakpoints", async () => {
     const { dispatch, getState } = createStore(
-      simpleMockThreadClient,
-      loadInitialState()
+      mockClient({ "5": [0] }),
+      loadInitialState(),
+      mockSourceMaps()
     );
     const bp = generateBreakpoint("foo.js");
 
     const source = makeOriginalSource("foo.js");
     await dispatch(actions.newSource(source));
     await dispatch(actions.newSource(makeSource("foo.js")));
     await dispatch(actions.loadSourceText(source));
 
@@ -272,49 +304,54 @@ describe("initializing when pending brea
     const bps = selectors.getPendingBreakpointList(getState());
     expect(bps).toHaveLength(2);
   });
 });
 
 describe("initializing with disabled pending breakpoints in prefs", () => {
   it("syncs breakpoints with pending breakpoints", async () => {
     const store = createStore(
-      simpleMockThreadClient,
-      loadInitialState({ disabled: true })
+      mockClient({ "5": [2] }),
+      loadInitialState({ disabled: true }),
+      mockSourceMaps()
     );
 
     const { getState, dispatch } = store;
     const source = makeOriginalSource("bar.js");
 
     await dispatch(actions.newSource(makeSource("bar.js")));
     await dispatch(actions.newSource(source));
     await dispatch(actions.loadSourceText(source));
 
     await waitForState(store, state => {
       const bps = selectors.getBreakpointsForSource(state, source.id);
       return bps && Object.values(bps).length > 0;
     });
 
     const bp = selectors.getBreakpointForLocation(getState(), {
       line: 5,
-      column: undefined,
+      column: 2,
       sourceUrl: source.url,
       sourceId: source.id
     });
     if (!bp) {
       throw new Error("no bp");
     }
     expect(bp.location.sourceId).toEqual(source.id);
     expect(bp.disabled).toEqual(true);
   });
 });
 
 describe("adding sources", () => {
   it("corresponding breakpoints are added for a single source", async () => {
-    const store = createStore(simpleMockThreadClient, loadInitialState());
+    const store = createStore(
+      mockClient({ "5": [2] }),
+      loadInitialState({ disabled: true }),
+      mockSourceMaps()
+    );
     const { getState, dispatch } = store;
 
     expect(selectors.getBreakpointCount(getState())).toEqual(0);
 
     const source = makeOriginalSource("bar.js");
 
     await dispatch(actions.newSource(makeSource("bar.js")));
     await dispatch(actions.newSource(source));
@@ -322,41 +359,52 @@ describe("adding sources", () => {
 
     await waitForState(store, state => selectors.getBreakpointCount(state) > 0);
 
     expect(selectors.getBreakpointCount(getState())).toEqual(1);
   });
 
   it("corresponding breakpoints are added to the original source", async () => {
     const source = makeOriginalSource("bar.js", { sourceMapURL: "foo" });
-    const store = createStore(simpleMockThreadClient, loadInitialState(), {
-      getOriginalURLs: async () => [source.url],
-      getOriginalSourceText: async () => ({ source: "" }),
-      getGeneratedLocation: async (location, _source) => ({
-        line: location.line,
-        column: location.column,
-        sourceId: _source.id
-      }),
-      getOriginalLocation: async location => location
-    });
+    const store = createStore(
+      mockClient({ "5": [2] }), 
+      loadInitialState(), 
+      {
+        getOriginalURLs: async () => [source.url],
+        getOriginalSourceText: async () => ({ source: "" }),
+        getGeneratedLocation: async (location, _source) => ({
+          line: location.line,
+          column: location.column,
+          sourceId: _source.id
+        }),
+        getOriginalLocation: async location => location,
+        getGeneratedRangesForOriginal: async () => [
+          { start: { line: 0, column: 0 }, end: { line: 10, column: 10 } }
+        ]
+      }
+    );
 
     const { getState, dispatch } = store;
 
     expect(selectors.getBreakpointCount(getState())).toEqual(0);
 
     await dispatch(actions.newSource(makeSource("bar.js")));
     await dispatch(actions.newSource(source));
 
     await waitForState(store, state => selectors.getBreakpointCount(state) > 0);
 
     expect(selectors.getBreakpointCount(getState())).toEqual(1);
   });
 
   it("add corresponding breakpoints for multiple sources", async () => {
-    const store = createStore(simpleMockThreadClient, loadInitialState());
+    const store = createStore(
+      mockClient({ "5": [2] }),
+      loadInitialState({ disabled: true }),
+      mockSourceMaps()
+    );
     const { getState, dispatch } = store;
 
     expect(selectors.getBreakpointCount(getState())).toEqual(0);
 
     const source1 = makeOriginalSource("bar.js");
     const source2 = makeOriginalSource("foo.js");
     await dispatch(actions.newSource(makeSource("bar.js")));
     await dispatch(actions.newSource(makeSource("foo.js")));
--- a/devtools/client/debugger/new/src/actions/tests/project-text-search.spec.js
+++ b/devtools/client/debugger/new/src/actions/tests/project-text-search.spec.js
@@ -13,49 +13,38 @@ import {
 
 const {
   getSource,
   getTextSearchQuery,
   getTextSearchResults,
   getTextSearchStatus
 } = selectors;
 
+const sources = {
+  foo1: {
+    source: "function foo1() {\n  const foo = 5; return foo;\n}",
+    contentType: "text/javascript"
+  },
+  foo2: {
+    source: "function foo2(x, y) {\n  return x + y;\n}",
+    contentType: "text/javascript"
+  },
+  bar: {
+    source: "function bla(x, y) {\n const bar = 4; return 2;\n}",
+    contentType: "text/javascript"
+  },
+  "bar:formatted": {
+    source: "function bla(x, y) {\n const bar = 4; return 2;\n}",
+    contentType: "text/javascript"
+  }
+};
+
 const threadClient = {
-  sourceContents: function({ source }) {
-    return new Promise((resolve, reject) => {
-      switch (source) {
-        case "foo1":
-          resolve({
-            source: "function foo1() {\n  const foo = 5; return foo;\n}",
-            contentType: "text/javascript"
-          });
-          break;
-        case "foo2":
-          resolve({
-            source: "function foo2(x, y) {\n  return x + y;\n}",
-            contentType: "text/javascript"
-          });
-          break;
-        case "bar":
-          resolve({
-            source: "function bla(x, y) {\n const bar = 4; return 2;\n}",
-            contentType: "text/javascript"
-          });
-          break;
-        case "bar:formatted":
-          resolve({
-            source: "function bla(x, y) {\n const bar = 4; return 2;\n}",
-            contentType: "text/javascript"
-          });
-          break;
-      }
-
-      reject(`unknown source: ${source}`);
-    });
-  }
+  sourceContents: async ({ source }) => sources[source],
+  getBreakpointPositions: async () => ({})
 };
 
 describe("project text search", () => {
   it("should add a project text search query", () => {
     const { dispatch, getState } = createStore();
     const mockQuery = "foo";
 
     dispatch(actions.addSearchQuery(mockQuery));
@@ -82,17 +71,18 @@ describe("project text search", () => {
     const source1 = makeSource("bar", { sourceMapURL: "bar:formatted" });
     const source2 = makeSource("bar:formatted");
 
     const mockMaps = {
       getOriginalSourceText: async () => ({
         source: "function bla(x, y) {\n const bar = 4; return 2;\n}",
         contentType: "text/javascript"
       }),
-      getOriginalURLs: async () => [source2.url]
+      getOriginalURLs: async () => [source2.url],
+      getGeneratedRangesForOriginal: async () => []
     };
 
     const { dispatch, getState } = createStore(threadClient, {}, mockMaps);
     const mockQuery = "bla";
 
     await dispatch(actions.newSource(source1));
     await dispatch(actions.newSource(source2));
 
--- a/devtools/client/debugger/new/src/actions/utils/middleware/log.js
+++ b/devtools/client/debugger/new/src/actions/utils/middleware/log.js
@@ -5,25 +5,27 @@
 
 // @flow
 
 import { isTesting } from "devtools-environment";
 import type { ThunkArgs } from "../../types";
 
 const blacklist = [
   "SET_POPUP_OBJECT_PROPERTIES",
-  "SET_PAUSE_POINTS",
+  "ADD_BREAKPOINT_POSITIONS",
   "SET_SYMBOLS",
   "OUT_OF_SCOPE_LOCATIONS",
   "MAP_SCOPES",
   "MAP_FRAMES",
   "ADD_SCOPES",
   "IN_SCOPE_LINES",
   "REMOVE_BREAKPOINT",
-  "NODE_PROPERTIES_LOADED"
+  "NODE_PROPERTIES_LOADED",
+  "SET_FOCUSED_SOURCE_ITEM",
+  "NODE_EXPAND"
 ];
 
 function cloneAction(action: any) {
   action = action || {};
   action = { ...action };
 
   // ADD_TAB, ...
   if (action.source && action.source.text) {
--- a/devtools/client/debugger/new/src/client/firefox/commands.js
+++ b/devtools/client/debugger/new/src/client/firefox/commands.js
@@ -7,22 +7,24 @@
 import { createSource, createWorker } from "./create";
 import { supportsWorkers, updateWorkerClients } from "./workers";
 import { features } from "../../utils/prefs";
 
 import type {
   ActorId,
   BreakpointLocation,
   BreakpointOptions,
+  PendingLocation,
   EventListenerBreakpoints,
   Frame,
   FrameId,
   Script,
   SourceId,
   SourceActor,
+  Source,
   Worker,
   Range
 } from "../../types";
 
 import type {
   TabTarget,
   DebuggerClient,
   Grip,
@@ -170,33 +172,34 @@ function setXHRBreakpoint(path: string, 
 }
 
 function removeXHRBreakpoint(path: string, method: string) {
   return threadClient.removeXHRBreakpoint(path, method);
 }
 
 // Get the string key to use for a breakpoint location.
 // See also duplicate code in breakpoint-actor-map.js :(
-function locationKey(location) {
-  const { sourceUrl, sourceId, line, column } = location;
-  return `${(sourceUrl: any)}:${(sourceId: any)}:${line}:${(column: any)}`;
+function locationKey(location: BreakpointLocation) {
+  const { sourceUrl, line, column } = location;
+  const sourceId = location.sourceId || "";
+  return `${(sourceUrl: any)}:${sourceId}:${line}:${(column: any)}`;
 }
 
 function waitForWorkers(shouldWait: boolean) {
   shouldWaitForWorkers = shouldWait;
 }
 
 function maybeGenerateLogGroupId(options) {
   if (options.logValue && tabTarget.traits && tabTarget.traits.canRewind) {
     return { ...options, logGroupId: `logGroup-${Math.random()}` };
   }
   return options;
 }
 
-function maybeClearLogpoint(location) {
+function maybeClearLogpoint(location: BreakpointLocation) {
   const bp = breakpoints[locationKey(location)];
   if (bp && bp.options.logGroupId && tabTarget.activeConsole) {
     tabTarget.activeConsole.emit(
       "clearLogpointMessages",
       bp.options.logGroupId
     );
   }
 }
@@ -214,19 +217,19 @@ async function setBreakpoint(
   // to complete, so that we don't get hung up if one of the threads stops
   // responding. We don't strictly need to wait for the main thread to finish
   // setting its breakpoint, but this leads to more consistent behavior if the
   // user sets a breakpoint and immediately starts interacting with the page.
   // If the main thread stops responding then we're toast regardless.
   await forEachWorkerThread(thread => thread.setBreakpoint(location, options));
 }
 
-async function removeBreakpoint(location: BreakpointLocation) {
-  maybeClearLogpoint(location);
-  delete breakpoints[locationKey(location)];
+async function removeBreakpoint(location: PendingLocation) {
+  maybeClearLogpoint((location: any));
+  delete breakpoints[locationKey((location: any))];
   await threadClient.removeBreakpoint(location);
 
   // Remove breakpoints without waiting for the thread to respond, for the same
   // reason as in setBreakpoint.
   await forEachWorkerThread(thread => thread.removeBreakpoint(location));
 }
 
 async function evaluateInFrame(script: Script, options: EvaluateParam) {
@@ -420,19 +423,20 @@ async function fetchWorkers(): Promise<W
   return workers;
 }
 
 function getMainThread() {
   return threadClient.actor;
 }
 
 async function getBreakpointPositions(
-  sourceActor: SourceActor,
+  source: Source,
   range: ?Range
 ): Promise<{ [string]: number[] }> {
+  const sourceActor = source.actors[0];
   const { thread, actor } = sourceActor;
   const sourceThreadClient = lookupThreadClient(thread);
   const sourceClient = sourceThreadClient.source({ actor });
   const { positions } = await sourceClient.getBreakpointPositionsCompressed(
     range
   );
   return positions;
 }
--- a/devtools/client/debugger/new/src/client/firefox/types.js
+++ b/devtools/client/debugger/new/src/client/firefox/types.js
@@ -13,16 +13,17 @@
 import type {
   BreakpointLocation,
   BreakpointOptions,
   FrameId,
   ActorId,
   Script,
   Source,
   Pause,
+  PendingLocation,
   Frame,
   SourceId,
   Worker,
   Range
 } from "../../types";
 
 type URL = string;
 
@@ -340,17 +341,17 @@ export type ThreadClient = {
   reverseStepOver: Function => Promise<*>,
   reverseStepOut: Function => Promise<*>,
   breakOnNext: () => Promise<*>,
   // FIXME: unclear if SourceId or ActorId here
   source: ({ actor: SourceId }) => SourceClient,
   pauseGrip: (Grip | Function) => ObjectClient,
   pauseOnExceptions: (boolean, boolean) => Promise<*>,
   setBreakpoint: (BreakpointLocation, BreakpointOptions) => Promise<*>,
-  removeBreakpoint: BreakpointLocation => Promise<*>,
+  removeBreakpoint: PendingLocation => Promise<*>,
   setXHRBreakpoint: (path: string, method: string) => Promise<boolean>,
   removeXHRBreakpoint: (path: string, method: string) => Promise<boolean>,
   interrupt: () => Promise<*>,
   eventListeners: () => Promise<*>,
   getFrames: (number, number) => FramesResponse,
   getEnvironment: (frame: Frame) => Promise<*>,
   addListener: (string, Function) => void,
   getSources: () => Promise<SourcesPacket>,
--- a/devtools/client/debugger/new/src/components/SecondaryPanes/Breakpoints/tests/BreakpointsContextMenu.spec.js
+++ b/devtools/client/debugger/new/src/components/SecondaryPanes/Breakpoints/tests/BreakpointsContextMenu.spec.js
@@ -6,67 +6,70 @@
 
 import React from "react";
 import { shallow } from "enzyme";
 
 import BreakpointsContextMenu from "../BreakpointsContextMenu";
 import { createBreakpoint } from "../../../../utils/breakpoint";
 import { buildMenu } from "devtools-contextmenu";
 
-import { makeMockSource } from "../../../../utils/test-mockup";
+import {
+  makeMockSource,
+  makeMappedLocation
+} from "../../../../utils/test-mockup";
 
 jest.mock("devtools-contextmenu");
 
 function render(disabled = false) {
   const props = generateDefaults(disabled);
   const component = shallow(<BreakpointsContextMenu {...props} />);
   return { component, props };
 }
 
 function generateDefaults(disabled) {
   const breakpoints = [
     createBreakpoint(
-      {
+      makeMappedLocation({
         line: 1,
         column: undefined,
         sourceId: "source-https://example.com/main.js",
         sourceUrl: "https://example.com/main.js"
-      },
+      }),
       {
         id: "https://example.com/main.js:1:",
         disabled: disabled,
         options: {
           condition: "",
           logValue: "",
           hidden: false
         }
       }
     ),
     createBreakpoint(
-      {
+      makeMappedLocation({
         line: 2,
         column: undefined,
         sourceId: "source-https://example.com/main.js",
         sourceUrl: "https://example.com/main.js"
-      },
+      }),
       {
         id: "https://example.com/main.js:2:",
         disabled: disabled,
         options: {
           hidden: false
         }
       }
     ),
     createBreakpoint(
-      {
+      makeMappedLocation({
         line: 3,
         column: undefined,
         sourceId: "source-https://example.com/main.js",
         sourceUrl: "https://example.com/main.js"
-      },
+      }),
       {
         id: "https://example.com/main.js:3:",
         disabled: disabled,
         options: {}
       }
     )
   ];
 
--- a/devtools/client/debugger/new/src/reducers/tests/breakpoints.spec.js
+++ b/devtools/client/debugger/new/src/reducers/tests/breakpoints.spec.js
@@ -8,33 +8,37 @@ declare var it: (desc: string, func: () 
 declare var expect: (value: any) => any;
 
 import {
   getBreakpointsForSource,
   initialBreakpointsState
 } from "../breakpoints";
 
 import { createBreakpoint } from "../../utils/breakpoint";
+import { makeMappedLocation } from "../../utils/test-mockup";
 
 function initializeStateWith(data) {
   const state = initialBreakpointsState();
   state.breakpoints = data;
   return state;
 }
 
 describe("Breakpoints Selectors", () => {
   it("it gets a breakpoint for an original source", () => {
     const sourceId = "server1.conn1.child1/source1/originalSource";
     const matchingBreakpoints = {
-      id1: createBreakpoint({ line: 1, sourceId: sourceId }, { options: {} })
+      id1: createBreakpoint(
+        makeMappedLocation({ line: 1, sourceId: sourceId }),
+        { options: {} }
+      )
     };
 
     const otherBreakpoints = {
       id2: createBreakpoint(
-        { line: 1, sourceId: "not-this-source" },
+        makeMappedLocation({ line: 1, sourceId: "not-this-source" }),
         { options: {} }
       )
     };
 
     const data = {
       ...matchingBreakpoints,
       ...otherBreakpoints
     };
@@ -49,35 +53,33 @@ describe("Breakpoints Selectors", () => 
     expect(sourceBreakpoints).toEqual(allBreakpoints);
     expect(sourceBreakpoints[0] === allBreakpoints[0]).toBe(true);
   });
 
   it("it gets a breakpoint for a generated source", () => {
     const generatedSourceId = "random-source";
     const matchingBreakpoints = {
       id1: createBreakpoint(
+        makeMappedLocation(
+          { line: 1, sourceId: "original-source-id-1" },
+          { line: 1, sourceId: generatedSourceId }
+        ),
         {
-          line: 1,
-          sourceId: "original-source-id-1"
-        },
-        {
-          generatedLocation: { line: 1, sourceId: generatedSourceId },
           options: {}
         }
       )
     };
 
     const otherBreakpoints = {
       id2: createBreakpoint(
+        makeMappedLocation(
+          { line: 1, sourceId: "original-source-id-2" },
+          { line: 1, sourceId: "not-this-source" }
+        ),
         {
-          line: 1,
-          sourceId: "original-source-id-2"
-        },
-        {
-          generatedLocation: { line: 1, sourceId: "not-this-source" },
           options: {}
         }
       )
     };
 
     const data = {
       ...matchingBreakpoints,
       ...otherBreakpoints
--- a/devtools/client/debugger/new/src/selectors/breakpointSources.js
+++ b/devtools/client/debugger/new/src/selectors/breakpointSources.js
@@ -23,47 +23,54 @@ export type BreakpointSources = Array<{
 }>;
 
 function getBreakpointsForSource(
   source: Source,
   selectedSource: ?Source,
   breakpoints: Breakpoint[]
 ) {
   return breakpoints
-    .sort((a, b) => a.location.line - b.location.line)
+    .sort(
+      (a, b) =>
+        getSelectedLocation(a, selectedSource).line -
+        getSelectedLocation(b, selectedSource).line
+    )
     .filter(
       bp =>
         !bp.options.hidden &&
         !bp.loading &&
         (bp.text || bp.originalText || bp.options.condition || bp.disabled)
     )
     .filter(
       bp => getSelectedLocation(bp, selectedSource).sourceId == source.id
     );
 }
 
 function findBreakpointSources(
   sources: SourcesMap,
-  breakpoints: Breakpoint[]
+  breakpoints: Breakpoint[],
+  selectedSource: ?Source
 ): Source[] {
-  const sourceIds: string[] = uniq(breakpoints.map(bp => bp.location.sourceId));
+  const sourceIds: string[] = uniq(
+    breakpoints.map(bp => getSelectedLocation(bp, selectedSource).sourceId)
+  );
 
   const breakpointSources = sourceIds
     .map(id => sources[id])
     .filter(source => source && !source.isBlackBoxed);
 
   return sortBy(breakpointSources, (source: Source) => getFilename(source));
 }
 
 export const getBreakpointSources: Selector<BreakpointSources> = createSelector(
   getBreakpointsList,
   getSources,
   getSelectedSource,
   (breakpoints: Breakpoint[], sources: SourcesMap, selectedSource: ?Source) =>
-    findBreakpointSources(sources, breakpoints)
+    findBreakpointSources(sources, breakpoints, selectedSource)
       .map(source => ({
         source,
         breakpoints: getBreakpointsForSource(
           source,
           selectedSource,
           breakpoints
         )
       }))
--- a/devtools/client/debugger/new/src/selectors/index.js
+++ b/devtools/client/debugger/new/src/selectors/index.js
@@ -25,26 +25,25 @@ export {
 } from "../reducers/quick-open";
 
 export {
   getBreakpointAtLocation,
   getBreakpointsAtLine
 } from "./breakpointAtLocation";
 export {
   getVisibleBreakpoints,
-  getFirstVisibleBreakpoints,
-  getFirstVisibleBreakpointPosition
+  getFirstVisibleBreakpoints
 } from "./visibleBreakpoints";
 export { inComponent } from "./inComponent";
 export { isSelectedFrameVisible } from "./isSelectedFrameVisible";
 export { getCallStackFrames } from "./getCallStackFrames";
 export { getVisibleSelectedFrame } from "./visibleSelectedFrame";
 export { getBreakpointSources } from "./breakpointSources";
 export { getXHRBreakpoints, shouldPauseOnAnyXHR } from "./breakpoints";
-export { visibleColumnBreakpoints } from "./visibleColumnBreakpoints";
+export * from "./visibleColumnBreakpoints";
 
 import { objectInspector } from "devtools-reps";
 
 const { reducer } = objectInspector;
 
 Object.keys(reducer).forEach(function(key) {
   if (key === "default" || key === "__esModule") {
     return;
--- a/devtools/client/debugger/new/src/selectors/test/__snapshots__/visibleColumnBreakpoints.spec.js.snap
+++ b/devtools/client/debugger/new/src/selectors/test/__snapshots__/visibleColumnBreakpoints.spec.js.snap
@@ -1,49 +1,10 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
-exports[`visible column breakpoints duplicate generated locations 1`] = `
-Array [
-  Object {
-    "breakpoint": Object {
-      "astLocation": null,
-      "disabled": false,
-      "generatedLocation": Object {
-        "column": 1,
-        "line": 1,
-        "sourceId": "foo",
-      },
-      "id": "breakpoint",
-      "loading": false,
-      "location": Object {
-        "column": 1,
-        "line": 1,
-        "sourceId": "foo",
-      },
-      "options": Object {},
-      "originalText": "text",
-      "text": "text",
-    },
-    "location": Object {
-      "column": 1,
-      "line": 1,
-      "sourceId": "foo",
-    },
-  },
-  Object {
-    "breakpoint": undefined,
-    "location": Object {
-      "column": 3,
-      "line": 1,
-      "sourceId": "foo",
-    },
-  },
-]
-`;
-
 exports[`visible column breakpoints ignores single breakpoints 1`] = `
 Array [
   Object {
     "breakpoint": Object {
       "astLocation": null,
       "disabled": false,
       "generatedLocation": Object {
         "column": 1,
--- a/devtools/client/debugger/new/src/selectors/test/visibleColumnBreakpoints.spec.js
+++ b/devtools/client/debugger/new/src/selectors/test/visibleColumnBreakpoints.spec.js
@@ -31,28 +31,16 @@ describe("visible column breakpoints", (
     };
     const pausePoints = [pp(1, 1), pp(1, 5), pp(3, 1)];
     const breakpoints = [bp(1, 1), bp(4, 0), bp(4, 3)];
 
     const columnBps = getColumnBreakpoints(pausePoints, breakpoints, viewport);
     expect(columnBps).toMatchSnapshot();
   });
 
-  it("duplicate generated locations", () => {
-    const viewport = {
-      start: { line: 1, column: 0 },
-      end: { line: 10, column: 10 }
-    };
-    const pausePoints = [pp(1, 1), pp(1, 1), pp(1, 3)];
-    const breakpoints = [bp(1, 1)];
-
-    const columnBps = getColumnBreakpoints(pausePoints, breakpoints, viewport);
-    expect(columnBps).toMatchSnapshot();
-  });
-
   it("ignores single breakpoints", () => {
     const viewport = {
       start: { line: 1, column: 0 },
       end: { line: 10, column: 10 }
     };
     const pausePoints = [pp(1, 1), pp(1, 3), pp(2, 1)];
     const breakpoints = [bp(1, 1)];
     const columnBps = getColumnBreakpoints(pausePoints, breakpoints, viewport);
--- a/devtools/client/debugger/new/src/selectors/visibleBreakpoints.js
+++ b/devtools/client/debugger/new/src/selectors/visibleBreakpoints.js
@@ -2,64 +2,55 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
 
 // @flow
 
 import { createSelector } from "reselect";
 import { uniqBy } from "lodash";
 
-import {
-  getBreakpointsList,
-  getBreakpointPositionsForLine
-} from "../reducers/breakpoints";
+import { getBreakpointsList } from "../reducers/breakpoints";
 import { getSelectedSource } from "../reducers/sources";
 
-import { sortBreakpoints } from "../utils/breakpoint";
+import { sortSelectedBreakpoints } from "../utils/breakpoint";
 import { getSelectedLocation } from "../utils/source-maps";
 
-import type { Breakpoint, Source, SourceLocation } from "../types";
-import type { Selector, State } from "../reducers/types";
-
-function isVisible(breakpoint: Breakpoint, selectedSource: Source) {
-  const location = getSelectedLocation(breakpoint, selectedSource);
-  return location.sourceId === selectedSource.id;
-}
+import type { Breakpoint, Source } from "../types";
+import type { Selector } from "../reducers/types";
 
 /*
  * Finds the breakpoints, which appear in the selected source.
  */
 export const getVisibleBreakpoints: Selector<?(Breakpoint[])> = createSelector(
   getSelectedSource,
   getBreakpointsList,
   (selectedSource: ?Source, breakpoints: Breakpoint[]) => {
-    if (selectedSource == null) {
+    if (!selectedSource) {
       return null;
     }
 
-    // FIXME: Even though selectedSource is checked above, it fails type
-    // checking for isVisible
-    const source: Source = selectedSource;
-    return breakpoints.filter(bp => isVisible(bp, source));
+    return breakpoints.filter(
+      bp =>
+        selectedSource &&
+        getSelectedLocation(bp, selectedSource).sourceId === selectedSource.id
+    );
   }
 );
 
-export function getFirstVisibleBreakpointPosition(
-  state: State,
-  location: SourceLocation
-): ?SourceLocation {
-  const { sourceId, line } = location;
-  const positions = getBreakpointPositionsForLine(state, sourceId, line);
-  return positions && positions[0].location;
-}
-
 /*
  * Finds the first breakpoint per line, which appear in the selected source.
  */
 export const getFirstVisibleBreakpoints: Selector<
   Breakpoint[]
-> = createSelector(getVisibleBreakpoints, breakpoints => {
-  if (!breakpoints) {
-    return [];
+> = createSelector(
+  getVisibleBreakpoints,
+  getSelectedSource,
+  (breakpoints, selectedSource) => {
+    if (!breakpoints || !selectedSource) {
+      return [];
+    }
+
+    return (uniqBy(
+      sortSelectedBreakpoints(breakpoints, selectedSource),
+      bp => getSelectedLocation(bp, selectedSource).line
+    ): any);
   }
-
-  return (uniqBy(sortBreakpoints(breakpoints), bp => bp.location.line): any);
-});
+);
--- a/devtools/client/debugger/new/src/selectors/visibleColumnBreakpoints.js
+++ b/devtools/client/debugger/new/src/selectors/visibleColumnBreakpoints.js
@@ -1,31 +1,35 @@
 // @flow
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
 
-import { groupBy, sortedUniqBy } from "lodash";
+import { groupBy } from "lodash";
 import { createSelector } from "reselect";
 
 import {
   getViewport,
+  getSource,
   getSelectedSource,
-  getBreakpointPositions
+  getBreakpointPositions,
+  getBreakpointPositionsForSource
 } from "../selectors";
 import { getVisibleBreakpoints } from "./visibleBreakpoints";
-import { makeBreakpointId } from "../utils/breakpoint";
-import type { Selector } from "../reducers/types";
+import { getSelectedLocation } from "../utils/source-maps";
+import type { Selector, State } from "../reducers/types";
 
 import type {
   SourceLocation,
   PartialPosition,
   Breakpoint,
   Range,
-  BreakpointPositions
+  BreakpointPositions,
+  BreakpointPosition,
+  Source
 } from "../types";
 
 export type ColumnBreakpoint = {|
   +location: SourceLocation,
   +breakpoint: ?Breakpoint
 |};
 
 export type ColumnBreakpoints = Array<ColumnBreakpoint>;
@@ -39,101 +43,112 @@ function contains(location: PartialPosit
         location.column <= range.end.column))
   );
 }
 
 function inViewport(viewport, location) {
   return viewport && contains(location, viewport);
 }
 
-function groupBreakpoints(breakpoints) {
+function groupBreakpoints(breakpoints, selectedSource) {
   if (!breakpoints) {
     return {};
   }
-  const map: any = groupBy(breakpoints, ({ location }) => location.line);
+  const map: any = groupBy(
+    breakpoints,
+    breakpoint => getSelectedLocation(breakpoint, selectedSource).line
+  );
+
   for (const line in map) {
-    map[line] = groupBy(map[line], ({ location }) => location.column);
+    map[line] = groupBy(
+      map[line],
+      breakpoint => getSelectedLocation(breakpoint, selectedSource).column
+    );
   }
 
   return map;
 }
 
 function findBreakpoint(location, breakpointMap) {
   const { line, column } = location;
   const breakpoints = breakpointMap[line] && breakpointMap[line][column];
 
   if (breakpoints) {
     return breakpoints[0];
   }
 }
 
-function getLineCount(columnBreakpoints) {
+function filterByLineCount(positions, selectedSource) {
   const lineCount = {};
-  columnBreakpoints.forEach(({ location: { line } }) => {
+
+  for (const breakpoint of positions) {
+    const { line } = getSelectedLocation(breakpoint, selectedSource);
     if (!lineCount[line]) {
       lineCount[line] = 0;
     }
 
     lineCount[line] = lineCount[line] + 1;
-  });
+  }
 
-  return lineCount;
+  return positions.filter(
+    breakpoint =>
+      lineCount[getSelectedLocation(breakpoint, selectedSource).line] > 1
+  );
+}
+
+function filterVisible(positions, selectedSource, viewport) {
+  return positions.filter(columnBreakpoint => {
+    const location = getSelectedLocation(columnBreakpoint, selectedSource);
+    return inViewport(viewport, location);
+  });
 }
 
-export function formatColumnBreakpoints(columnBreakpoints: ColumnBreakpoints) {
-  console.log(
-    "Column Breakpoints\n\n",
-    columnBreakpoints
-      .map(
-        ({ location, breakpoint }) =>
-          `(${location.line}, ${location.column || ""}) ${
-            breakpoint && breakpoint.disabled ? "disabled" : ""
-          }`
-      )
-      .join("\n")
-  );
+function filterByBreakpoints(positions, selectedSource, breakpointMap) {
+  return positions.filter(position => {
+    const location = getSelectedLocation(position, selectedSource);
+    return breakpointMap[location.line];
+  });
+}
+
+function formatPositions(
+  positions: BreakpointPositions,
+  selectedSource,
+  breakpointMap
+) {
+  return (positions: any).map((position: BreakpointPosition) => {
+    const location = getSelectedLocation(position, selectedSource);
+    return {
+      location,
+      breakpoint: findBreakpoint(location, breakpointMap)
+    };
+  });
 }
 
 export function getColumnBreakpoints(
   positions: ?BreakpointPositions,
   breakpoints: ?(Breakpoint[]),
-  viewport: Range
+  viewport: Range,
+  selectedSource: ?Source
 ) {
   if (!positions) {
     return [];
   }
 
-  const breakpointMap = groupBreakpoints(breakpoints);
-
   // We only want to show a column breakpoint if several conditions are matched
-  // 1. there is a breakpoint on that line
-  // 2. the position is in the current viewport
-  // 4. it is the first breakpoint to appear at that generated location
-  // 5. there is atleast one other breakpoint on that line
-
-  let columnBreakpoints = positions.filter(
-    ({ location }) =>
-      breakpointMap[location.line] && inViewport(viewport, location)
-  );
+  // - it is the first breakpoint to appear at an the original location
+  // - the position is in the current viewport
+  // - there is atleast one other breakpoint on that line
+  // - there is a breakpoint on that line
+  const breakpointMap = groupBreakpoints(breakpoints, selectedSource);
 
-  // 4. Only show one column breakpoint per generated location
-  columnBreakpoints = sortedUniqBy(columnBreakpoints, ({ generatedLocation }) =>
-    makeBreakpointId(generatedLocation)
-  );
+  positions = filterByLineCount(positions, selectedSource);
+  positions = filterVisible(positions, selectedSource, viewport);
+  positions = filterByBreakpoints(positions, selectedSource, breakpointMap);
 
-  // 5. Check that there is atleast one other possible breakpoint on the line
-  const lineCount = getLineCount(columnBreakpoints);
-  columnBreakpoints = columnBreakpoints.filter(
-    ({ location: { line } }) => lineCount[line] > 1
-  );
-
-  return (columnBreakpoints: any).map(({ location }) => ({
-    location,
-    breakpoint: findBreakpoint(location, breakpointMap)
-  }));
+  return formatPositions(positions, selectedSource, breakpointMap);
 }
 
 const getVisibleBreakpointPositions = createSelector(
   getSelectedSource,
   getBreakpointPositions,
   (source, positions) => source && positions[source.id]
 );
 
@@ -141,8 +156,40 @@ export const visibleColumnBreakpoints: S
   ColumnBreakpoints
 > = createSelector(
   getVisibleBreakpointPositions,
   getVisibleBreakpoints,
   getViewport,
   getSelectedSource,
   getColumnBreakpoints
 );
+
+export function getFirstBreakpointPosition(
+  state: State,
+  { line, sourceId }: SourceLocation
+) {
+  const positions = getBreakpointPositionsForSource(state, sourceId);
+  const source = getSource(state, sourceId);
+
+  if (!source || !positions) {
+    return;
+  }
+
+  return positions.find(
+    position => getSelectedLocation(position, source).line == line
+  );
+}
+
+export function getFirstVisibleBreakpointPosition(
+  state: State,
+  { line }: SourceLocation
+) {
+  const positions = getVisibleBreakpointPositions(state);
+  const selectedSource = getSelectedSource(state);
+
+  if (!selectedSource || !positions) {
+    return;
+  }
+
+  return positions.find(
+    position => getSelectedLocation(position, selectedSource).line == line
+  );
+}
--- a/devtools/client/debugger/new/src/utils/breakpoint/astBreakpointLocation.js
+++ b/devtools/client/debugger/new/src/utils/breakpoint/astBreakpointLocation.js
@@ -28,17 +28,17 @@ export function getASTLocation(
       name: scope.name,
       offset: { line, column: undefined },
       index: scope.index
     };
   }
   return { name: undefined, offset: location, index: 0 };
 }
 
-export async function findScopeByName(
+export async function findFunctionByName(
   source: Source,
   name: ?string,
   index: number
 ) {
   const symbols = await getSymbols(source.id);
   const functions = symbols.functions;
 
   return functions.find(node => node.name === name && node.index === index);
new file mode 100644
--- /dev/null
+++ b/devtools/client/debugger/new/src/utils/breakpoint/breakpointPositions.js
@@ -0,0 +1,23 @@
+// @flow
+
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
+
+import { comparePosition } from "../location";
+import type {
+  BreakpointPositions,
+  SourceLocation,
+  Position
+} from "../../types";
+
+export function findPosition(
+  positions: ?BreakpointPositions,
+  location: Position | SourceLocation
+) {
+  if (!positions) {
+    return null;
+  }
+
+  return positions.find(pos => comparePosition(pos.location, location));
+}
--- a/devtools/client/debugger/new/src/utils/breakpoint/index.js
+++ b/devtools/client/debugger/new/src/utils/breakpoint/index.js
@@ -8,51 +8,44 @@ import { sortBy } from "lodash";
 
 import { getBreakpoint, getSource } from "../../selectors";
 import { isGenerated } from "../source";
 
 import assert from "../assert";
 import { features } from "../prefs";
 import { getSelectedLocation } from "../source-maps";
 
-export { getASTLocation, findScopeByName } from "./astBreakpointLocation";
+export * from "./astBreakpointLocation";
+export * from "./breakpointPositions";
 
 import type {
   Source,
   SourceActor,
   SourceLocation,
   SourceActorLocation,
   PendingLocation,
   Breakpoint,
   BreakpointLocation,
-  PendingBreakpoint
+  PendingBreakpoint,
+  MappedLocation
 } from "../../types";
 
 import type { State } from "../../reducers/types";
 
 // Return the first argument that is a string, or null if nothing is a
 // string.
 export function firstString(...args: string[]) {
   for (const arg of args) {
     if (typeof arg === "string") {
       return arg;
     }
   }
   return null;
 }
 
-export function locationMoved(
-  location: SourceLocation,
-  newLocation: SourceLocation
-) {
-  return (
-    location.line !== newLocation.line || location.column !== newLocation.column
-  );
-}
-
 // The ID for a Breakpoint is derived from its location in its Source.
 export function makeBreakpointId(location: SourceLocation) {
   const { sourceId, line, column } = location;
   const columnString = column || "";
   return `${sourceId}:${line}:${columnString}`;
 }
 
 export function getLocationWithoutColumn(location: SourceLocation) {
@@ -159,45 +152,37 @@ export function breakpointAtLocation(
 }
 
 export function breakpointExists(state: State, location: SourceLocation) {
   const currentBp = getBreakpoint(state, location);
   return currentBp && !currentBp.disabled;
 }
 
 export function createBreakpoint(
-  location: SourceLocation,
+  mappedLocation: MappedLocation,
   overrides: Object = {}
 ): Breakpoint {
-  const {
-    disabled,
-    generatedLocation,
-    astLocation,
-    text,
-    originalText,
-    options
-  } = overrides;
+  const { disabled, astLocation, text, originalText, options } = overrides;
 
   const defaultASTLocation = {
     name: undefined,
-    offset: location,
+    offset: mappedLocation.location,
     index: 0
   };
   const properties = {
-    id: makeBreakpointId(location),
+    id: makeBreakpointId(mappedLocation.location),
+    ...mappedLocation,
     options: {
       condition: options.condition || null,
       logValue: options.logValue || null,
       hidden: options.hidden || false
     },
     disabled: disabled || false,
     loading: false,
     astLocation: astLocation || defaultASTLocation,
-    generatedLocation: generatedLocation || location,
-    location,
     text,
     originalText
   };
 
   return properties;
 }
 
 export function createXHRBreakpoint(
--- a/devtools/client/debugger/new/src/utils/breakpoint/moz.build
+++ b/devtools/client/debugger/new/src/utils/breakpoint/moz.build
@@ -4,10 +4,11 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 DIRS += [
 
 ]
 
 CompiledModules(
     'astBreakpointLocation.js',
+    'breakpointPositions.js',
     'index.js',
 )
--- a/devtools/client/debugger/new/src/utils/location.js
+++ b/devtools/client/debugger/new/src/utils/location.js
@@ -1,23 +1,27 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
 
 // @flow
 
-import type { SourceLocation, SourceId } from "../types";
+import type { PartialPosition, SourceLocation, SourceId } from "../types";
 
 type IncompleteLocation = {
   sourceId: SourceId,
   line?: number,
   column?: number,
   sourceUrl?: string
 };
 
+export function comparePosition(a: ?PartialPosition, b: ?PartialPosition) {
+  return a && b && a.line == b.line && a.column == b.column;
+}
+
 export function createLocation({
   sourceId,
   line = 1,
   column,
   sourceUrl = ""
 }: IncompleteLocation): SourceLocation {
   return {
     sourceId,
--- a/devtools/client/debugger/new/src/utils/source-maps.js
+++ b/devtools/client/debugger/new/src/utils/source-maps.js
@@ -36,44 +36,77 @@ export async function getGeneratedLocati
     sourceId,
     column: column === 0 ? undefined : column,
     sourceUrl: generatedSource.url
   };
 }
 
 export async function getOriginalLocation(
   generatedLocation: SourceLocation,
-  source: Source,
   sourceMaps: SourceMaps
 ) {
   if (isOriginalId(generatedLocation.sourceId)) {
     return location;
   }
 
   return sourceMaps.getOriginalLocation(generatedLocation);
 }
 
 export async function getMappedLocation(
   state: Object,
   sourceMaps: Object,
   location: SourceLocation
+): Promise<MappedLocation> {
+  const source = getSource(state, location.sourceId);
+
+  if (!source) {
+    throw new Error(`no source ${location.sourceId}`);
+  }
+
+  if (isOriginalId(location.sourceId)) {
+    const generatedLocation = await getGeneratedLocation(
+      state,
+      source,
+      location,
+      sourceMaps
+    );
+    return { location, generatedLocation };
+  }
+
+  const generatedLocation = location;
+  const originalLocation = await sourceMaps.getOriginalLocation(
+    generatedLocation,
+    source
+  );
+
+  return { location: originalLocation, generatedLocation };
+}
+
+export async function mapLocation(
+  state: Object,
+  sourceMaps: Object,
+  location: SourceLocation
 ): Promise<SourceLocation> {
   const source = getSource(state, location.sourceId);
 
   if (!source) {
     return location;
   }
 
   if (isOriginalId(location.sourceId)) {
     return getGeneratedLocation(state, source, location, sourceMaps);
   }
 
   return sourceMaps.getOriginalLocation(location, source);
 }
 
+export function isOriginalSource(source: ?Source) {
+  return source && isOriginalId(source.id);
+}
+
 export function getSelectedLocation(
   mappedLocation: MappedLocation,
   selectedSource: ?Source
-) {
+): SourceLocation {
   return selectedSource && isGenerated(selectedSource)
     ? mappedLocation.generatedLocation
     : mappedLocation.location;
 }
--- a/devtools/client/debugger/new/src/utils/test-head.js
+++ b/devtools/client/debugger/new/src/utils/test-head.js
@@ -40,16 +40,24 @@ function createStore(client: any, initia
       };
     }
   })(combineReducers(reducers), initialState);
   sourceQueue.clear();
   sourceQueue.initialize({
     newSources: sources => store.dispatch(actions.newSources(sources))
   });
 
+  store.thunkArgs = () => ({
+    dispatch: store.dispatch,
+    getState: store.getState,
+    client,
+    sourceMaps,
+    panel: {}
+  });
+
   return store;
 }
 
 /**
  * @memberof utils/test-head
  * @static
  */
 function commonLog(msg: string, data: any = {}) {
--- a/devtools/client/debugger/new/src/utils/test-mockup.js
+++ b/devtools/client/debugger/new/src/utils/test-mockup.js
@@ -17,16 +17,17 @@ import type {
   Expression,
   Frame,
   FrameId,
   Scope,
   JsSource,
   WasmSource,
   Source,
   SourceId,
+  SourceLocation,
   Why
 } from "../types";
 
 function makeMockSource(
   url: string = "url",
   id: SourceId = "source",
   contentType: string = "text/javascript",
   text: string = ""
@@ -148,16 +149,24 @@ function makeMockExpression(value: Objec
   return {
     input: "input",
     value,
     from: "from",
     updating: false
   };
 }
 
+export function makeMappedLocation(
+  location: SourceLocation,
+  generatedLocation: ?SourceLocation
+) {
+  generatedLocation = generatedLocation || location;
+  return { location, generatedLocation };
+}
+
 export {
   makeMockSource,
   makeMockWasmSource,
   makeMockScope,
   mockScopeAddVariable,
   makeMockBreakpoint,
   makeMockFrame,
   makeMockFrameWithURL,
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-breaking.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-breaking.js
@@ -5,29 +5,32 @@
 
 add_task(async function() {
   const dbg = await initDebugger("doc-scripts.html");
   const {
     selectors: { getSelectedSource },
     getState
   } = dbg;
 
+  await selectSource(dbg, "scripts.html");
+
   // Make sure we can set a top-level breakpoint and it will be hit on
   // reload.
   await addBreakpoint(dbg, "scripts.html", 21);
+
   reload(dbg);
 
   await waitForDispatch(dbg, "NAVIGATE");
   await waitForSelectedSource(dbg, "doc-scripts.html");
   await waitForPaused(dbg);
 
   assertPausedLocation(dbg);
   await resume(dbg);
 
-  // Create an eval script that pauses itself.
+  info('Create an eval script that pauses itself.')
   invokeInTab("doEval");
   await waitForPaused(dbg);
 
   await resume(dbg);
   const source = getSelectedSource(getState())
   ok(!source.url, "It is an eval source");
 
   await addBreakpoint(dbg, source, 5);
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-breakpoint-skipping.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-breakpoint-skipping.js
@@ -8,16 +8,17 @@ function skipPausing(dbg) {
 
 /*
  * Tests toggling the skip pausing button and 
  * invoking functions without pausing.
  */
 
 add_task(async function() {
   let dbg = await initDebugger("doc-scripts.html");
+  await selectSource(dbg, "simple3")
   await addBreakpoint(dbg, "simple3", 2);
 
   await skipPausing(dbg);
   let res = await invokeInTab("simple");
   is(res, 3, "simple() successfully completed");
 
   info("Reload and invoke again");
   reload(dbg, "simple3");
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-breakpoints-cond.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-breakpoints-cond.js
@@ -1,22 +1,12 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
 
-function findBreakpoint(dbg, url, line, column = 0) {
-  const {
-    selectors: { getBreakpoint },
-    getState
-  } = dbg;
-  const source = findSource(dbg, url);
-  const location = { sourceId: source.id, line, column };
-  return getBreakpoint(getState(), location);
-}
-
 function getLineEl(dbg, line) {
   const lines = dbg.win.document.querySelectorAll(".CodeMirror-code > div");
   return lines[line - 1];
 }
 
 function assertEditorBreakpoint(
   dbg,
   line,
@@ -111,17 +101,17 @@ async function setLogPoint(dbg, index, v
   // Position cursor reliably at the end of the text.
   pressKey(dbg, "End");
   type(dbg, value);
   pressKey(dbg, "Enter");
 }
 
 add_task(async function() {
   const dbg = await initDebugger("doc-scripts.html", "simple2");
-  await pushPref("devtools.debugger.features.column-breakpoints", false);
+  await pushPref("devtools.debugger.features.column-breakpoints", true);
   await pushPref("devtools.debugger.features.log-points", true);
 
   await selectSource(dbg, "simple2");
   await waitForSelectedSource(dbg, "simple2");
 
   await setConditionalBreakpoint(dbg, 5, "1");
   await waitForDispatch(dbg, "ADD_BREAKPOINT");
   await waitForBreakpointWithCondition(dbg, "simple2", 5);
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-debugger-buttons.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-debugger-buttons.js
@@ -37,29 +37,29 @@ async function clickResume(dbg) {
 add_task(async function() {
   const dbg = await initDebugger("doc-debugger-statements.html");
 
   await reload(dbg);
   await waitForPaused(dbg);
   await waitForLoadedSource(dbg, "debugger-statements.html");
   assertPausedLocation(dbg);
 
-  // resume
+  info("resume");
   await clickResume(dbg);
   await waitForPaused(dbg);
   assertPausedLocation(dbg);
 
-  // step over
+  info("step over");
   await clickStepOver(dbg);
   assertPausedLocation(dbg);
 
-  // step into
+  info("step into");
   await clickStepIn(dbg);
   assertPausedLocation(dbg);
 
-  // step over
+  info("step over");
   await clickStepOver(dbg);
   assertPausedLocation(dbg);
 
-  // step out
+  info("step out");
   await clickStepOut(dbg);
   assertPausedLocation(dbg);
 });
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-editor-gutter.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-editor-gutter.js
@@ -48,17 +48,9 @@ add_task(async function() {
   is(getBreakpointCount(getState()), 1, "One breakpoint exists");
   assertEditorBreakpoint(dbg, 4, true);
 
   // Make sure clicking at the same place removes the icon.
   clickGutter(dbg, 4);
   await waitForDispatch(dbg, "REMOVE_BREAKPOINT");
   is(getBreakpointCount(getState()), 0, "No breakpoints exist");
   assertEditorBreakpoint(dbg, 4, false);
-
-  // Ensure that clicking the gutter removes all breakpoints on a given line
-  await addBreakpoint(dbg, source, 4, 0);
-  await addBreakpoint(dbg, source, 4, 1);
-  await addBreakpoint(dbg, source, 4, 2);
-  clickGutter(dbg, 4);
-  await waitForState(dbg, state => dbg.selectors.getBreakpointCount(state) === 0);
-  assertEditorBreakpoint(dbg, 4, false);
 });
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-editor-select.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-editor-select.js
@@ -13,18 +13,18 @@ add_task(async function() {
   const {
     selectors: { getSelectedSource },
     getState
   } = dbg;
   const simple1 = findSource(dbg, "simple1.js");
   const simple2 = findSource(dbg, "simple2.js");
 
   // Set the initial breakpoint.
+  await selectSource(dbg, "simple1");
   await addBreakpoint(dbg, simple1, 4);
-  ok(!getSelectedSource(getState()), "No selected source");
 
   // Call the function that we set a breakpoint in.
   invokeInTab("main");
   await waitForPaused(dbg);
   await waitForSelectedSource(dbg, "simple1");
   assertPausedLocation(dbg);
 
   // Step through to another file and make sure it's paused in the
@@ -38,16 +38,17 @@ add_task(async function() {
   await stepOut(dbg);
   await stepOut(dbg);
   assertPausedLocation(dbg);
   await resume(dbg);
 
   // Make sure that we can set a breakpoint on a line out of the
   // viewport, and that pausing there scrolls the editor to it.
   let longSrc = findSource(dbg, "long.js");
+  await selectSource(dbg, "long.js");
   await addBreakpoint(dbg, longSrc, 66);
 
   invokeInTab("testModel");
   await waitForPaused(dbg);
   await waitForSelectedSource(dbg, "long.js");
 
   assertPausedLocation(dbg);
   ok(
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-navigation.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-navigation.js
@@ -24,16 +24,17 @@ add_task(async function() {
     selectors: { getSelectedSource, isPaused },
     getState
   } = dbg;
 
   invokeInTab("firstCall");
   await waitForPaused(dbg);
 
   await navigate(dbg, "doc-scripts.html", "simple1.js");
+  await selectSource(dbg, "simple1");
   await addBreakpoint(dbg, "simple1.js", 4);
   invokeInTab("main");
   await waitForPaused(dbg);
   await waitForLoadedSource(dbg, "simple1");
   toggleScopes(dbg);
 
   assertPausedLocation(dbg);
   is(countSources(dbg), 5, "5 sources are loaded.");
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-pause-ux.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-pause-ux.js
@@ -17,16 +17,17 @@ async function waitForMatch(dbg, { match
 }
 
 add_task(async function() {
   const dbg = await initDebugger("doc-scripts.html");
 
   // Make sure that we can set a breakpoint on a line out of the
   // viewport, and that pausing there scrolls the editor to it.
   let longSrc = findSource(dbg, "long.js");
+  await selectSource(dbg, "long.js")
   await addBreakpoint(dbg, longSrc, 66);
   invokeInTab("testModel");
   await waitForPaused(dbg, "long.js");
 
   const pauseScrollTop = getScrollTop(dbg);
 
   log("1. adding a breakpoint should not scroll the editor");
   getCM(dbg).scrollTo(0, 0);
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-pretty-print.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-pretty-print.js
@@ -11,17 +11,17 @@ add_task(async function() {
 
   await waitForSelectedSource(dbg, "math.min.js:formatted");
   const ppSrc = findSource(dbg, "math.min.js:formatted");
 
   ok(ppSrc, "Pretty-printed source exists");
 
   // this is not implemented yet
   // assertHighlightLocation(dbg, "math.min.js:formatted", 18);
-
+  // await selectSource(dbg, "math.min.js")
   await addBreakpoint(dbg, ppSrc, 18);
 
   invokeInTab("arithmetic");
   await waitForPaused(dbg);
 
   assertPausedLocation(dbg);
 
   await stepOver(dbg);
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-react-app.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-react-app.js
@@ -1,11 +1,12 @@
 add_task(async function() {
   const dbg = await initDebugger("doc-react.html", "App.js");
 
+  await selectSource(dbg, "App.js");
   await addBreakpoint(dbg, "App.js", 11);
 
   info('Test previewing an immutable Map inside of a react component')
   invokeInTab("clickButton");
   await waitForPaused(dbg);
   await waitForState(
     dbg,
     state => dbg.selectors.getSelectedScopeMappings(state)
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-reload.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-reload.js
@@ -23,17 +23,17 @@ add_task(async function() {
   await waitForSource(dbg, "sjs_code_reload");
   await selectSource(dbg, "sjs_code_reload");
   await addBreakpoint(dbg, "sjs_code_reload", 2);
 
   await reload(dbg, "sjs_code_reload.sjs");
   await waitForSelectedSource(dbg, "sjs_code_reload.sjs");
 
   const source = findSource(dbg, "sjs_code_reload");
-  const location = { sourceId: source.id, line: 6 };
+  const location = { sourceId: source.id, line: 6, column: 2 };
 
   await waitForBreakpoint(dbg, location);
 
   const breakpointList = dbg.selectors.getBreakpointsList(dbg.getState());
   const breakpoint = breakpointList[0];
 
   is(breakpointList.length, 1);
   is(breakpoint.location.line, 6);
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-sourcemapped-breakpoint-console.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-sourcemapped-breakpoint-console.js
@@ -74,13 +74,13 @@ add_task(async function() {
   await evalInConsoleAtPoint(
     dbg,
     "webpack3-babel6",
     "shadowed-vars",
     { line: 18, column: 6 },
     [`aVar === "var3"`, `aLet === "let3"`, `aConst === "const3"`]
   );
 
-  await evalInConsoleAtPoint(dbg, "webpack3-babel6", "babel-classes", { line: 8, column: 6 }, [
+  await evalInConsoleAtPoint(dbg, "webpack3-babel6", "babel-classes", { line: 8, column: 16 }, [
     `this.hasOwnProperty("bound")`,
   ]);
 
 });
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-sourcemapped-scopes.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-sourcemapped-scopes.js
@@ -80,17 +80,17 @@ function targetToFlags(target) {
   const isParcel = target.startsWith("parcel");
   const hasBabel = target.includes("-babel") || isParcel;
   const isWebpack4 = target.startsWith("webpack4");
 
   // Rollup removes lots of things as dead code, so they are marked as optimized out.
   const rollupOptimized = isRollup ? "(optimized away)" : null;
   const webpackImportGetter = isWebpack ? "Getter" : null;
   const webpack4ImportGetter = isWebpack4 ? "Getter" : null;
-  const maybeLineStart = hasBabel ? col => col : col => 0;
+  const maybeLineStart = col => col;
   const defaultExport = isWebpack4
       ? name => `${name}()`
       : name => [name, "(optimized away)"];
 
   return {
     isRollup,
     isWebpack,
     isParcel,
@@ -178,17 +178,17 @@ async function testEvalMaps(dbg) {
   // we should consider disabling this test for now.
 
   for (const target of [
     "webpack3",
     "webpack4",
   ]) {
     const { defaultExport } = targetToFlags(target);
 
-    await breakpointScopes(dbg, target, "eval-maps", { line: 14, column: 0 }, [
+    await breakpointScopes(dbg, target, "eval-maps", { line: 14, column: 4 }, [
       "Block",
       ["<this>", "Window"],
       ["three", "5"],
       ["two", "4"],
       "Block",
       ["three", "3"],
       ["two", "2"],
       "Block",
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-sourcemaps-reload.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-sourcemaps-reload.js
@@ -21,34 +21,40 @@ function getBreakpoints(dbg) {
   return dbg.selectors.getBreakpointsList(dbg.getState());
 }
 
 add_task(async function() {
   const dbg = await initDebugger("doc-minified.html");
 
   await navigate(dbg, "sourcemaps-reload/doc-sourcemaps-reload.html", "v1.js");
 
+  info('Add initial breakpoint');
   await selectSource(dbg, "v1.js");
   await addBreakpoint(dbg, "v1.js", 6);
 
   let breakpoint = getBreakpoints(dbg)[0];
   is(breakpoint.location.line, 6);
 
+  info('Reload with a new version of the file');
   let syncBp = waitForDispatch(dbg, "SYNC_BREAKPOINT");
   await navigate(dbg, "doc-sourcemaps-reload2.html", "v1.js");
 
   await syncBp;
   breakpoint = getBreakpoints(dbg)[0];
 
   is(breakpoint.location.line, 9);
-  is(breakpoint.generatedLocation.line, 73);
+  is(breakpoint.generatedLocation.line, 79);
 
+  info('Add a second breakpoint');
   await addBreakpoint(dbg, "v1.js", 13);
+  is(dbg.selectors.getBreakpointCount(dbg.getState()), 2, "No breakpoints");
+
 
   // NOTE: When we reload, the `foo` function and the
   // module is no longer 13 lines long
+  info('Reload and observe no breakpoints')
   syncBp = waitForDispatch(dbg, "SYNC_BREAKPOINT", 2);
   await navigate(dbg, "doc-sourcemaps-reload3.html", "v1.js");
   await waitForSource(dbg, "v1");
   await syncBp;
 
   is(getBreakpoints(dbg).length, 0, "No breakpoints");
 });
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-sourcemaps-reloading.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-sourcemaps-reloading.js
@@ -25,47 +25,37 @@ add_task(async function() {
   await selectSource(dbg, entrySrc);
   ok(
     getCM(dbg)
       .getValue()
       .includes("window.keepMeAlive"),
     "Original source text loaded correctly"
   );
 
-  // Test that breakpoint sliding is not attempted. The breakpoint
-  // should not move anywhere.
-  await addBreakpoint(dbg, entrySrc, 13);
-  is(getBreakpointCount(getState()), 1, "One breakpoint exists");
-
-  ok(
-    getBreakpoint(getState(), { sourceId: entrySrc.id, line: 13 }),
-    "Breakpoint has correct line"
-  );
-
   await addBreakpoint(dbg, entrySrc, 5);
-
   await addBreakpoint(dbg, entrySrc, 15, 0);
   await disableBreakpoint(dbg, entrySrc, 15, 0);
 
   // Test reloading the debugger
   await reload(dbg, "opts.js");
   await waitForDispatch(dbg, "LOAD_SOURCE_TEXT");
 
   await waitForPaused(dbg);
   assertPausedLocation(dbg);
 
-  await waitForBreakpointCount(dbg, 3);
-  is(getBreakpointCount(getState()), 3, "Three breakpoints exist");
+  await waitForBreakpointCount(dbg, 2);
+  is(getBreakpointCount(getState()), 2, "Three breakpoints exist");
 
   ok(
-    getBreakpoint(getState(), { sourceId: entrySrc.id, line: 13 }),
+    getBreakpoint(getState(), { sourceId: entrySrc.id, line: 15, column: 0 }),
     "Breakpoint has correct line"
   );
 
   ok(
     getBreakpoint(getState(), {
       sourceId: entrySrc.id,
       line: 15,
+      column: 0,
       disabled: true
     }),
     "Breakpoint has correct line"
   );
 });
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-sourcemaps.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-sourcemaps.js
@@ -12,34 +12,39 @@ function assertBreakpointExists(dbg, sou
   } = dbg;
 
   ok(
     getBreakpoint(getState(), { sourceId: source.id, line }),
     "Breakpoint has correct line"
   );
 }
 
-function assertEditorBreakpoint(dbg, line, shouldExist) {
-  const exists = !!getLineEl(dbg, line).querySelector(".new-breakpoint");
+async function assertEditorBreakpoint(dbg, line, shouldExist) {
+  const el = await getLineEl(dbg, line);
+  const exists = !!el.querySelector(".new-breakpoint");
   ok(
     exists === shouldExist,
     "Breakpoint " +
       (shouldExist ? "exists" : "does not exist") +
       " on line " +
       line
   );
 }
 
-function getLineEl(dbg, line) {
-  const lines = dbg.win.document.querySelectorAll(".CodeMirror-code > div");
-  return lines[line - 1];
+async function getLineEl(dbg, line) {
+  let el = await codeMirrorGutterElement(dbg, line);
+  while (el && !el.matches(".CodeMirror-code > div")) {
+    el = el.parentElement;
+  }
+  return el;
 }
 
-function clickGutter(dbg, line) {
-  clickElement(dbg, "gutter", line);
+async function clickGutter(dbg, line) {
+  const el = await codeMirrorGutterElement(dbg, line);
+  clickDOMElement(dbg, el);
 }
 
 add_task(async function() {
   // NOTE: the CORS call makes the test run times inconsistent
   const dbg = await initDebugger("doc-sourcemaps.html", "entry.js", "output.js", "times2.js", "opts.js");
   const {
     selectors: { getBreakpoint, getBreakpointCount },
     getState
@@ -49,21 +54,21 @@ add_task(async function() {
   const bundleSrc = findSource(dbg, "bundle.js");
 
   // Check that the original sources appear in the source tree
   await clickElement(dbg, "sourceDirectoryLabel", 3);
   await assertSourceCount(dbg, 8);
 
   await selectSource(dbg, bundleSrc);
 
-  await clickGutter(dbg, 13);
+  await clickGutter(dbg, 70);
   await waitForDispatch(dbg, "ADD_BREAKPOINT");
-  assertEditorBreakpoint(dbg, 13, true);
+  assertEditorBreakpoint(dbg, 70, true);
 
-  await clickGutter(dbg, 13);
+  await clickGutter(dbg, 70);
   await waitForDispatch(dbg, "REMOVE_BREAKPOINT");
   is(getBreakpointCount(getState()), 0, "No breakpoints exists");
 
   const entrySrc = findSource(dbg, "entry.js");
 
   await selectSource(dbg, entrySrc);
   ok(
     getCM(dbg)
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-windowless-workers-early-breakpoint.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-windowless-workers-early-breakpoint.js
@@ -9,27 +9,28 @@ add_task(async function() {
 
   const workerSource = findSource(dbg, "simple-worker.js");
 
   // NOTE: by default we do not wait on worker
   // commands to complete because the thread could be
   // shutting down.
   dbg.client.waitForWorkers(true);
 
+  await selectSource(dbg, "simple-worker.js");
   await addBreakpoint(dbg, workerSource, 1);
   invokeInTab("startWorker");
   await waitForPaused(dbg, "simple-worker.js");
 
   // We should be paused at the first line of simple-worker.js
   assertPausedAtSourceAndLine(dbg, workerSource.id, 1);
-  await removeBreakpoint(dbg, workerSource.id, 1);
+  await removeBreakpoint(dbg, workerSource.id, 1, 12);
   await resume(dbg);
 
   // Make sure that suspending activity in the worker when attaching does not
   // interfere with sending messages to the worker.
   await addBreakpoint(dbg, workerSource, 10);
   invokeInTab("startWorkerWithMessage");
   await waitForPaused(dbg, "simple-worker.js");
 
   // We should be paused in the message listener in simple-worker.js
   assertPausedAtSourceAndLine(dbg, workerSource.id, 10);
-  await removeBreakpoint(dbg, workerSource.id, 10);
+  await removeBreakpoint(dbg, workerSource.id, 10, 2);
 });
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-windowless-workers.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-windowless-workers.js
@@ -85,16 +85,17 @@ add_task(async function() {
   info("Test resuming in the mainThread");
   await resume(dbg);
   assertNotPaused(dbg);
 
   info("Test pausing in both workers");
   await addBreakpoint(dbg, "simple-worker", 10);
   invokeInTab("sayHello");
   dbg.actions.selectThread(worker1Thread);
+
   await waitForPaused(dbg);
   assertPausedAtSourceAndLine(dbg, workerSource.id, 10);
 
   dbg.actions.selectThread(worker2Thread);
   await waitForPaused(dbg);
   assertPausedAtSourceAndLine(dbg, workerSource.id, 10);
 
   info("Test stepping in second worker and not the first");
--- a/devtools/client/debugger/new/test/mochitest/examples/doc-scripts.html
+++ b/devtools/client/debugger/new/test/mochitest/examples/doc-scripts.html
@@ -14,11 +14,12 @@
     <script src="simple2.js"></script>
     <script src="simple3.js"></script>
     <script src="long.js"></script>
     <script>
       // This inline script allows this HTML page to show up as a
       // source. It also needs to introduce a new global variable so
       // it's not immediately garbage collected.
       inline_script = function () { var x = 5; };
+      inline_script();
     </script>
   </body>
 </html>
--- a/devtools/client/debugger/new/test/mochitest/examples/sourcemaps-reload/v1.bundle.js
+++ b/devtools/client/debugger/new/test/mochitest/examples/sourcemaps-reload/v1.bundle.js
@@ -62,28 +62,30 @@
 /******/ 	// Load entry module and return exports
 /******/ 	return __webpack_require__(__webpack_require__.s = 0);
 /******/ })
 /************************************************************************/
 /******/ ([
 /* 0 */
 /***/ (function(module, exports) {
 
-let foo = (() => {
+function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
+
+window.bar = function bar() {
+  return new Promise(resolve => setTimeout(resolve, 100));
+};
+
+window.foo = (() => {
   var _ref = _asyncToGenerator(function* () {
     yield bar();
     console.log("YO");
   });
 
-  return function foo() {
+  function foo() {
     return _ref.apply(this, arguments);
-  };
-})();
+  }
 
-function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
-
-function bar() {
-  return new Promise(resolve => setTimeout(resolve, 100));
-}
+  return foo;
+})();
 
 /***/ })
 /******/ ]);
 //# sourceMappingURL=v1.bundle.js.map
\ No newline at end of file
--- a/devtools/client/debugger/new/test/mochitest/examples/sourcemaps-reload/v1.bundle.js.map
+++ b/devtools/client/debugger/new/test/mochitest/examples/sourcemaps-reload/v1.bundle.js.map
@@ -1,1 +1,1 @@
-{"version":3,"sources":["webpack:///webpack/bootstrap 8bcf0d04c821a99f6859","webpack:///./v1.js"],"names":["bar","console","log","foo","Promise","resolve","setTimeout"],"mappings":";AAAA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAK;AACL;AACA;;AAEA;AACA;AACA;AACA,mCAA2B,0BAA0B,EAAE;AACvD,yCAAiC,eAAe;AAChD;AACA;AACA;;AAEA;AACA,8DAAsD,+DAA+D;;AAErH;AACA;;AAEA;AACA;;;;;;;;+BCzDA,aAAqB;AACnB,UAAMA,KAAN;AACAC,YAAQC,GAAR,CAAY,IAAZ;AACD,G;;kBAHcC,G;;;;;;;AAJf,SAASH,GAAT,GAAe;AACb,SAAO,IAAII,OAAJ,CAAYC,WAAWC,WAAWD,OAAX,EAAoB,GAApB,CAAvB,CAAP;AACD,C","file":"v1.bundle.js","sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, {\n \t\t\t\tconfigurable: false,\n \t\t\t\tenumerable: true,\n \t\t\t\tget: getter\n \t\t\t});\n \t\t}\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 0);\n\n\n\n// WEBPACK FOOTER //\n// webpack/bootstrap 8bcf0d04c821a99f6859","function bar() {\n  return new Promise(resolve => setTimeout(resolve, 100))\n}\n\nasync function foo() {\n  await bar();\n  console.log(\"YO\")\n}\n\n\n\n// WEBPACK FOOTER //\n// ./v1.js"],"sourceRoot":""}
\ No newline at end of file
+{"version":3,"sources":["webpack:///webpack/bootstrap 7f7d36c9c8ca0d417720","webpack:///./v1.js"],"names":["window","bar","Promise","resolve","setTimeout","foo","console","log"],"mappings":";AAAA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAK;AACL;AACA;;AAEA;AACA;AACA;AACA,mCAA2B,0BAA0B,EAAE;AACvD,yCAAiC,eAAe;AAChD;AACA;AACA;;AAEA;AACA,8DAAsD,+DAA+D;;AAErH;AACA;;AAEA;AACA;;;;;;;;;AC7DAA,OAAOC,GAAP,GAAa,SAASA,GAAT,GAAe;AAC1B,SAAO,IAAIC,OAAJ,CAAYC,WAAWC,WAAWD,OAAX,EAAoB,GAApB,CAAvB,CAAP;AACD,CAFD;;AAIAH,OAAOK,GAAP;AAAA,+BAAa,aAAqB;AAChC,UAAMJ,KAAN;AACAK,YAAQC,GAAR,CAAY,IAAZ;AACD,GAHD;;AAAA,WAA4BF,GAA5B;AAAA;AAAA;;AAAA,SAA4BA,GAA5B;AAAA,K","file":"v1.bundle.js","sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, {\n \t\t\t\tconfigurable: false,\n \t\t\t\tenumerable: true,\n \t\t\t\tget: getter\n \t\t\t});\n \t\t}\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 0);\n\n\n\n// WEBPACK FOOTER //\n// webpack/bootstrap 7f7d36c9c8ca0d417720","window.bar = function bar() {\n  return new Promise(resolve => setTimeout(resolve, 100))\n}\n\nwindow.foo = async function foo() {\n  await bar();\n  console.log(\"YO\")\n}\n\n\n\n// WEBPACK FOOTER //\n// ./v1.js"],"sourceRoot":""}
\ No newline at end of file
--- a/devtools/client/debugger/new/test/mochitest/examples/sourcemaps-reload/v1.js
+++ b/devtools/client/debugger/new/test/mochitest/examples/sourcemaps-reload/v1.js
@@ -1,8 +1,8 @@
-function bar() {
+window.bar = function bar() {
   return new Promise(resolve => setTimeout(resolve, 100))
 }
 
-async function foo() {
+window.foo = async function foo() {
   await bar();
   console.log("YO")
 }
--- a/devtools/client/debugger/new/test/mochitest/examples/sourcemaps-reload/v2.bundle.js
+++ b/devtools/client/debugger/new/test/mochitest/examples/sourcemaps-reload/v2.bundle.js
@@ -63,30 +63,32 @@
 /******/ 	return __webpack_require__(__webpack_require__.s = 1);
 /******/ })
 /************************************************************************/
 /******/ ([
 /* 0 */,
 /* 1 */
 /***/ (function(module, exports) {
 
-let foo = (() => {
+function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
+
+window.bar = function bar() {
+  return new Promise(resolve => setTimeout(resolve, 100));
+};
+
+window.foo = (() => {
   var _ref = _asyncToGenerator(function* () {
     yield bar();
     console.log("YO");
   });
 
-  return function foo() {
+  function foo() {
     return _ref.apply(this, arguments);
-  };
-})();
+  }
 
-function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
-
-function bar() {
-  return new Promise(resolve => setTimeout(resolve, 100));
-}
+  return foo;
+})();
 
 console.log("HEY");
 
 /***/ })
 /******/ ]);
 //# sourceMappingURL=v2.bundle.js.map
\ No newline at end of file
--- a/devtools/client/debugger/new/test/mochitest/examples/sourcemaps-reload/v2.bundle.js.map
+++ b/devtools/client/debugger/new/test/mochitest/examples/sourcemaps-reload/v2.bundle.js.map
@@ -1,1 +1,1 @@
-{"version":3,"sources":["webpack:///webpack/bootstrap 8bcf0d04c821a99f6859","webpack:///./v1.js"],"names":["bar","console","log","foo","Promise","resolve","setTimeout"],"mappings":";AAAA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAK;AACL;AACA;;AAEA;AACA;AACA;AACA,mCAA2B,0BAA0B,EAAE;AACvD,yCAAiC,eAAe;AAChD;AACA;AACA;;AAEA;AACA,8DAAsD,+DAA+D;;AAErH;AACA;;AAEA;AACA;;;;;;;;;+BCtDA,aAAqB;AACnB,UAAMA,KAAN;AACAC,YAAQC,GAAR,CAAY,IAAZ;AACD,G;;kBAHcC,G;;;;;;;AAPf,SAASH,GAAT,GAAe;AACb,SAAO,IAAII,OAAJ,CAAYC,WAAWC,WAAWD,OAAX,EAAoB,GAApB,CAAvB,CAAP;AACD;;AAUDJ,QAAQC,GAAR,CAAY,KAAZ,E","file":"v2.bundle.js","sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, {\n \t\t\t\tconfigurable: false,\n \t\t\t\tenumerable: true,\n \t\t\t\tget: getter\n \t\t\t});\n \t\t}\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 1);\n\n\n\n// WEBPACK FOOTER //\n// webpack/bootstrap 8bcf0d04c821a99f6859","function bar() {\n  return new Promise(resolve => setTimeout(resolve, 100))\n}\n\n\n\n\nasync function foo() {\n  await bar();\n  console.log(\"YO\")\n}\n\nconsole.log(\"HEY\")\n\n\n\n// WEBPACK FOOTER //\n// ./v2.js"],"sourceRoot":""}
+{"version":3,"sources":["webpack:///webpack/bootstrap 7f7d36c9c8ca0d417720","webpack:///./v1.js"],"names":["window","bar","Promise","resolve","setTimeout","foo","console","log"],"mappings":";AAAA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAK;AACL;AACA;;AAEA;AACA;AACA;AACA,mCAA2B,0BAA0B,EAAE;AACvD,yCAAiC,eAAe;AAChD;AACA;AACA;;AAEA;AACA,8DAAsD,+DAA+D;;AAErH;AACA;;AAEA;AACA;;;;;;;;;;AC7DAA,OAAOC,GAAP,GAAa,SAASA,GAAT,GAAe;AAC1B,SAAO,IAAIC,OAAJ,CAAYC,WAAWC,WAAWD,OAAX,EAAoB,GAApB,CAAvB,CAAP;AACD,CAFD;;AAOAH,OAAOK,GAAP;AAAA,+BAAa,aAAqB;AAChC,UAAMJ,KAAN;AACAK,YAAQC,GAAR,CAAY,IAAZ;AACD,GAHD;;AAAA,WAA4BF,GAA5B;AAAA;AAAA;;AAAA,SAA4BA,GAA5B;AAAA;;AAKAC,QAAQC,GAAR,CAAY,KAAZ,E","file":"v2.bundle.js","sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, {\n \t\t\t\tconfigurable: false,\n \t\t\t\tenumerable: true,\n \t\t\t\tget: getter\n \t\t\t});\n \t\t}\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 1);\n\n\n\n// WEBPACK FOOTER //\n// webpack/bootstrap 7f7d36c9c8ca0d417720","window.bar = function bar() {\n  return new Promise(resolve => setTimeout(resolve, 100))\n}\n\n\n\n\nwindow.foo = async function foo() {\n  await bar();\n  console.log(\"YO\")\n}\n\nconsole.log(\"HEY\")\n\n\n\n// WEBPACK FOOTER //\n// ./v2.js"],"sourceRoot":""}
\ No newline at end of file
--- a/devtools/client/debugger/new/test/mochitest/examples/sourcemaps-reload/v2.js
+++ b/devtools/client/debugger/new/test/mochitest/examples/sourcemaps-reload/v2.js
@@ -1,13 +1,13 @@
-function bar() {
+window.bar = function bar() {
   return new Promise(resolve => setTimeout(resolve, 100))
 }
 
 
 
 
-async function foo() {
+window.foo = async function foo() {
   await bar();
   console.log("YO")
 }
 
 console.log("HEY")
--- a/devtools/client/debugger/new/test/mochitest/examples/sourcemaps-reload/v3.bundle.js
+++ b/devtools/client/debugger/new/test/mochitest/examples/sourcemaps-reload/v3.bundle.js
@@ -63,16 +63,16 @@
 /******/ 	return __webpack_require__(__webpack_require__.s = 2);
 /******/ })
 /************************************************************************/
 /******/ ({
 
 /***/ 2:
 /***/ (function(module, exports) {
 
-function bar() {
+window.bar = function bar() {
   return new Promise(resolve => setTimeout(resolve, 100));
-}
+};
 
 /***/ })
 
 /******/ });
 //# sourceMappingURL=v3.bundle.js.map
\ No newline at end of file
--- a/devtools/client/debugger/new/test/mochitest/examples/sourcemaps-reload/v3.bundle.js.map
+++ b/devtools/client/debugger/new/test/mochitest/examples/sourcemaps-reload/v3.bundle.js.map
@@ -1,1 +1,1 @@
-{"version":3,"sources":["webpack:///webpack/bootstrap 8bcf0d04c821a99f6859","webpack:///./v1.js"],"names":["bar","Promise","resolve","setTimeout"],"mappings":";AAAA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAK;AACL;AACA;;AAEA;AACA;AACA;AACA,mCAA2B,0BAA0B,EAAE;AACvD,yCAAiC,eAAe;AAChD;AACA;AACA;;AAEA;AACA,8DAAsD,+DAA+D;;AAErH;AACA;;AAEA;AACA;;;;;;;;AC7DA,SAASA,GAAT,GAAe;AACb,SAAO,IAAIC,OAAJ,CAAYC,WAAWC,WAAWD,OAAX,EAAoB,GAApB,CAAvB,CAAP;AACD,C","file":"v3.bundle.js","sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, {\n \t\t\t\tconfigurable: false,\n \t\t\t\tenumerable: true,\n \t\t\t\tget: getter\n \t\t\t});\n \t\t}\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 2);\n\n\n\n// WEBPACK FOOTER //\n// webpack/bootstrap 8bcf0d04c821a99f6859","function bar() {\n  return new Promise(resolve => setTimeout(resolve, 100))\n}\n\n\n\n// WEBPACK FOOTER //\n// ./v3.js"],"sourceRoot":""}
+{"version":3,"sources":["webpack:///webpack/bootstrap 7f7d36c9c8ca0d417720","webpack:///./v1.js"],"names":["window","bar","Promise","resolve","setTimeout"],"mappings":";AAAA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAK;AACL;AACA;;AAEA;AACA;AACA;AACA,mCAA2B,0BAA0B,EAAE;AACvD,yCAAiC,eAAe;AAChD;AACA;AACA;;AAEA;AACA,8DAAsD,+DAA+D;;AAErH;AACA;;AAEA;AACA;;;;;;;;AC7DAA,OAAOC,GAAP,GAAa,SAASA,GAAT,GAAe;AAC1B,SAAO,IAAIC,OAAJ,CAAYC,WAAWC,WAAWD,OAAX,EAAoB,GAApB,CAAvB,CAAP;AACD,CAFD,C","file":"v3.bundle.js","sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, {\n \t\t\t\tconfigurable: false,\n \t\t\t\tenumerable: true,\n \t\t\t\tget: getter\n \t\t\t});\n \t\t}\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 2);\n\n\n\n// WEBPACK FOOTER //\n// webpack/bootstrap 7f7d36c9c8ca0d417720","window.bar = function bar() {\n  return new Promise(resolve => setTimeout(resolve, 100))\n}\n\n\n\n// WEBPACK FOOTER //\n// ./v3.js"],"sourceRoot":""}
\ No newline at end of file
--- a/devtools/client/debugger/new/test/mochitest/examples/sourcemaps-reload/v3.js
+++ b/devtools/client/debugger/new/test/mochitest/examples/sourcemaps-reload/v3.js
@@ -1,3 +1,3 @@
-function bar() {
+window.bar = function bar() {
   return new Promise(resolve => setTimeout(resolve, 100))
 }
--- a/devtools/client/debugger/new/test/mochitest/helpers.js
+++ b/devtools/client/debugger/new/test/mochitest/helpers.js
@@ -12,16 +12,18 @@ Services.scriptloader.loadSubScript(
   "chrome://mochitests/content/browser/devtools/client/debugger/new/test/mochitest/helpers/context.js",
   this
 );
 
 var { Toolbox } = require("devtools/client/framework/toolbox");
 var { Task } = require("devtools/shared/task");
 var asyncStorage = require("devtools/shared/async-storage");
 
+const { getSelectedLocation } = require("devtools/client/debugger/new/src/utils/source-maps");
+
 const sourceUtils = {
   isLoaded: source => source.loadedState === "loaded"
 };
 
 function log(msg, data) {
   info(`${msg} ${!data ? "" : JSON.stringify(data)}`);
 }
 
@@ -214,41 +216,44 @@ async function waitForElement(dbg, name,
 }
 
 async function waitForElementWithSelector(dbg, selector) {
   await waitUntil(() => findElementWithSelector(dbg, selector));
   return findElementWithSelector(dbg, selector);
 }
 
 function waitForSelectedSource(dbg, url) {
+  const {
+    getSelectedSource,
+    hasSymbols,
+    hasSourceMetaData,
+    hasBreakpointPositions
+  } = dbg.selectors;
+
   return waitForState(
     dbg,
     state => {
-      const source = dbg.selectors.getSelectedSource(state);
+      const source = getSelectedSource(state);
       const isLoaded = source && sourceUtils.isLoaded(source);
       if (!isLoaded) {
         return false;
       }
 
       if (!url) {
         return true;
       }
 
       const newSource = findSource(dbg, url, { silent: true });
       if (newSource.id != source.id) {
         return false;
       }
 
-      // wait for async work to be done
-      const hasSymbols = dbg.selectors.hasSymbols(state, source);
-      const hasSourceMetaData = dbg.selectors.hasSourceMetaData(
-        state,
-        source.id
-      );
-      return hasSymbols && hasSourceMetaData;
+      return hasSymbols(state, source) &&
+        hasSourceMetaData( state, source.id) &&
+        hasBreakpointPositions(state, source.id);
     },
     "selected source"
   );
 }
 
 /**
  * Assert that the debugger is not currently paused.
  * @memberof mochitest/asserts
@@ -726,32 +731,43 @@ async function reload(dbg, ...sources) {
 async function navigate(dbg, url, ...sources) {
   info(`Navigating to ${url}`);
   const navigated = waitForDispatch(dbg, "NAVIGATE");
   await dbg.client.navigate(url);
   await navigated;
   return waitForSources(dbg, ...sources);
 }
 
+function getFirstBreakpointColumn(dbg, {line, sourceId}) {
+  const {getSource, getFirstBreakpointPosition} = dbg.selectors;
+  const source = getSource(dbg.getState(), sourceId)
+  const position = getFirstBreakpointPosition(dbg.getState(), { line, sourceId });
+
+  return getSelectedLocation(position, source).column;
+}
+
 /**
  * Adds a breakpoint to a source at line/col.
  *
  * @memberof mochitest/actions
  * @param {Object} dbg
  * @param {String} source
  * @param {Number} line
  * @param {Number} col
  * @return {Promise}
  * @static
  */
-function addBreakpoint(dbg, source, line, column, options) {
+async function addBreakpoint(dbg, source, line, column) {
   source = findSource(dbg, source);
   const sourceId = source.id;
-  dbg.actions.addBreakpoint({ sourceId, line, column }, options);
-  return waitForDispatch(dbg, "ADD_BREAKPOINT");
+  column = column || getFirstBreakpointColumn(dbg, {line, sourceId: source.id});
+  const bpCount = dbg.selectors.getBreakpointCount(dbg.getState());
+  dbg.actions.addBreakpoint({ sourceId, line, column });
+  await waitForDispatch(dbg, "ADD_BREAKPOINT");
+  is(dbg.selectors.getBreakpointCount(dbg.getState()), bpCount + 1, "a new breakpoint was created");
 }
 
 function disableBreakpoint(dbg, source, line, column) {
   const location = { sourceId: source.id, sourceUrl: source.url, line, column };
   const bp = dbg.selectors.getBreakpointForLocation(dbg.getState(), location);
   dbg.actions.disableBreakpoint(bp);
   return waitForDispatch(dbg, "DISABLE_BREAKPOINT");
 }
@@ -760,32 +776,21 @@ function setBreakpointOptions(dbg, sourc
   source = findSource(dbg, source);
   const sourceId = source.id;
   dbg.actions.setBreakpointOptions({ sourceId, line, column }, options);
   return waitForDispatch(dbg, "SET_BREAKPOINT_OPTIONS");
 }
 
 function findBreakpoint(dbg, url, line) {
   const {
-    selectors: { getBreakpoint },
+    selectors: { getBreakpoint, getBreakpointsList },
     getState
   } = dbg;
   const source = findSource(dbg, url);
-  let column;
-  if (
-    Services.prefs.getBoolPref("devtools.debugger.features.column-breakpoints")
-  ) {
-    ({ column } = dbg.selectors.getFirstVisibleBreakpointPosition(
-      dbg.store.getState(),
-      {
-        sourceId: source.id,
-        line
-      }
-    ));
-  }
+  const column = getFirstBreakpointColumn(dbg, {line, sourceId: source.id });
   return getBreakpoint(getState(), { sourceId: source.id, line, column });
 }
 
 async function loadAndAddBreakpoint(dbg, filename, line, column) {
   const {
     selectors: { getBreakpoint, getBreakpointCount, getBreakpointsMap },
     getState
   } = dbg;
@@ -896,16 +901,17 @@ async function assertScopes(dbg, items) 
  * @param {String} source
  * @param {Number} line
  * @param {Number} col
  * @return {Promise}
  * @static
  */
 function removeBreakpoint(dbg, sourceId, line, column) {
   const source = dbg.selectors.getSource(dbg.getState(), sourceId);
+  column = column || getFirstBreakpointColumn(dbg, {line, sourceId});
   const location = { sourceId, sourceUrl: source.url, line, column };
   const bp = dbg.selectors.getBreakpointForLocation(dbg.getState(), location);
   dbg.actions.removeBreakpoint(bp);
   return waitForDispatch(dbg, "REMOVE_BREAKPOINT");
 }
 
 /**
  * Toggles the Pause on exceptions feature in the debugger.
@@ -1222,18 +1228,25 @@ async function clickElement(dbg, element
   const el = await waitForElementWithSelector(dbg, selector);
 
   el.scrollIntoView();
 
   return clickElementWithSelector(dbg, selector);
 }
 
 function clickElementWithSelector(dbg, selector) {
+  clickDOMElement(
+    dbg,
+    findElementWithSelector(dbg, selector)
+  );
+}
+
+function clickDOMElement(dbg, element) {
   EventUtils.synthesizeMouseAtCenter(
-    findElementWithSelector(dbg, selector),
+    element,
     {},
     dbg.win
   );
 }
 
 function dblClickElement(dbg, elementName, ...args) {
   const selector = getSelector(elementName, ...args);
 
@@ -1320,16 +1333,43 @@ function getCoordsFromPosition(cm, { lin
 
 async function waitForScrolling(codeMirror) {
   return new Promise(resolve => {
     codeMirror.on("scroll", resolve);
     setTimeout(resolve, 500);
   });
 }
 
+async function codeMirrorGutterElement(dbg, line) {
+  info(`CodeMirror line ${line}`);
+  const cm = getCM(dbg);
+
+  const position = { line: line - 1, ch: 0 };
+  cm.scrollIntoView(position, 0);
+  await waitForScrolling(cm);
+
+  const coords = getCoordsFromPosition(cm, position);
+
+  const { left, top } = coords;
+
+  // Adds a vertical offset due to increased line height
+  // https://github.com/firefox-devtools/debugger/pull/7934
+  const lineHeightOffset = 3;
+
+  const tokenEl = dbg.win.document.elementFromPoint(
+    left,
+    top + lineHeightOffset
+  );
+
+  if (!tokenEl) {
+    throw new Error("Failed to find element for line " + line);
+  }
+  return tokenEl;
+}
+
 async function hoverAtPos(dbg, { line, ch }) {
   info(`Hovering at ${line}, ${ch}`);
   const cm = getCM(dbg);
 
   // Ensure the line is visible with margin because the bar at the bottom of
   // the editor overlaps into what the editor things is its own space, blocking
   // the click event below.
   cm.scrollIntoView({ line: line - 1, ch }, 0);
--- a/devtools/client/framework/test/test_browser_toolbox_debugger.js
+++ b/devtools/client/framework/test/test_browser_toolbox_debugger.js
@@ -1,11 +1,11 @@
 /* global toolbox, createDebuggerContext, waitForSources, testUrl,
           waitForPaused, addBreakpoint, assertPausedLocation, stepIn,
-          findSource, removeBreakpoint, resume */
+          findSource, removeBreakpoint, resume, selectSource */
 
 info(`START: ${new Error().lineNumber}`);
 
 (async function() {
   Services.prefs.clearUserPref("devtools.debugger.tabs");
   Services.prefs.clearUserPref("devtools.debugger.pending-selected-location");
 
   info("Waiting for debugger load");
@@ -29,16 +29,17 @@ info(`START: ${new Error().lineNumber}`)
 
   let script = [...document.querySelectorAll(".tree-node")].find(node => {
     return node.textContent.includes(fileName);
   });
   script = script.querySelector(".node");
   script.click();
 
   const onPaused = waitForPaused(dbg);
+  await selectSource(dbg, fileName);
   await addBreakpoint(dbg, fileName, 2);
 
   await onPaused;
 
   assertPausedLocation(dbg, fileName, 2);
 
   await stepIn(dbg);
 
--- a/devtools/client/shared/source-map/worker.js
+++ b/devtools/client/shared/source-map/worker.js
@@ -7244,28 +7244,39 @@ async function getOriginalSourceText(ori
  *   contiguous ranges associated with a file, rather than the specifics of
  *   the ranges provided by the sourcemap.
  */
 const GENERATED_MAPPINGS = new WeakMap();
 async function getGeneratedRangesForOriginal(sourceId, url, mergeUnmappedRegions = false) {
   assert(isOriginalId(sourceId), "Source is not an original source");
 
   const map = await getSourceMap(originalToGeneratedId(sourceId));
+
+  // NOTE: this is only needed for Flow
   if (!map) {
     return [];
   }
 
   if (!COMPUTED_SPANS.has(map)) {
     COMPUTED_SPANS.add(map);
     map.computeColumnSpans();
   }
 
-  const cachedGeneratedMappingsForOriginal = GENERATED_MAPPINGS.get(map);
-  if (cachedGeneratedMappingsForOriginal) {
-    return cachedGeneratedMappingsForOriginal;
+  if (!GENERATED_MAPPINGS.has(map)) {
+    GENERATED_MAPPINGS.set(map, new Map());
+  }
+
+  const generatedRangesMap = GENERATED_MAPPINGS.get(map);
+  if (!generatedRangesMap) {
+    return [];
+  }
+
+  if (generatedRangesMap.has(sourceId)) {
+    // NOTE we need to coerce the result to an array for Flow
+    return generatedRangesMap.get(sourceId) || [];
   }
 
   // Gather groups of mappings on the generated file, with new groups created
   // if we cross a mapping for a different file.
   let currentGroup = [];
   const originalGroups = [currentGroup];
   map.eachMapping(mapping => {
     if (mapping.source === url) {
@@ -7317,17 +7328,17 @@ async function getGeneratedRangesForOrig
           const newEntry = { start, end };
           generatedMappingsForOriginal.push(newEntry);
           lastEntry = newEntry;
         }
       }
     }
   }
 
-  GENERATED_MAPPINGS.set(map, generatedMappingsForOriginal);
+  generatedRangesMap.set(sourceId, generatedMappingsForOriginal);
   return generatedMappingsForOriginal;
 }
 
 function wrappedMappingPosition(pos) {
   if (pos.column !== Infinity) {
     return pos;
   }
 
--- a/devtools/client/webconsole/test/mochitest/browser_webconsole_optimized_out_vars.js
+++ b/devtools/client/webconsole/test/mochitest/browser_webconsole_optimized_out_vars.js
@@ -15,16 +15,17 @@ const TEST_URI = "http://example.com/bro
 add_task(async function() {
   const breakpointLine = 18;
   const hud = await openNewTabAndConsole(TEST_URI);
   await openDebugger();
 
   const toolbox = gDevTools.getToolbox(hud.target);
   const dbg = createDebuggerContext(toolbox);
 
+  await selectSource(dbg, "test-closure-optimized-out.html");
   await addBreakpoint(dbg, "test-closure-optimized-out.html", breakpointLine);
 
   // Cause the debuggee to pause
   await pauseDebugger(dbg);
 
   await toolbox.selectTool("webconsole");
 
   // This is the meat of the test: evaluate the optimized out variable.
--- a/testing/talos/talos/tests/devtools/addon/content/tests/debugger/debugger-helpers.js
+++ b/testing/talos/talos/tests/devtools/addon/content/tests/debugger/debugger-helpers.js
@@ -234,18 +234,20 @@ async function reloadDebuggerAndLog(labe
 exports.reloadDebuggerAndLog = reloadDebuggerAndLog;
 
 async function addBreakpoint(dbg, line, url) {
   dump(`add breakpoint\n`);
   const source = findSource(dbg, url);
   const location = {
     sourceId: source.id,
     line,
-    column: 0,
   };
+
+  await selectSource(dbg, url);
+
   const onDispatched = waitForDispatch(dbg, "ADD_BREAKPOINT");
   dbg.actions.addBreakpoint(location);
   return onDispatched;
 }
 exports.addBreakpoint = addBreakpoint;
 
 async function removeBreakpoints(dbg, line, url) {
   dump(`remove all breakpoints\n`);