Backed out changeset 295288a58683 (bug 1531350) for failing at /browser_dbg-sourcemaps-reload.js on a CLOSED TREE.
authorGurzau Raul <rgurzau@mozilla.com>
Wed, 06 Mar 2019 10:49:10 +0200
changeset 520438 2c2584c8276f00c69f24e2a3353aaf642c144f05
parent 520437 a902fdf8f03ca2a1a502fd30077a7197bf79140e
child 520439 35f5d2d519eb442c74d883fc88fcbc0e10b6af5b
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)
bugs1531350
milestone67.0a1
backs out295288a5868385e81cc0e96f2acc7ead3039ff7a
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
Backed out changeset 295288a58683 (bug 1531350) for failing at /browser_dbg-sourcemaps-reload.js on a CLOSED TREE.
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/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,27 +30,16 @@ 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();
@@ -349,43 +338,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<Range[]> {
+): Promise<
+  Array<{
+    start: {
+      line: number,
+      column: number
+    },
+    end: {
+      line: number,
+      column: number
+    }
+  }>
+> {
   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();
   }
 
-  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) || [];
+  const cachedGeneratedMappingsForOriginal = GENERATED_MAPPINGS.get(map);
+  if (cachedGeneratedMappingsForOriginal) {
+    return cachedGeneratedMappingsForOriginal;
   }
 
   // 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 => {
@@ -451,17 +440,17 @@ async function getGeneratedRangesForOrig
           const newEntry = { start, end };
           generatedMappingsForOriginal.push(newEntry);
           lastEntry = newEntry;
         }
       }
     }
   }
 
