summaryrefslogtreecommitdiffstats
path: root/devtools/client/debugger/src/actions/pause/mapScopes.js
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/client/debugger/src/actions/pause/mapScopes.js')
-rw-r--r--devtools/client/debugger/src/actions/pause/mapScopes.js194
1 files changed, 194 insertions, 0 deletions
diff --git a/devtools/client/debugger/src/actions/pause/mapScopes.js b/devtools/client/debugger/src/actions/pause/mapScopes.js
new file mode 100644
index 0000000000..2a352dc578
--- /dev/null
+++ b/devtools/client/debugger/src/actions/pause/mapScopes.js
@@ -0,0 +1,194 @@
+/* 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 {
+ getSelectedFrameId,
+ getSettledSourceTextContent,
+ isMapScopesEnabled,
+ getSelectedFrame,
+ getSelectedGeneratedScope,
+ getSelectedOriginalScope,
+ getThreadContext,
+ getFirstSourceActorForGeneratedSource,
+} from "../../selectors";
+import {
+ loadOriginalSourceText,
+ loadGeneratedSourceText,
+} from "../sources/loadSourceText";
+import { PROMISE } from "../utils/middleware/promise";
+import assert from "../../utils/assert";
+
+import { log } from "../../utils/log";
+import { isGenerated } from "../../utils/source";
+
+import { buildMappedScopes } from "../../utils/pause/mapScopes";
+import { isFulfilled } from "../../utils/async-value";
+
+import { getMappedLocation } from "../../utils/source-maps";
+
+const expressionRegex = /\bfp\(\)/g;
+
+export async function buildOriginalScopes(
+ frame,
+ client,
+ cx,
+ frameId,
+ generatedScopes
+) {
+ if (!frame.originalVariables) {
+ throw new TypeError("(frame.originalVariables: XScopeVariables)");
+ }
+ const originalVariables = frame.originalVariables;
+ const frameBase = originalVariables.frameBase || "";
+
+ const inputs = [];
+ for (let i = 0; i < originalVariables.vars.length; i++) {
+ const { expr } = originalVariables.vars[i];
+ const expression = expr
+ ? expr.replace(expressionRegex, frameBase)
+ : "void 0";
+
+ inputs[i] = expression;
+ }
+
+ const results = await client.evaluateExpressions(inputs, {
+ frameId,
+ });
+
+ const variables = {};
+ for (let i = 0; i < originalVariables.vars.length; i++) {
+ const { name } = originalVariables.vars[i];
+ variables[name] = { value: results[i].result };
+ }
+
+ const bindings = {
+ arguments: [],
+ variables,
+ };
+
+ const { actor } = await generatedScopes;
+ const scope = {
+ type: "function",
+ scopeKind: "",
+ actor,
+ bindings,
+ parent: null,
+ function: null,
+ block: null,
+ };
+ return {
+ mappings: {},
+ scope,
+ };
+}
+
+export function toggleMapScopes() {
+ return async function ({ dispatch, getState }) {
+ if (isMapScopesEnabled(getState())) {
+ dispatch({ type: "TOGGLE_MAP_SCOPES", mapScopes: false });
+ return;
+ }
+
+ dispatch({ type: "TOGGLE_MAP_SCOPES", mapScopes: true });
+
+ const cx = getThreadContext(getState());
+
+ if (getSelectedOriginalScope(getState(), cx.thread)) {
+ return;
+ }
+
+ const scopes = getSelectedGeneratedScope(getState(), cx.thread);
+ const frame = getSelectedFrame(getState(), cx.thread);
+ if (!scopes || !frame) {
+ return;
+ }
+
+ dispatch(mapScopes(cx, Promise.resolve(scopes.scope), frame));
+ };
+}
+
+export function mapScopes(cx, scopes, frame) {
+ return async function (thunkArgs) {
+ const { dispatch, client, getState } = thunkArgs;
+ assert(cx.thread == frame.thread, "Thread mismatch");
+
+ await dispatch({
+ type: "MAP_SCOPES",
+ cx,
+ thread: cx.thread,
+ frame,
+ [PROMISE]: (async function () {
+ if (frame.isOriginal && frame.originalVariables) {
+ const frameId = getSelectedFrameId(getState(), cx.thread);
+ return buildOriginalScopes(frame, client, cx, frameId, scopes);
+ }
+
+ return dispatch(getMappedScopes(cx, scopes, frame));
+ })(),
+ });
+ };
+}
+
+export function getMappedScopes(cx, scopes, frame) {
+ return async function (thunkArgs) {
+ const { getState, dispatch } = thunkArgs;
+ const generatedSource = frame.generatedLocation.source;
+
+ const source = frame.location.source;
+
+ if (
+ !isMapScopesEnabled(getState()) ||
+ !source ||
+ !generatedSource ||
+ generatedSource.isWasm ||
+ source.isPrettyPrinted ||
+ isGenerated(source)
+ ) {
+ return null;
+ }
+
+ // Load source text for the original source
+ await dispatch(loadOriginalSourceText({ cx, source }));
+
+ const generatedSourceActor = getFirstSourceActorForGeneratedSource(
+ getState(),
+ generatedSource.id
+ );
+
+ // Also load source text for its corresponding generated source
+ await dispatch(
+ loadGeneratedSourceText({
+ cx,
+ sourceActor: generatedSourceActor,
+ })
+ );
+
+ try {
+ // load original source text content
+ const content = getSettledSourceTextContent(getState(), frame.location);
+
+ return await buildMappedScopes(
+ source,
+ content && isFulfilled(content)
+ ? content.value
+ : { type: "text", value: "", contentType: undefined },
+ frame,
+ await scopes,
+ thunkArgs
+ );
+ } catch (e) {
+ log(e);
+ return null;
+ }
+ };
+}
+
+export function getMappedScopesForLocation(location) {
+ return async function (thunkArgs) {
+ const { dispatch, getState } = thunkArgs;
+ const cx = getThreadContext(getState());
+ const mappedLocation = await getMappedLocation(location, thunkArgs);
+ return dispatch(getMappedScopes(cx, null, mappedLocation));
+ };
+}