tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

pause.js (10436B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
      4 
      5 import { getThreadPauseState } from "../reducers/pause";
      6 import { getSelectedSource, getSelectedLocation } from "./sources";
      7 import { getBlackBoxRanges } from "./source-blackbox";
      8 import { getSelectedTraceSource } from "./tracer";
      9 
     10 // eslint-disable-next-line
     11 import { getSelectedLocation as _getSelectedLocation } from "../utils/selected-location";
     12 import { isFrameBlackBoxed } from "../utils/source";
     13 import { createSelector } from "devtools/client/shared/vendor/reselect";
     14 
     15 export const getSelectedFrame = createSelector(
     16  (state, thread) => state.pause.threads[thread || getCurrentThread(state)],
     17  threadPauseState => {
     18    if (!threadPauseState) {
     19      return null;
     20    }
     21    const { selectedFrameId, frames } = threadPauseState;
     22    if (frames) {
     23      return frames.find(frame => frame.id == selectedFrameId);
     24    }
     25    return null;
     26  }
     27 );
     28 
     29 export const getVisibleSelectedFrame = createSelector(
     30  getSelectedLocation,
     31  state => getSelectedFrame(state, getCurrentThread(state)),
     32  (selectedLocation, selectedFrame) => {
     33    if (!selectedFrame) {
     34      return null;
     35    }
     36 
     37    const { id, displayName } = selectedFrame;
     38 
     39    return {
     40      id,
     41      displayName,
     42      location: _getSelectedLocation(selectedFrame, selectedLocation),
     43    };
     44  }
     45 );
     46 
     47 export function getContext(state) {
     48  return state.pause.cx;
     49 }
     50 
     51 export function getThreadContext(state) {
     52  return state.pause.threadcx;
     53 }
     54 
     55 export function getNavigateCounter(state) {
     56  return state.pause.threadcx.navigateCounter;
     57 }
     58 
     59 export function getPauseReason(state, thread) {
     60  return getThreadPauseState(state.pause, thread).why;
     61 }
     62 
     63 export function getShouldBreakpointsPaneOpenOnPause(state, thread) {
     64  return getThreadPauseState(state.pause, thread)
     65    .shouldBreakpointsPaneOpenOnPause;
     66 }
     67 
     68 export function getPauseCommand(state, thread) {
     69  return getThreadPauseState(state.pause, thread).command;
     70 }
     71 
     72 export function isStepping(state, thread) {
     73  return ["stepIn", "stepOver", "stepOut"].includes(
     74    getPauseCommand(state, thread)
     75  );
     76 }
     77 
     78 export function getCurrentThread(state) {
     79  return getThreadContext(state).thread;
     80 }
     81 
     82 export function getIsPaused(state, thread) {
     83  return getThreadPauseState(state.pause, thread).isPaused;
     84 }
     85 
     86 export function getIsCurrentThreadPaused(state) {
     87  return getIsPaused(state, getCurrentThread(state));
     88 }
     89 
     90 export function isEvaluatingExpression(state, thread) {
     91  return getThreadPauseState(state.pause, thread).command === "expression";
     92 }
     93 
     94 export function getIsWaitingOnBreak(state, thread) {
     95  return getThreadPauseState(state.pause, thread).isWaitingOnBreak;
     96 }
     97 
     98 export function getShouldPauseOnDebuggerStatement(state) {
     99  return state.pause.shouldPauseOnDebuggerStatement;
    100 }
    101 
    102 export function getShouldPauseOnExceptions(state) {
    103  return state.pause.shouldPauseOnExceptions;
    104 }
    105 
    106 export function getShouldPauseOnCaughtExceptions(state) {
    107  return state.pause.shouldPauseOnCaughtExceptions;
    108 }
    109 
    110 export function getFrames(state, thread) {
    111  const { frames, framesLoading } = getThreadPauseState(state.pause, thread);
    112  return framesLoading ? null : frames;
    113 }
    114 
    115 export const getCurrentThreadFrames = createSelector(
    116  state => {
    117    const { frames, framesLoading } = getThreadPauseState(
    118      state.pause,
    119      getCurrentThread(state)
    120    );
    121    if (framesLoading) {
    122      return [];
    123    }
    124    return frames;
    125  },
    126  getBlackBoxRanges,
    127  (frames, blackboxedRanges) => {
    128    return frames.filter(frame => !isFrameBlackBoxed(frame, blackboxedRanges));
    129  }
    130 );
    131 
    132 function getGeneratedFrameId(frameId) {
    133  if (frameId.includes("-originalFrame")) {
    134    // The mapFrames can add original stack frames -- get generated frameId.
    135    return frameId.substr(0, frameId.lastIndexOf("-originalFrame"));
    136  }
    137  return frameId;
    138 }
    139 // This is Environment Scope information from the platform.
    140 // See https://searchfox.org/mozilla-central/rev/b0e8e4ceb46cb3339cdcb90310fcc161ef4b9e3e/devtools/server/actors/environment.js#42-81
    141 export function getGeneratedFrameScope(state, frame) {
    142  if (!frame) {
    143    return null;
    144  }
    145  return getFrameScopes(state, frame.thread).generated[
    146    getGeneratedFrameId(frame.id)
    147  ];
    148 }
    149 
    150 export function getOriginalFrameScope(state, frame) {
    151  if (!frame) {
    152    return null;
    153  }
    154  // Only compute original scope if we are currently showing an original source.
    155  const source = getSelectedSource(state);
    156  if (!source || !source.isOriginal) {
    157    return null;
    158  }
    159 
    160  const original = getFrameScopes(state, frame.thread).original[
    161    getGeneratedFrameId(frame.id)
    162  ];
    163 
    164  if (original && (original.pending || original.scope)) {
    165    return original;
    166  }
    167 
    168  return null;
    169 }
    170 
    171 // This is only used by tests
    172 export function getFrameScopes(state, thread) {
    173  return getThreadPauseState(state.pause, thread).frameScopes;
    174 }
    175 
    176 export function getSelectedFrameBindings(state, thread) {
    177  const scopes = getFrameScopes(state, thread);
    178  const selectedFrameId = getSelectedFrameId(state, thread);
    179  if (!scopes || !selectedFrameId) {
    180    return null;
    181  }
    182 
    183  const frameScope = scopes.generated[selectedFrameId];
    184  if (!frameScope || frameScope.pending) {
    185    return null;
    186  }
    187 
    188  let currentScope = frameScope.scope;
    189  let frameBindings = [];
    190  while (currentScope && currentScope.type != "object") {
    191    if (currentScope.bindings) {
    192      const bindings = Object.keys(currentScope.bindings.variables);
    193      const args = [].concat(
    194        ...currentScope.bindings.arguments.map(argument =>
    195          Object.keys(argument)
    196        )
    197      );
    198 
    199      frameBindings = [...frameBindings, ...bindings, ...args];
    200    }
    201    currentScope = currentScope.parent;
    202  }
    203 
    204  return frameBindings;
    205 }
    206 
    207 export function getSelectedScope(state) {
    208  const frame = getSelectedFrame(state);
    209  if (!frame) {
    210    return null;
    211  }
    212 
    213  let scopes;
    214  // For non-pretty printed original sources
    215  if (
    216    frame.location.source.isOriginal &&
    217    !frame.location.source.isPrettyPrinted &&
    218    !frame.generatedLocation?.source.isWasm
    219  ) {
    220    scopes = getOriginalFrameScope(state, frame)?.scope;
    221    // Fallback to the generated scopes if there are no original scopes
    222    if (!scopes) {
    223      scopes = getGeneratedFrameScope(state, frame)?.scope;
    224    }
    225  } else {
    226    // For generated sources
    227    // For pretty printed sources - Even though are seen as original sources they do not include any rename of variables/function names.
    228    scopes = getGeneratedFrameScope(state, frame)?.scope;
    229  }
    230  return scopes;
    231 }
    232 
    233 export function getSelectedOriginalScope(state, thread) {
    234  const frame = getSelectedFrame(state, thread);
    235  return getOriginalFrameScope(state, frame);
    236 }
    237 
    238 export function getSelectedScopeMappings(state, thread) {
    239  const frameId = getSelectedFrameId(state, thread);
    240  if (!frameId) {
    241    return null;
    242  }
    243 
    244  return getFrameScopes(state, thread).mappings[frameId];
    245 }
    246 
    247 export function getSelectedFrameId(state, thread) {
    248  return getThreadPauseState(state.pause, thread).selectedFrameId;
    249 }
    250 
    251 export function isTopFrameSelected(state, thread) {
    252  const selectedFrameId = getSelectedFrameId(state, thread);
    253  // Consider that the top frame is selected when none is specified,
    254  // which happens when a JS Tracer frame is selected.
    255  if (!selectedFrameId) {
    256    return true;
    257  }
    258  const topFrame = getTopFrame(state, thread);
    259  return selectedFrameId == topFrame?.id;
    260 }
    261 
    262 export function getTopFrame(state, thread) {
    263  const frames = getFrames(state, thread);
    264  return frames?.[0];
    265 }
    266 
    267 // getTopFrame wouldn't return the top frame if the frames are still being fetched
    268 export function getCurrentlyFetchedTopFrame(state, thread) {
    269  const { frames } = getThreadPauseState(state.pause, thread);
    270  return frames?.[0];
    271 }
    272 
    273 export function hasFrame(state, frame) {
    274  // Don't use getFrames as it returns null when the frames are still loading
    275  const { frames } = getThreadPauseState(state.pause, frame.thread);
    276  if (!frames) {
    277    return false;
    278  }
    279  // Compare IDs and not frame objects as they get cloned during mapping
    280  return frames.some(f => f.id == frame.id);
    281 }
    282 
    283 export function getSkipPausing(state) {
    284  return state.pause.skipPausing;
    285 }
    286 
    287 export function isMapScopesEnabled(state) {
    288  return state.pause.mapScopes;
    289 }
    290 
    291 /**
    292 * This selector only returns inline previews object for current paused location.
    293 * (it ignores the JS Tracer and ignore the selected location, which may different from paused location)
    294 */
    295 export function getSelectedFrameInlinePreviews(state) {
    296  const thread = getCurrentThread(state);
    297  const frame = getSelectedFrame(state, thread);
    298  if (!frame) {
    299    return null;
    300  }
    301  return getThreadPauseState(state.pause, thread).inlinePreview[
    302    getGeneratedFrameId(frame.id)
    303  ];
    304 }
    305 
    306 /**
    307 * This selector returns the inline previews object for the selected location.
    308 * It considers both paused and traced previews and will only return values
    309 * if it matches the currently selected location.
    310 */
    311 export function getInlinePreviews(state) {
    312  const selectedSource = getSelectedSource(state);
    313  if (!selectedSource) {
    314    return null;
    315  }
    316 
    317  // We first check if a frame in the JS Tracer was selected and generated its previews
    318  if (state.tracerFrames?.previews) {
    319    const selectedTraceSource = getSelectedTraceSource(state);
    320    if (selectedTraceSource) {
    321      if (selectedTraceSource.id == selectedSource.id) {
    322        return state.tracerFrames?.previews;
    323      }
    324 
    325      // If the "selected" versus "tracing selected" sources don't match, it means that we selected the original source
    326      // while the traced source is the generated one. We don't yet support showing inline previews in this configuration.
    327      return null;
    328    }
    329  }
    330 
    331  // Otherwise, we fallback to look if we were paused and the inline preview is available
    332  const thread = getCurrentThread(state);
    333  const frame = getSelectedFrame(state, thread);
    334  // When we are paused, we also check if the selected source matches the paused original or generated location.
    335  if (
    336    !frame ||
    337    (frame.location.source.id != selectedSource.id &&
    338      frame.generatedLocation.source.id != selectedSource.id)
    339  ) {
    340    return null;
    341  }
    342  return getThreadPauseState(state.pause, thread).inlinePreview[
    343    getGeneratedFrameId(frame.id)
    344  ];
    345 }
    346 
    347 export function getLastExpandedScopes(state, thread) {
    348  return getThreadPauseState(state.pause, thread).lastExpandedScopes;
    349 }