-  generatedRangesMap.set(sourceId, generatedMappingsForOriginal);
+  GENERATED_MAPPINGS.set(map, 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,20 +76,16 @@ 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,43 +4,70 @@
 
 // @flow
 
 import {
   breakpointExists,
   assertBreakpoint,
   createBreakpoint,
   getASTLocation,
+  assertLocation,
   makeBreakpointId,
-  makeBreakpointLocation,
-  findPosition
+  makeBreakpointLocation
 } from "../../utils/breakpoint";
 import { PROMISE } from "../utils/middleware/promise";
 import {
+  getSource,
   getSymbols,
-  getFirstVisibleBreakpointPosition,
-  getBreakpointPositionsForSource,
-  getSourceFromId
+  getFirstVisibleBreakpointPosition
 } 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 { location, generatedLocation } = breakpoint;
-  const source = getSourceFromId(state, location.sourceId);
-  const generatedSource = getSourceFromId(state, generatedLocation.sourceId);
+  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);
 
   if (breakpointExists(state, location)) {
     const newBreakpoint = { ...breakpoint, location, generatedLocation };
     assertBreakpoint(newBreakpoint);
     return newBreakpoint;
   }
 
   const breakpointLocation = makeBreakpointLocation(
@@ -96,31 +123,30 @@ export function enableBreakpoint(breakpo
 }
 
 export function addBreakpoint(
   location: SourceLocation,
   options: BreakpointOptions = {}
 ) {
   return async ({ dispatch, getState, sourceMaps, client }: ThunkArgs) => {
     recordEvent("add_breakpoint");
-    let position;
-    const { sourceId, column } = location;
-
-    if (column === undefined) {
-      position = getFirstVisibleBreakpointPosition(getState(), location);
-    } else {
-      const positions = getBreakpointPositionsForSource(getState(), sourceId);
-      position = findPosition(positions, location);
+    let breakpointPosition = location;
+    if (features.columnBreakpoints && location.column === undefined) {
+      await dispatch(setBreakpointPositions(location.sourceId));
+      breakpointPosition = getFirstVisibleBreakpointPosition(
+        getState(),
+        location
+      );
     }
 
-    if (!position) {
+    if (!breakpointPosition) {
       return;
     }
 
-    const breakpoint = createBreakpoint(position, { options });
+    const breakpoint = createBreakpoint(breakpointPosition, { 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,127 +1,110 @@
 /* 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 {
-  getSource,
-  getSourceFromId,
-  hasBreakpointPositions,
-  getBreakpointPositionsForSource
-} from "../../selectors";
+import { getSourceFromId, hasBreakpointPositions } 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: SourceLocation[],
-  { sourceMaps }: { sourceMaps: SourceMaps }
-) {
+async function mapLocations(generatedLocations, state, source, sourceMaps) {
   return Promise.all(
-    (generatedLocations: any).map(async (generatedLocation: SourceLocation) => {
-      const location = await getOriginalLocation(generatedLocation, sourceMaps);
+    generatedLocations.map(async generatedLocation => {
+      const location = await getOriginalLocation(
+        generatedLocation,
+        source,
+        sourceMaps
+      );
 
       return { location, generatedLocation };
     })
   );
 }
 
-function filterByUniqLocation(positions: MappedLocation[]) {
-  return uniqBy(positions, ({ location }) => makeBreakpointId(location));
-}
-
-function convertToList(results, source) {
-  const { id, url } = source;
+function convertToList(results, sourceId) {
   const positions = [];
 
   for (const line in results) {
     for (const column of results[line]) {
-      positions.push({
-        line: Number(line),
-        column: column,
-        sourceId: id,
-        sourceUrl: url
-      });
+      positions.push({ line: Number(line), column: column, sourceId });
     }
   }
 
   return positions;
 }
 
-async function _setBreakpointPositions(sourceId, thunkArgs) {
-  const { client, dispatch, getState, sourceMaps } = thunkArgs;
-  let generatedSource = getSource(getState(), sourceId);
-  if (!generatedSource) {
-    return;
-  }
+async function getBreakpointPositions(
+  sourceId,
+  { client, dispatch, getState, sourceMaps }
+) {
+  let source = getSourceFromId(getState(), sourceId);
 
   let results = {};
   if (isOriginalId(sourceId)) {
     const ranges = await sourceMaps.getGeneratedRangesForOriginal(
       sourceId,
-      generatedSource.url,
+      source.url,
       true
     );
-    const generatedSourceId = originalToGeneratedId(sourceId);
-    generatedSource = getSourceFromId(getState(), generatedSourceId);
+    sourceId = originalToGeneratedId(sourceId);
+    source = getSourceFromId(getState(), sourceId);
 
     // 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(generatedSource, range);
+      const bps = await client.getBreakpointPositions(source.actors[0], range);
       for (const line in bps) {
         results[line] = (results[line] || []).concat(bps[line]);
       }
     }
   } else {
-    results = await client.getBreakpointPositions(generatedSource);
+    results = await client.getBreakpointPositions(source.actors[0]);
   }
 
-  let positions = convertToList(results, generatedSource);
-  positions = await mapLocations(positions, thunkArgs);
-  positions = filterByUniqLocation(positions);
-  dispatch({ type: "ADD_BREAKPOINT_POSITIONS", sourceId, positions });
+  const positions = convertToList(results, sourceId);
+  return mapLocations(positions, getState(), source, sourceMaps);
 }
 
 export function setBreakpointPositions(sourceId: string) {
   return async (thunkArgs: ThunkArgs) => {
-    const { getState } = thunkArgs;
+    const { dispatch, getState } = thunkArgs;
+
     if (hasBreakpointPositions(getState(), sourceId)) {
-      return getBreakpointPositionsForSource(getState(), sourceId);
+      return;
     }
 
     if (!requests.has(sourceId)) {
       requests.set(
         sourceId,
         (async () => {
           try {
-            await _setBreakpointPositions(sourceId, thunkArgs);
+            dispatch({
+              type: "ADD_BREAKPOINT_POSITIONS",
+              sourceId,
+              positions: await getBreakpointPositions(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,67 +1,68 @@
 /* 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,
-  findFunctionByName,
-  findPosition,
+  findScopeByName,
   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 } from "../../selectors";
+import { getSource, getBreakpointPositionsForSource } from "../../selectors";
+import { features } from "../../utils/prefs";
 
 import type { ThunkArgs, Action } from "../types";
 
 import type {
   SourceLocation,
   ASTLocation,
   PendingBreakpoint,
   SourceId,
   Breakpoint
 } from "../../types";
 
 type BreakpointSyncData = {
   previousLocation: SourceLocation,
   breakpoint: ?Breakpoint
 };
 
-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 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 findNewLocation(
+async function makeScopedLocation(
   { name, offset, index }: ASTLocation,
   location: SourceLocation,
   source
 ) {
-  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;
-  }
-
+  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;
   return {
     line,
     column: location.column,
     sourceUrl: source.url,
     sourceId: source.id
   };
 }
 
@@ -70,143 +71,173 @@ function createSyncData(
   location: SourceLocation,
   generatedLocation: SourceLocation,
   previousLocation: SourceLocation,
   text: string,
   originalText: string
 ): BreakpointSyncData {
   const overrides = {
     ...pendingBreakpoint,
+    generatedLocation,
     text,
     originalText
   };
-  const breakpoint = createBreakpoint(
-    { generatedLocation, location },
-    overrides
-  );
+  const breakpoint = createBreakpoint(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(
-  thunkArgs: ThunkArgs,
+  getState: Function,
+  client: Object,
+  sourceMaps: Object,
+  dispatch: Function,
   sourceId: SourceId,
   pendingBreakpoint: PendingBreakpoint
-): Promise<?BreakpointSyncData> {
-  const { getState, client } = thunkArgs;
+): Promise<BreakpointSyncData | null> {
   assertPendingBreakpoint(pendingBreakpoint);
 
   const source = getSource(getState(), sourceId);
 
   const generatedSourceId = isOriginalId(sourceId)
     ? originalToGeneratedId(sourceId)
     : sourceId;
 
   const generatedSource = getSource(getState(), generatedSourceId);
 
-  if (!source || !generatedSource) {
-    return;
+  if (!source) {
+    return null;
   }
 
-  const { location, generatedLocation, astLocation } = pendingBreakpoint;
+  const { location, astLocation } = pendingBreakpoint;
   const previousLocation = { ...location, sourceId };
 
-  const newLocation = await findNewLocation(
+  const scopedLocation = await makeScopedLocation(
     astLocation,
     previousLocation,
     source
   );
 
-  const newGeneratedLocation = await findBreakpointPosition(
-    thunkArgs,
-    newLocation
+  const scopedGeneratedLocation = await getGeneratedLocation(
+    getState(),
+    source,
+    scopedLocation,
+    sourceMaps
   );
 
-  const isSameLocation = comparePosition(
+  // 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(
     generatedLocation,
-    newGeneratedLocation
+    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
   );
 
   /** ******* CASE 1: No server change ***********/
   // early return if breakpoint is disabled or we are in the sameLocation
-  if (newGeneratedLocation && (pendingBreakpoint.disabled || isSameLocation)) {
+  if (possiblePosition && (pendingBreakpoint.disabled || isSameLocation)) {
     // Make sure the breakpoint is installed on all source actors.
     if (!pendingBreakpoint.disabled) {
-      await client.setBreakpoint(
-        makeBreakpointLocation(getState(), newGeneratedLocation),
-        pendingBreakpoint.options
-      );
+      await client.setBreakpoint(breakpointLocation, pendingBreakpoint.options);
     }
 
     const originalText = getTextAtPosition(source, previousLocation);
-    const text = getTextAtPosition(generatedSource, newGeneratedLocation);
+    const text = getTextAtPosition(generatedSource, generatedLocation);
 
     return createSyncData(
       pendingBreakpoint,
-      newLocation,
-      newGeneratedLocation,
+      scopedLocation,
+      scopedGeneratedLocation,
       previousLocation,
       text,
       originalText
     );
   }
 
   // clear server breakpoints if they exist and we have moved
-  await client.removeBreakpoint(generatedLocation);
+  await client.removeBreakpoint(breakpointLocation);
 
-  if (!newGeneratedLocation) {
+  if (!possiblePosition || !scopedGeneratedLocation.line) {
     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(
-    makeBreakpointLocation(getState(), newGeneratedLocation),
+    scopedGeneratedLocation,
     pendingBreakpoint.options
   );
 
-  const originalText = getTextAtPosition(source, newLocation);
-  const text = getTextAtPosition(generatedSource, newGeneratedLocation);
+  const originalText = getTextAtPosition(source, scopedLocation);
+  const text = getTextAtPosition(generatedSource, scopedGeneratedLocation);
 
   return createSyncData(
     pendingBreakpoint,
-    newLocation,
-    newGeneratedLocation,
+    scopedLocation,
+    scopedGeneratedLocation,
     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 (thunkArgs: ThunkArgs) => {
-    const { dispatch } = thunkArgs;
-
+  return async ({ dispatch, getState, client, sourceMaps }: ThunkArgs) => {
     const response = await syncBreakpointPromise(
-      thunkArgs,
+      getState,
+      client,
+      sourceMaps,
+      dispatch,
       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,33 +4,30 @@ 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:1",
+        "id": "a:2:",
         "loading": false,
         "location": Object {
-          "column": 1,
           "line": 2,
           "sourceId": "a",
           "sourceUrl": "http://localhost:8000/examples/a",
         },
         "options": Object {
           "condition": null,
           "hidden": false,
           "logValue": null,
@@ -62,25 +59,23 @@ 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,
@@ -102,33 +97,30 @@ 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:1",
+        "id": "a:5:",
         "loading": false,
         "location": Object {
-          "column": 1,
           "line": 5,
           "sourceId": "a",
           "sourceUrl": "http://localhost:8000/examples/a",
         },
         "options": Object {
           "condition": null,
           "hidden": false,
           "logValue": null,
new file mode 100644
--- /dev/null
+++ b/devtools/client/debugger/new/src/actions/breakpoints/tests/__snapshots__/syncing.spec.js.snap
@@ -0,0 +1,199 @@
+// 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,28 +26,18 @@ describe("breakpointPositions", () => {
     await waitForState(store, state =>
       selectors.hasBreakpointPositions(state, "foo")
     );
 
     expect(
       selectors.getBreakpointPositionsForSource(getState(), "foo")
     ).toEqual([
       {
-        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"
-        }
+        location: { line: 9, column: 1, sourceId: "foo" },
+        generatedLocation: { line: 9, column: 1, sourceId: "foo" }
       }
     ]);
   });
 
   it("doesn't re-fetch positions", async () => {
     let resolve = _ => {};
     let count = 0;
     const store = createStore({
@@ -68,26 +58,16 @@ describe("breakpointPositions", () => {
     await waitForState(store, state =>
       selectors.hasBreakpointPositions(state, "foo")
     );
 
     expect(
       selectors.getBreakpointPositionsForSource(getState(), "foo")
     ).toEqual([
       {
-        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"
-        }
+        location: { line: 9, column: 1, sourceId: "foo" },
+        generatedLocation: { line: 9, column: 1, sourceId: "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,202 +9,144 @@ 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(mockClient({ "2": [1] }));
+    const { dispatch, getState } = createStore(simpleMockThreadClient);
     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(mockClient({ "5": [1] }));
+    const { dispatch, getState } = createStore(simpleMockThreadClient);
     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(mockClient({ "5": [1] }));
+    const { dispatch, getState } = createStore(simpleMockThreadClient);
     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(mockClient({ "5": [1] }));
+    const { dispatch, getState } = createStore(simpleMockThreadClient);
     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(
-      mockClient({ "5": [1], "6": [2] })
-    );
+    const { dispatch, getState } = createStore(simpleMockThreadClient);
 
     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(
-      mockClient({ "5": [1], "6": [2] })
-    );
+    const { dispatch, getState } = createStore(simpleMockThreadClient);
 
     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");
@@ -216,23 +158,20 @@ 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(
-      mockClient({ "5": [1], "6": [2] })
-    );
+    const { dispatch, getState } = createStore(simpleMockThreadClient);
     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));
@@ -243,31 +182,27 @@ 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(
-      mockClient({ "5": [1], "6": [2] })
-    );
+    const { dispatch, getState } = createStore(simpleMockThreadClient);
 
     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");
@@ -276,53 +211,52 @@ 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 loc = { sourceId: "foo1", line: 5, column: 1 };
-    const getBp = () => selectors.getBreakpoint(getState(), loc);
+    const location = { sourceId: "foo1", line: 5 };
+    const getBp = () => selectors.getBreakpoint(getState(), location);
 
-    const { dispatch, getState } = createStore(mockClient({ "5": [1] }));
+    const { dispatch, getState } = createStore(simpleMockThreadClient);
 
     const source = makeSource("foo1");
     await dispatch(actions.newSource(source));
     await dispatch(actions.loadSourceText(source));
 
-    await dispatch(actions.selectLocation(loc));
+    await dispatch(actions.selectLocation({ sourceId: "foo1", line: 1 }));
 
     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, column: 1 };
+    const location = { sourceId: "foo1", line: 5 };
     const getBp = () => selectors.getBreakpoint(getState(), location);
 
-    const { dispatch, getState } = createStore(mockClient({ "5": [1] }));
+    const { dispatch, getState } = createStore(simpleMockThreadClient);
 
     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));
@@ -333,22 +267,21 @@ 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(mockClient({ "5": [1] }));
+    const { dispatch, getState } = createStore(simpleMockThreadClient);
 
     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));
@@ -363,29 +296,25 @@ 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(mockClient({ "5": [1] }));
+    const { dispatch, getState } = createStore(simpleMockThreadClient);
 
     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.newSource(makeSource("a")));
     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, {
@@ -396,22 +325,21 @@ 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(mockClient({ "1": [0] }));
+    const { dispatch, getState } = createStore(simpleMockThreadClient);
 
     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));
new file mode 100644
--- /dev/null
+++ b/devtools/client/debugger/new/src/actions/breakpoints/tests/syncing.spec.js
@@ -0,0 +1,303 @@
+/* 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,18 +64,17 @@ 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 = {}
 ) {
@@ -316,18 +315,17 @@ 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,18 +1,16 @@
 /* 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";
@@ -83,19 +81,18 @@ export function loadSourceText(source: ?
       return;
     }
 
     if (isOriginal(newSource) && !newSource.isWasm) {
       const generatedSource = getGeneratedSource(getState(), source);
       await dispatch(loadSourceText(generatedSource));
     }
 
-    if (!newSource.isWasm && isLoaded(newSource)) {
+    if (!newSource.isWasm) {
       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, setBreakpointPositions } from "../breakpoints";
+import { remapBreakpoints } 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 { mapLocation } from "../../utils/source-maps";
+import { getMappedLocation } 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 mapLocation(getState(), sourceMaps, location);
+      location = await getMappedLocation(getState(), sourceMaps, location);
       source = getSourceFromId(getState(), location.sourceId);
     }
 
     const tabSources = getSourcesForTabs(getState());
     if (!tabSources.includes(source)) {
       dispatch(addTab(source));
     }
 
@@ -187,17 +187,21 @@ export function selectSpecificLocation(l
  * @static
  */
 export function jumpToMappedLocation(location: SourceLocation) {
   return async function({ dispatch, getState, client, sourceMaps }: ThunkArgs) {
     if (!client) {
       return;
     }
 
-    const pairedLocation = await mapLocation(getState(), sourceMaps, location);
+    const pairedLocation = await getMappedLocation(
+      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,18 +41,17 @@ 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));
@@ -74,18 +73,17 @@ 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,18 +225,17 @@ 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: "" }),
-        getGeneratedRangesForOriginal: async () => []
+        getOriginalSourceText: async () => ({ source: "" })
       }
     );
 
     const baseSource = makeSource("base.js");
     await dispatch(actions.newSource(baseSource));
 
     const originalBaseSource = makeOriginalSource("base.js");
     await dispatch(actions.newSource(originalBaseSource));
@@ -250,26 +249,20 @@ 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 }),
-        getGeneratedRangesForOriginal: async () => [],
-        getOriginalSourceText: async () => ({ source: "" })
-      }
+      { getOriginalLocation: async location => ({ ...location, line: 12 }) }
     );
 
-    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:2": Object {
+  "http://localhost:8000/examples/bar.js:5:": Object {
     "astLocation": Object {
       "index": 0,
       "name": undefined,
       "offset": Object {
         "line": 5,
       },
     },
     "disabled": false,
     "generatedLocation": Object {
-      "column": 2,
+      "column": undefined,
       "line": 5,
       "sourceUrl": "http://localhost:8000/examples/bar.js",
     },
     "location": Object {
-      "column": 2,
+      "column": undefined,
       "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": 1,
+      "column": 0,
       "line": 5,
-      "sourceId": "foo.js",
+      "sourceId": "foo.js/originalSource",
       "sourceUrl": "http://localhost:8000/examples/foo.js",
     },
   },
   "disabled": false,
   "generatedLocation": Object {
-    "column": 1,
+    "column": undefined,
     "line": 5,
     "sourceUrl": "http://localhost:8000/examples/foo.js",
   },
   "location": Object {
-    "column": 1,
+    "column": 0,
     "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",
+      "sourceId": "foo/originalSource",
       "sourceUrl": "http://localhost:8000/examples/foo",
     },
   },
   "disabled": false,
   "generatedLocation": Object {
-    "column": 0,
+    "column": undefined,
     "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",
+      "sourceId": "foo2/originalSource",
       "sourceUrl": "http://localhost:8000/examples/foo2",
     },
   },
   "disabled": false,
   "generatedLocation": Object {
-    "column": 0,
+    "column": undefined,
     "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,27 +30,25 @@ 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] })),
-  getBreakpointPositions: async () => ({})
+    expressions.map(expression => ({ result: evaluationResult[expression] }))
 };
 
 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 || 1
+      column: column || undefined
     },
     generatedLocation: {
       sourceUrl: sourceUrl || "http://localhost:8000/examples/bar.js",
       line: line || 5,
-      column: column || 1
+      column: column || undefined
     },
     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,11 +71,10 @@ export const sourceThreadClient = {
         resolve(createSource(source));
       }
 
       reject(`unknown source: ${source}`);
     });
   },
   threadClient: async () => {},
   getFrameScopes: async () => {},
