diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
commit | 2aa4a82499d4becd2284cdb482213d541b8804dd (patch) | |
tree | b80bf8bf13c3766139fbacc530efd0dd9d54394c /devtools/client/debugger/src/actions/pause/mapFrames.js | |
parent | Initial commit. (diff) | |
download | firefox-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.js | 177 |
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, + }); + }; +} |