summaryrefslogtreecommitdiffstats
path: root/devtools/client/debugger/src/actions/pause/mapFrames.js
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
commit2aa4a82499d4becd2284cdb482213d541b8804dd (patch)
treeb80bf8bf13c3766139fbacc530efd0dd9d54394c /devtools/client/debugger/src/actions/pause/mapFrames.js
parentInitial commit. (diff)
downloadfirefox-2aa4a82499d4becd2284cdb482213d541b8804dd.tar.xz
firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.zip
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'devtools/client/debugger/src/actions/pause/mapFrames.js')
-rw-r--r--devtools/client/debugger/src/actions/pause/mapFrames.js177
1 files changed, 177 insertions, 0 deletions
diff --git a/devtools/client/debugger/src/actions/pause/mapFrames.js b/devtools/client/debugger/src/actions/pause/mapFrames.js
new file mode 100644
index 0000000000..8de3e09f3d
--- /dev/null
+++ b/devtools/client/debugger/src/actions/pause/mapFrames.js
@@ -0,0 +1,177 @@
+/* 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 { getFrames, getSource, getSelectedFrame } from "../../selectors";
+
+import assert from "../../utils/assert";
+
+import type {
+ Frame,
+ FrameId,
+ OriginalFrame,
+ ThreadContext,
+ ThreadId,
+} from "../../types";
+import type { State } from "../../reducers/types";
+import type { ThunkArgs } from "../types";
+
+import SourceMaps, { isGeneratedId } from "devtools-source-map";
+
+function isFrameBlackboxed(state: State, frame: Frame): boolean {
+ const source = getSource(state, frame.location.sourceId);
+ return !!source?.isBlackBoxed;
+}
+
+function getSelectedFrameId(
+ state: State,
+ thread: ThreadId,
+ frames: Frame[]
+): ?FrameId {
+ let selectedFrame = getSelectedFrame(state, thread);
+ if (selectedFrame && !isFrameBlackboxed(state, selectedFrame)) {
+ return selectedFrame.id;
+ }
+
+ selectedFrame = frames.find(frame => !isFrameBlackboxed(state, frame));
+ return selectedFrame?.id;
+}
+
+export function updateFrameLocation(
+ frame: Frame,
+ sourceMaps: typeof SourceMaps
+): Promise<Frame> {
+ if (frame.isOriginal) {
+ return Promise.resolve(frame);
+ }
+ return sourceMaps.getOriginalLocation(frame.location).then(loc => ({
+ ...frame,
+ location: loc,
+ generatedLocation: frame.generatedLocation || frame.location,
+ }));
+}
+
+function updateFrameLocations(
+ frames: Frame[],
+ sourceMaps: typeof SourceMaps
+): Promise<Frame[]> {
+ if (!frames || frames.length == 0) {
+ return Promise.resolve(frames);
+ }
+
+ return Promise.all(
+ frames.map(frame => updateFrameLocation(frame, sourceMaps))
+ );
+}
+
+function isWasmOriginalSourceFrame(
+ frame: Frame,
+ getState: () => State
+): boolean {
+ if (isGeneratedId(frame.location.sourceId)) {
+ return false;
+ }
+ const generatedSource = getSource(
+ getState(),
+ frame.generatedLocation.sourceId
+ );
+
+ return Boolean(generatedSource?.isWasm);
+}
+
+async function expandFrames(
+ frames: Frame[],
+ sourceMaps: typeof SourceMaps,
+ getState: () => State
+): Promise<Frame[]> {
+ const result = [];
+ for (let i = 0; i < frames.length; ++i) {
+ const frame = frames[i];
+ if (frame.isOriginal || !isWasmOriginalSourceFrame(frame, getState)) {
+ result.push(frame);
+ continue;
+ }
+ const originalFrames: ?Array<OriginalFrame> = await sourceMaps.getOriginalStackFrames(
+ frame.generatedLocation
+ );
+ if (!originalFrames) {
+ result.push(frame);
+ continue;
+ }
+
+ assert(originalFrames.length > 0, "Expected at least one original frame");
+ // First entry has not specific location -- use one from original frame.
+ originalFrames[0] = {
+ ...originalFrames[0],
+ location: frame.location,
+ };
+
+ originalFrames.forEach((originalFrame, j) => {
+ if (!originalFrame.location) {
+ return;
+ }
+
+ // Keep outer most frame with true actor ID, and generate uniquie
+ // one for the nested frames.
+ const id = j == 0 ? frame.id : `${frame.id}-originalFrame${j}`;
+ result.push({
+ id,
+ displayName: originalFrame.displayName,
+ location: originalFrame.location,
+ index: frame.index,
+ source: null,
+ thread: frame.thread,
+ scope: frame.scope,
+ this: frame.this,
+ isOriginal: true,
+ // More fields that will be added by the mapDisplayNames and
+ // updateFrameLocation.
+ generatedLocation: frame.generatedLocation,
+ originalDisplayName: originalFrame.displayName,
+ originalVariables: originalFrame.variables,
+ asyncCause: frame.asyncCause,
+ state: frame.state,
+ });
+ });
+ }
+ return result;
+}
+
+/**
+ * Map call stack frame locations and display names to originals.
+ * e.g.
+ * 1. When the debuggee pauses
+ * 2. When a source is pretty printed
+ * 3. When symbols are loaded
+ * @memberof actions/pause
+ * @static
+ */
+export function mapFrames(cx: ThreadContext) {
+ return async function(thunkArgs: ThunkArgs) {
+ const { dispatch, getState, sourceMaps } = thunkArgs;
+ const frames = getFrames(getState(), cx.thread);
+ if (!frames) {
+ return;
+ }
+
+ let mappedFrames = await updateFrameLocations(frames, sourceMaps);
+
+ mappedFrames = await expandFrames(mappedFrames, sourceMaps, getState);
+
+ const selectedFrameId = getSelectedFrameId(
+ getState(),
+ cx.thread,
+ mappedFrames
+ );
+
+ dispatch({
+ type: "MAP_FRAMES",
+ cx,
+ thread: cx.thread,
+ frames: mappedFrames,
+ selectedFrameId,
+ });
+ };
+}