-  evaluateExpressions: async () => {},
-  getBreakpointPositions: async () => ({})
+  evaluateExpressions: 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: async () => ({
-    source: "function foo1() {\n  const foo = 5; return foo;\n}",
-    contentType: "text/javascript"
-  }),
-  getBreakpointPositions: async () => ({})
+  sourceContents: () =>
+    Promise.resolve({
+      source: "function foo1() {\n  const foo = 5; return foo;\n}",
+      contentType: "text/javascript"
+    })
 };
 
 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, column: 2});
-  const id = makePendingLocationId(mockedPendingBreakpoint.location)
+  const mockedPendingBreakpoint = mockPendingBreakpoint(opts);
+  const id = makePendingLocationId(mockedPendingBreakpoint.location);
   asyncStore.pendingBreakpoints = { [id]: mockedPendingBreakpoint };
 
   return { pendingBreakpoints: asyncStore.pendingBreakpoints };
 }
 
 jest.mock("../../utils/prefs", () => ({
   prefs: {
     clientSourceMapsEnabled: true,
@@ -42,51 +42,31 @@ 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(
-      mockClient({ "5": [1] }),
-      loadInitialState(),
-      mockSourceMaps()
+      simpleMockThreadClient,
+      loadInitialState()
     );
 
     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", 5, 1);
+    const bp = generateBreakpoint("foo.js");
     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();
   });
@@ -101,19 +81,18 @@ 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(
-        mockClient({ "5": [0] }),
-        loadInitialState(),
-        mockSourceMaps()
+        simpleMockThreadClient,
+        loadInitialState()
       );
 
       const source1 = makeOriginalSource("foo");
       const source2 = makeOriginalSource("foo2");
 
       await dispatch(actions.newSource(makeSource("foo")));
       await dispatch(actions.newSource(makeSource("foo2")));
 
@@ -122,29 +101,24 @@ 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(
-        mockClient({ "5": [0] }),
-        loadInitialState(),
-        mockSourceMaps()
+        simpleMockThreadClient,
+        loadInitialState()
       );
 
       const source = makeOriginalSource("foo");
       await dispatch(actions.newSource(makeSource("foo")));
       await dispatch(actions.newSource(source));
       await dispatch(actions.loadSourceText(source));
 
       await dispatch(
@@ -152,19 +126,18 @@ 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(
-        mockClient({ "5": [0] }),
-        loadInitialState(),
-        mockSourceMaps()
+        simpleMockThreadClient,
+        loadInitialState()
       );
 
       await dispatch(actions.newSource(makeSource("foo")));
       await dispatch(actions.newSource(makeSource("foo2")));
 
       const source1 = makeOriginalSource("foo");
       const source2 = makeOriginalSource("foo2");
 
@@ -183,19 +156,18 @@ 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(
-      mockClient({ "5": [0] }),
-      loadInitialState(),
-      mockSourceMaps()
+      simpleMockThreadClient,
+      loadInitialState()
     );
     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));
@@ -206,19 +178,18 @@ 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(
-      mockClient({ "5": [0] }),
-      loadInitialState(),
-      mockSourceMaps()
+      simpleMockThreadClient,
+      loadInitialState()
     );
     const bp = generateBreakpoint("foo");
     const id = makePendingLocationId(bp.location);
 
     await dispatch(actions.newSource(makeSource("foo")));
 
     const source = makeOriginalSource("foo");
     await dispatch(actions.newSource(source));
@@ -228,19 +199,18 @@ 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(
-      mockClient({ "5": [0] }),
-      loadInitialState(),
-      mockSourceMaps()
+      simpleMockThreadClient,
+      loadInitialState()
     );
     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));
 
