tor-browser

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

environment.js (5636B)


      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 "use strict";
      5 
      6 const { Actor } = require("resource://devtools/shared/protocol.js");
      7 const {
      8  environmentSpec,
      9 } = require("resource://devtools/shared/specs/environment.js");
     10 
     11 /**
     12 * Creates an EnvironmentActor. EnvironmentActors are responsible for listing
     13 * the bindings introduced by a lexical environment and assigning new values to
     14 * those identifier bindings.
     15 *
     16 * @param Debugger.Environment aEnvironment
     17 *        The lexical environment that will be used to create the actor.
     18 * @param ThreadActor aThreadActor
     19 *        The parent thread actor that contains this environment.
     20 */
     21 class EnvironmentActor extends Actor {
     22  constructor(environment, threadActor) {
     23    super(threadActor.conn, environmentSpec);
     24 
     25    this.obj = environment;
     26    this.threadActor = threadActor;
     27  }
     28 
     29  /**
     30   * When the Environment Actor is destroyed it removes the
     31   * Debugger.Environment.actor field so that environment does not
     32   * reference a destroyed actor.
     33   */
     34  destroy() {
     35    this.obj.actor = null;
     36    super.destroy();
     37  }
     38 
     39  /**
     40   * Return an environment form for use in a protocol message.
     41   */
     42  form() {
     43    const form = { actor: this.actorID };
     44 
     45    // What is this environment's type?
     46    if (this.obj.type == "declarative") {
     47      form.type = this.obj.calleeScript ? "function" : "block";
     48    } else {
     49      form.type = this.obj.type;
     50    }
     51 
     52    form.scopeKind = this.obj.scopeKind;
     53 
     54    // Does this environment have a parent?
     55    if (this.obj.parent) {
     56      form.parent = this.threadActor
     57        .createEnvironmentActor(this.obj.parent, this.threadActor)
     58        .form();
     59    }
     60 
     61    // Does this environment reflect the properties of an object as variables?
     62    if (this.obj.type == "object" || this.obj.type == "with") {
     63      form.object = this.threadActor.createValueGrip(this.obj.object);
     64    }
     65 
     66    // Is this the environment created for a function call?
     67    if (this.obj.calleeScript) {
     68      // Client only uses "displayName" for "function".
     69      // Create a fake object actor containing only "displayName" as replacement
     70      // for the no longer available obj.callee (see bug 1663847).
     71      // See bug 1664218 for cleanup.
     72      form.function = { displayName: this.obj.calleeScript.displayName };
     73    }
     74 
     75    // Shall we list this environment's bindings?
     76    if (this.obj.type == "declarative") {
     77      form.bindings = this.bindings();
     78    }
     79 
     80    return form;
     81  }
     82 
     83  /**
     84   * Handle a protocol request to fully enumerate the bindings introduced by the
     85   * lexical environment.
     86   */
     87  bindings() {
     88    const bindings = { arguments: [], variables: Object.create(null) };
     89 
     90    // TODO: this part should be removed in favor of the commented-out part
     91    // below when getVariableDescriptor lands (bug 725815).
     92    if (typeof this.obj.getVariable != "function") {
     93      // if (typeof this.obj.getVariableDescriptor != "function") {
     94      return bindings;
     95    }
     96 
     97    let parameterNames;
     98    if (this.obj.calleeScript) {
     99      parameterNames = this.obj.calleeScript.parameterNames;
    100    } else {
    101      parameterNames = [];
    102    }
    103    for (const name of parameterNames) {
    104      // The names of destructuring parameters will be `undefined`.
    105      // See https://firefox-source-docs.mozilla.org/js/Debugger/Debugger.Script.html#parameternames
    106      if (name == undefined) {
    107        continue;
    108      }
    109      const arg = Object.create(null);
    110      const value = this.obj.getVariable(name);
    111 
    112      // TODO: this part should be removed in favor of the commented-out part
    113      // below when getVariableDescriptor lands (bug 725815).
    114      const desc = {
    115        value,
    116        configurable: false,
    117        writable: !value?.optimizedOut,
    118        enumerable: true,
    119      };
    120 
    121      // let desc = this.obj.getVariableDescriptor(name);
    122      const descForm = {
    123        enumerable: true,
    124        configurable: desc.configurable,
    125      };
    126      if ("value" in desc) {
    127        descForm.value = this.threadActor.createValueGrip(desc.value);
    128        descForm.writable = desc.writable;
    129      } else {
    130        descForm.get = this.threadActor.createValueGrip(desc.get);
    131        descForm.set = this.threadActor.createValueGrip(desc.set);
    132      }
    133      arg[name] = descForm;
    134      bindings.arguments.push(arg);
    135    }
    136 
    137    for (const name of this.obj.names()) {
    138      if (
    139        bindings.arguments.some(function exists(element) {
    140          return !!element[name];
    141        })
    142      ) {
    143        continue;
    144      }
    145 
    146      const value = this.obj.getVariable(name);
    147 
    148      // TODO: this part should be removed in favor of the commented-out part
    149      // below when getVariableDescriptor lands.
    150      const desc = {
    151        value,
    152        configurable: false,
    153        writable: !(
    154          value &&
    155          (value.optimizedOut || value.uninitialized || value.missingArguments)
    156        ),
    157        enumerable: true,
    158      };
    159 
    160      // let desc = this.obj.getVariableDescriptor(name);
    161      const descForm = {
    162        enumerable: true,
    163        configurable: desc.configurable,
    164      };
    165      if ("value" in desc) {
    166        descForm.value = this.threadActor.createValueGrip(desc.value);
    167        descForm.writable = desc.writable;
    168      } else {
    169        descForm.get = this.threadActor.createValueGrip(desc.get || undefined);
    170        descForm.set = this.threadActor.createValueGrip(desc.set || undefined);
    171      }
    172      bindings.variables[name] = descForm;
    173    }
    174 
    175    return bindings;
    176  }
    177 }
    178 
    179 exports.EnvironmentActor = EnvironmentActor;