@@ -254,48 +224,46 @@ 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(
-      mockClient({ "5": [0] }),
-      loadInitialState(),
-      mockSourceMaps()
+      simpleMockThreadClient,
+      loadInitialState()
     );
     const bps = selectors.getPendingBreakpoints(getState());
     expect(bps).toMatchSnapshot();
   });
 
   it("re-adding breakpoints update existing pending breakpoints", async () => {
     const { dispatch, getState } = createStore(
-      mockClient({ "5": [1, 2] }),
-      loadInitialState(),
-      mockSourceMaps()
+      simpleMockThreadClient,
+      loadInitialState()
     );
-    const bar = generateBreakpoint("bar.js", 5, 1);
+    const bar = generateBreakpoint("bar.js");
 
     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(2);
+    expect(bps).toHaveLength(1);
   });
 
   it("adding bps doesn't remove existing pending breakpoints", async () => {
     const { dispatch, getState } = createStore(
-      mockClient({ "5": [0] }),
-      loadInitialState(),
-      mockSourceMaps()
+      simpleMockThreadClient,
+      loadInitialState()
     );
     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));
 
@@ -304,54 +272,49 @@ 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(
-      mockClient({ "5": [2] }),
-      loadInitialState({ disabled: true }),
-      mockSourceMaps()
+      simpleMockThreadClient,
+      loadInitialState({ disabled: true })
     );
 
     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: 2,
+      column: undefined,
       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(
-      mockClient({ "5": [2] }),
-      loadInitialState({ disabled: true }),
-      mockSourceMaps()
-    );
+    const store = createStore(simpleMockThreadClient, loadInitialState());
     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));
@@ -359,52 +322,41 @@ 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(
-      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 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 { 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(
-      mockClient({ "5": [2] }),
-      loadInitialState({ disabled: true }),
-      mockSourceMaps()
-    );
+    const store = createStore(simpleMockThreadClient, loadInitialState());
     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,40 +13,51 @@ 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}`);
+    });
   }
 };
 
-const threadClient = {
-  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));
 
     expect(getTextSearchQuery(getState())).toEqual(mockQuery);
@@ -71,18 +82,17 @@ 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],
-      getGeneratedRangesForOriginal: async () => []
+      getOriginalURLs: async () => [source2.url]
     };
 
     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,27 +5,25 @@
 
 // @flow
 
 import { isTesting } from "devtools-environment";
 import type { ThunkArgs } from "../../types";
 
 const blacklist = [
   "SET_POPUP_OBJECT_PROPERTIES",
-  "ADD_BREAKPOINT_POSITIONS",
+  "SET_PAUSE_POINTS",
   "SET_SYMBOLS",
   "OUT_OF_SCOPE_LOCATIONS",
   "MAP_SCOPES",
   "MAP_FRAMES",
   "ADD_SCOPES",
   "IN_SCOPE_LINES",
   "REMOVE_BREAKPOINT",
-  "NODE_PROPERTIES_LOADED",
-  "SET_FOCUSED_SOURCE_ITEM",
-  "NODE_EXPAND"
+  "NODE_PROPERTIES_LOADED"
 ];
 
 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,24 +7,22 @@
 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,
@@ -172,20 +170,19 @@ 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: BreakpointLocation) {
-  const { sourceUrl, line, column } = location;
-  const sourceId = location.sourceId || "";
-  return `${(sourceUrl: any)}:${sourceId}:${line}:${(column: any)}`;
+function locationKey(location) {
+  const { sourceUrl, sourceId, line, column } = location;
+  return `${(sourceUrl: any)}:${(sourceId: any)}:${line}:${(column: any)}`;
 }
 
 function waitForWorkers(shouldWait: boolean) {
   shouldWaitForWorkers = shouldWait;
 }
 
 async function setBreakpoint(
   location: BreakpointLocation,
@@ -198,18 +195,18 @@ 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: PendingLocation) {
-  delete breakpoints[locationKey((location: any))];
+async function removeBreakpoint(location: BreakpointLocation) {
+  delete breakpoints[locationKey(location)];
   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) {
@@ -403,20 +400,19 @@ async function fetchWorkers(): Promise<W
   return workers;
 }
 
 function getMainThread() {
   return threadClient.actor;
 }
 
 async function getBreakpointPositions(
-  source: Source,
+  sourceActor: SourceActor,
   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,17 +13,16 @@
 import type {
   BreakpointLocation,
   BreakpointOptions,
   FrameId,
   ActorId,
   Script,
   Source,
   Pause,
-  PendingLocation,
   Frame,
   SourceId,
   Worker,
   Range
 } from "../../types";
 
 type URL = string;
 
@@ -339,17 +338,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: PendingLocation => Promise<*>,
+  removeBreakpoint: BreakpointLocation => 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,70 +6,67 @@
 
 import React from "react";
 import { shallow } from "enzyme";
 
 import BreakpointsContextMenu from "../BreakpointsContextMenu";
 import { createBreakpoint } from "../../../../utils/breakpoint";
 import { buildMenu } from "devtools-contextmenu";
 
-import {
-  makeMockSource,
-  makeMappedLocation
-} from "../../../../utils/test-mockup";
+import { makeMockSource } 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,37 +8,33 @@ 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(
-        makeMappedLocation({ line: 1, sourceId: sourceId }),
-        { options: {} }
-      )
+      id1: createBreakpoint({ line: 1, sourceId: sourceId }, { options: {} })
     };
 
     const otherBreakpoints = {
       id2: createBreakpoint(
-        makeMappedLocation({ line: 1, sourceId: "not-this-source" }),
+        { line: 1, sourceId: "not-this-source" },
         { options: {} }
       )
     };
 
     const data = {
       ...matchingBreakpoints,
       ...otherBreakpoints
     };
@@ -53,33 +49,35 @@ 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,54 +23,47 @@ export type BreakpointSources = Array<{
 }>;
 
 function getBreakpointsForSource(
   source: Source,
   selectedSource: ?Source,
   breakpoints: Breakpoint[]
 ) {
   return breakpoints
-    .sort(
-      (a, b) =>
-        getSelectedLocation(a, selectedSource).line -
-        getSelectedLocation(b, selectedSource).line
-    )
+    .sort((a, b) => a.location.line - b.location.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[],
-  selectedSource: ?Source
+  breakpoints: Breakpoint[]
 ): Source[] {
-  const sourceIds: string[] = uniq(
-    breakpoints.map(bp => getSelectedLocation(bp, selectedSource).sourceId)
-  );
+  const sourceIds: string[] = uniq(breakpoints.map(bp => bp.location.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, selectedSource)
+    findBreakpointSources(sources, breakpoints)
       .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,25 +25,26 @@ export {
 } from "../reducers/quick-open";
 
 export {
   getBreakpointAtLocation,
   getBreakpointsAtLine
 } from "./breakpointAtLocation";
 export {
   getVisibleBreakpoints,
-  getFirstVisibleBreakpoints
+  getFirstVisibleBreakpoints,
+  getFirstVisibleBreakpointPosition
 } 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 * from "./visibleColumnBreakpoints";
+export { visibleColumnBreakpoints } 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,10 +1,49 @@
 // 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,16 +31,28 @@ 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,55 +2,64 @@
  * 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 } from "../reducers/breakpoints";
+import {
+  getBreakpointsList,
+  getBreakpointPositionsForLine
+} from "../reducers/breakpoints";
 import { getSelectedSource } from "../reducers/sources";
 
-import { sortSelectedBreakpoints } from "../utils/breakpoint";
+import { sortBreakpoints } from "../utils/breakpoint";
 import { getSelectedLocation } from "../utils/source-maps";
 
-import type { Breakpoint, Source } from "../types";
-import type { Selector } from "../reducers/types";
+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;
+}
 
 /*
  * Finds the breakpoints, which appear in the selected source.
  */
 export const getVisibleBreakpoints: Selector<?(Breakpoint[])> = createSelector(
   getSelectedSource,
   getBreakpointsList,
   (selectedSource: ?Source, breakpoints: Breakpoint[]) => {
-    if (!selectedSource) {
+    if (selectedSource == null) {
       return null;
     }
 
-    return breakpoints.filter(
-      bp =>
-        selectedSource &&
-        getSelectedLocation(bp, selectedSource).sourceId === selectedSource.id
-    );
+    // FIXME: Even though selectedSource is checked above, it fails type
+    // checking for isVisible
+    const source: Source = selectedSource;
+    return breakpoints.filter(bp => isVisible(bp, source));
   }
 );
 
+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,
-  getSelectedSource,
-  (breakpoints, selectedSource) => {
-    if (!breakpoints || !selectedSource) {
-      return [];
-    }
+> = createSelector(getVisibleBreakpoints, breakpoints => {
+  if (!breakpoints) {
+    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,35 +1,31 @@
 // @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 } from "lodash";
+import { groupBy, sortedUniqBy } from "lodash";
 import { createSelector } from "reselect";
 
 import {
   getViewport,
-  getSource,
   getSelectedSource,
-  getBreakpointPositions,
-  getBreakpointPositionsForSource
+  getBreakpointPositions
 } from "../selectors";
 import { getVisibleBreakpoints } from "./visibleBreakpoints";
-import { getSelectedLocation } from "../utils/source-maps";
-import type { Selector, State } from "../reducers/types";
+import { makeBreakpointId } from "../utils/breakpoint";
+import type { Selector } from "../reducers/types";
 
 import type {
   SourceLocation,
   PartialPosition,
   Breakpoint,
   Range,
-  BreakpointPositions,
-  BreakpointPosition,
-  Source
+  BreakpointPositions
 } from "../types";
 
 export type ColumnBreakpoint = {|
   +location: SourceLocation,
   +breakpoint: ?Breakpoint
 |};
 
 export type ColumnBreakpoints = Array<ColumnBreakpoint>;
@@ -43,112 +39,101 @@ function contains(location: PartialPosit
         location.column <= range.end.column))
   );
 }
 
 function inViewport(viewport, location) {
   return viewport && contains(location, viewport);
 }
 
-function groupBreakpoints(breakpoints, selectedSource) {
+function groupBreakpoints(breakpoints) {
   if (!breakpoints) {
     return {};
   }
-  const map: any = groupBy(
-    breakpoints,
-    breakpoint => getSelectedLocation(breakpoint, selectedSource).line
-  );
-
+  const map: any = groupBy(breakpoints, ({ location }) => location.line);
   for (const line in map) {
-    map[line] = groupBy(
-      map[line],
-      breakpoint => getSelectedLocation(breakpoint, selectedSource).column
-    );
+    map[line] = groupBy(map[line], ({ location }) => location.column);
   }
 
   return map;
 }
 
 function findBreakpoint(location, breakpointMap) {
   const { line, column } = location;
   const breakpoints = breakpointMap[line] && breakpointMap[line][column];
 
   if (breakpoints) {
     return breakpoints[0];
   }
 }
 
-function filterByLineCount(positions, selectedSource) {
+function getLineCount(columnBreakpoints) {
   const lineCount = {};
-
-  for (const breakpoint of positions) {
-    const { line } = getSelectedLocation(breakpoint, selectedSource);
+  columnBreakpoints.forEach(({ location: { line } }) => {
     if (!lineCount[line]) {
       lineCount[line] = 0;
     }
 
     lineCount[line] = lineCount[line] + 1;
-  }
+  });
 
-  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);
-  });
+  return lineCount;
 }
 
-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 formatColumnBreakpoints(columnBreakpoints: ColumnBreakpoints) {
+  console.log(
+    "Column Breakpoints\n\n",
+    columnBreakpoints
+      .map(
+        ({ location, breakpoint }) =>
+          `(${location.line}, ${location.column || ""}) ${
+            breakpoint && breakpoint.disabled ? "disabled" : ""
+          }`
+      )
+      .join("\n")
+  );
 }
 
 export function getColumnBreakpoints(
   positions: ?BreakpointPositions,
   breakpoints: ?(Breakpoint[]),
-  viewport: Range,
-  selectedSource: ?Source
+  viewport: Range
 ) {
   if (!positions) {
     return [];
   }
 
+  const breakpointMap = groupBreakpoints(breakpoints);
+
   // We only want to show a column breakpoint if several conditions are matched
-  // - 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);
+  // 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)
+  );
 
-  positions = filterByLineCount(positions, selectedSource);
-  positions = filterVisible(positions, selectedSource, viewport);
-  positions = filterByBreakpoints(positions, selectedSource, breakpointMap);
+  // 4. Only show one column breakpoint per generated location
+  columnBreakpoints = sortedUniqBy(columnBreakpoints, ({ generatedLocation }) =>
+    makeBreakpointId(generatedLocation)
+  );
 
-  return formatPositions(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)
+  }));
 }
 
 const getVisibleBreakpointPositions = createSelector(
   getSelectedSource,
   getBreakpointPositions,
   (source, positions) => source && positions[source.id]
 );
 
@@ -156,40 +141,8 @@ 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 findFunctionByName(
+export async function findScopeByName(
   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);
deleted file mode 100644
--- a/devtools/client/debugger/new/src/utils/breakpoint/breakpointPositions.js
+++ /dev/null
@@ -1,23 +0,0 @@
-// @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,44 +8,51 @@ 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 * from "./astBreakpointLocation";
-export * from "./breakpointPositions";
+export { getASTLocation, findScopeByName } from "./astBreakpointLocation";
 
 import type {
   Source,
   SourceActor,
   SourceLocation,
   SourceActorLocation,
   PendingLocation,
   Breakpoint,
   BreakpointLocation,
-  PendingBreakpoint,
-  MappedLocation
+  PendingBreakpoint
 } 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) {
@@ -152,37 +159,45 @@ export function breakpointAtLocation(
 }
 
 export function breakpointExists(state: State, location: SourceLocation) {
   const currentBp = getBreakpoint(state, location);
   return currentBp && !currentBp.disabled;
 }
 
 export function createBreakpoint(
-  mappedLocation: MappedLocation,
+  location: SourceLocation,
   overrides: Object = {}
 ): Breakpoint {
-  const { disabled, astLocation, text, originalText, options } = overrides;
+  const {
+    disabled,
+    generatedLocation,
+    astLocation,
+    text,
+    originalText,
+    options
+  } = overrides;
 
   const defaultASTLocation = {
     name: undefined,
-    offset: mappedLocation.location,
+    offset: location,
     index: 0
   };
   const properties = {
-    id: makeBreakpointId(mappedLocation.location),
-    ...mappedLocation,
+    id: makeBreakpointId(location),
     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,11 +4,10 @@
 # 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,27 +1,23 @@
 /* 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 { PartialPosition, SourceLocation, SourceId } from "../types";
+import type { 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,77 +36,44 @@ 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,24 +40,16 @@ 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,17 +17,16 @@ 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 = ""
@@ -149,24 +148,16 @@ 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,32 +5,29 @@
 
 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);
 
-  info('Create an eval script that pauses itself.')
+  // 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,17 +8,16 @@ 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,12 +1,22 @@
 /* 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,
@@ -101,17 +111,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", true);
+  await pushPref("devtools.debugger.features.column-breakpoints", false);
   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);
 
-  info("resume");
+  // resume
   await clickResume(dbg);
   await waitForPaused(dbg);
   assertPausedLocation(dbg);
 
-  info("step over");
+  // step over
   await clickStepOver(dbg);
   assertPausedLocation(dbg);
 
-  info("step into");
+  // step into
   await clickStepIn(dbg);
   assertPausedLocation(dbg);
 
-  info("step over");
+  // step over
   await clickStepOver(dbg);
   assertPausedLocation(dbg);
 
-  info("step out");
+  // 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,9 +48,17 @@ 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,17 +38,16 @@ 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,17 +24,16 @@ 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,17 +17,16 @@ 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,12 +1,11 @@
 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, column: 2 };
+  const location = { sourceId: source.id, line: 6 };
 
   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: 16 }, [
+  await evalInConsoleAtPoint(dbg, "webpack3-babel6", "babel-classes", { line: 8, column: 6 }, [
     `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 = col => col;
+  const maybeLineStart = hasBabel ? col => col : col => 0;
   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: 4 }, [
+    await breakpointScopes(dbg, target, "eval-maps", { line: 14, column: 0 }, [
       "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,40 +21,34 @@ 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);
 
-  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,37 +25,47 @@ 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, 2);
-  is(getBreakpointCount(getState()), 2, "Three breakpoints exist");
+  await waitForBreakpointCount(dbg, 3);
+  is(getBreakpointCount(getState()), 3, "Three breakpoints exist");
 
   ok(
-    getBreakpoint(getState(), { sourceId: entrySrc.id, line: 15, column: 0 }),
+    getBreakpoint(getState(), { sourceId: entrySrc.id, line: 13 }),
     "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,39 +12,34 @@ function assertBreakpointExists(dbg, sou
   } = dbg;
 
   ok(
     getBreakpoint(getState(), { sourceId: source.id, line }),
     "Breakpoint has correct line"
   );
 }
 
-async function assertEditorBreakpoint(dbg, line, shouldExist) {
-  const el = await getLineEl(dbg, line);
-  const exists = !!el.querySelector(".new-breakpoint");
+function assertEditorBreakpoint(dbg, line, shouldExist) {
+  const exists = !!getLineEl(dbg, line).querySelector(".new-breakpoint");
   ok(
     exists === shouldExist,
     "Breakpoint " +
       (shouldExist ? "exists" : "does not exist") +
       " on line " +
       line
   );
 }
 
-async function getLineEl(dbg, line) {
-  let el = await codeMirrorGutterElement(dbg, line);
-  while (el && !el.matches(".CodeMirror-code > div")) {
-    el = el.parentElement;
-  }
-  return el;
+function getLineEl(dbg, line) {
+  const lines = dbg.win.document.querySelectorAll(".CodeMirror-code > div");
+  return lines[line - 1];
 }
 
-async function clickGutter(dbg, line) {
-  const el = await codeMirrorGutterElement(dbg, line);
-  clickDOMElement(dbg, el);
+function clickGutter(dbg, line) {
+  clickElement(dbg, "gutter", line);
 }
 
 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
@@ -54,21 +49,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, 70);
+  await clickGutter(dbg, 13);
   await waitForDispatch(dbg, "ADD_BREAKPOINT");
-  assertEditorBreakpoint(dbg, 70, true);
+  assertEditorBreakpoint(dbg, 13, true);
 
-  await clickGutter(dbg, 70);
+  await clickGutter(dbg, 13);
   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,28 +9,27 @@ 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, 12);
+  await removeBreakpoint(dbg, workerSource.id, 1);
   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, 2);
+  await removeBreakpoint(dbg, workerSource.id, 10);
 });
--- 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,17 +85,16 @@ 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,12 +14,11 @@
     <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/helpers.js
+++ b/devtools/client/debugger/new/test/mochitest/helpers.js
@@ -12,18 +12,16 @@ 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)}`);
 }
 
@@ -216,44 +214,41 @@ 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 = getSelectedSource(state);
+      const source = dbg.selectors.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;
       }
 
-      return hasSymbols(state, source) &&
-        hasSourceMetaData( state, source.id) &&
-        hasBreakpointPositions(state, source.id);
+      // 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;
     },
     "selected source"
   );
 }
 
 /**
  * Assert that the debugger is not currently paused.
  * @memberof mochitest/asserts
@@ -731,60 +726,59 @@ 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
  */
-async function addBreakpoint(dbg, source, line, column) {
+function addBreakpoint(dbg, source, line, column) {
   source = findSource(dbg, source);
   const sourceId = source.id;
-  column = column || getFirstBreakpointColumn(dbg, {line, sourceId: source.id});
-  const bpCount = dbg.selectors.getBreakpointCount(dbg.getState());
-  Cu.forceGC();
   dbg.actions.addBreakpoint({ sourceId, line, column });
-  await waitForDispatch(dbg, "ADD_BREAKPOINT");
-  is(dbg.selectors.getBreakpointCount(dbg.getState()), bpCount + 1, "a new breakpoint was created");
+  return waitForDispatch(dbg, "ADD_BREAKPOINT");
 }
 
 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");
 }
 
 function findBreakpoint(dbg, url, line) {
   const {
-    selectors: { getBreakpoint, getBreakpointsList },
+    selectors: { getBreakpoint },
     getState
   } = dbg;
   const source = findSource(dbg, url);
-  const column = getFirstBreakpointColumn(dbg, {line, sourceId: source.id });
+  let column;
+  if (
+    Services.prefs.getBoolPref("devtools.debugger.features.column-breakpoints")
+  ) {
+    ({ column } = dbg.selectors.getFirstVisibleBreakpointPosition(
+      dbg.store.getState(),
+      {
+        sourceId: source.id,
+        line
+      }
+    ));
+  }
   return getBreakpoint(getState(), { sourceId: source.id, line, column });
 }
 
 async function loadAndAddBreakpoint(dbg, filename, line, column) {
   const {
     selectors: { getBreakpoint, getBreakpointCount, getBreakpointsMap },
     getState
   } = dbg;
@@ -895,17 +889,16 @@ 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,25 +1215,18 @@ 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(
-    element,
+    findElementWithSelector(dbg, selector),
     {},
     dbg.win
   );
 }
 
 function dblClickElement(dbg, elementName, ...args) {
   const selector = getSelector(elementName, ...args);
 
@@ -1327,43 +1313,16 @@ 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, selectSource */
+          findSource, removeBreakpoint, resume */
 
 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,17 +29,16 @@ 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,39 +7244,28 @@ 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();
   }
 
-  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) || [];
+  const cachedGeneratedMappingsForOriginal = GENERATED_MAPPINGS.get(map);
+  if (cachedGeneratedMappingsForOriginal) {
+    return cachedGeneratedMappingsForOriginal;
   }
 
   // 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) {
@@ -7328,17 +7317,17 @@ async function getGeneratedRangesForOrig
           const newEntry = { start, end };
           generatedMappingsForOriginal.push(newEntry);
           lastEntry = newEntry;
         }
       }
     }
   }
 
-  generatedRangesMap.set(sourceId, generatedMappingsForOriginal);
+  GENERATED_MAPPINGS.set(map, 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,17 +15,16 @@ 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,20 +234,18 @@ 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`);