tor-browser

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

NameAnalysisTypes.h (12631B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
      2 * vim: set ts=8 sts=2 et sw=2 tw=80:
      3 * This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #ifndef frontend_NameAnalysisTypes_h
      8 #define frontend_NameAnalysisTypes_h
      9 
     10 #include "mozilla/Assertions.h"  // MOZ_ASSERT, MOZ_CRASH
     11 #include "mozilla/Casting.h"     // mozilla::AssertedCast
     12 
     13 #include <stdint.h>  // uint8_t, uint16_t, uint32_t
     14 
     15 #include "vm/BindingKind.h"          // BindingKind, BindingLocation
     16 #include "vm/BytecodeFormatFlags.h"  // JOF_ENVCOORD
     17 #include "vm/BytecodeUtil.h"  // ENVCOORD_HOPS_BITS, ENVCOORD_SLOT_BITS, GET_ENVCOORD_HOPS, GET_ENVCOORD_SLOT, ENVCOORD_HOPS_LEN, JOF_OPTYPE, JSOp, LOCALNO_LIMIT
     18 
     19 namespace js {
     20 
     21 // An "environment coordinate" describes how to get from head of the
     22 // environment chain to a given lexically-enclosing variable. An environment
     23 // coordinate has two dimensions:
     24 //  - hops: the number of environment objects on the scope chain to skip
     25 //  - slot: the slot on the environment object holding the variable's value
     26 class EnvironmentCoordinate {
     27  uint32_t hops_;
     28  uint32_t slot_;
     29 
     30  // Technically, hops_/slot_ are ENVCOORD_(HOPS|SLOT)_BITS wide.  Since
     31  // EnvironmentCoordinate is a temporary value, don't bother with a bitfield as
     32  // this only adds overhead.
     33  static_assert(ENVCOORD_HOPS_BITS <= 32, "We have enough bits below");
     34  static_assert(ENVCOORD_SLOT_BITS <= 32, "We have enough bits below");
     35 
     36 public:
     37  explicit inline EnvironmentCoordinate(jsbytecode* pc)
     38      : hops_(GET_ENVCOORD_HOPS(pc)),
     39        slot_(GET_ENVCOORD_SLOT(pc + ENVCOORD_HOPS_LEN)) {
     40    MOZ_ASSERT(JOF_OPTYPE(JSOp(*pc)) == JOF_ENVCOORD ||
     41               JOF_OPTYPE(JSOp(*pc)) == JOF_DEBUGCOORD);
     42  }
     43 
     44  EnvironmentCoordinate() = default;
     45 
     46  void setHops(uint32_t hops) {
     47    MOZ_ASSERT(hops < ENVCOORD_HOPS_LIMIT);
     48    hops_ = hops;
     49  }
     50 
     51  void setSlot(uint32_t slot) {
     52    MOZ_ASSERT(slot < ENVCOORD_SLOT_LIMIT);
     53    slot_ = slot;
     54  }
     55 
     56  uint32_t hops() const {
     57    MOZ_ASSERT(hops_ < ENVCOORD_HOPS_LIMIT);
     58    return hops_;
     59  }
     60 
     61  uint32_t slot() const {
     62    MOZ_ASSERT(slot_ < ENVCOORD_SLOT_LIMIT);
     63    return slot_;
     64  }
     65 
     66  bool operator==(const EnvironmentCoordinate& rhs) const {
     67    return hops() == rhs.hops() && slot() == rhs.slot();
     68  }
     69 };
     70 
     71 namespace frontend {
     72 
     73 enum class ParseGoal : uint8_t { Script, Module };
     74 
     75 // A detailed kind used for tracking declarations in the Parser. Used for
     76 // specific early error semantics and better error messages.
     77 enum class DeclarationKind : uint8_t {
     78  PositionalFormalParameter,
     79  FormalParameter,
     80  CoverArrowParameter,
     81  Var,
     82  Let,
     83  Const,
     84 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
     85  Using,
     86  AwaitUsing,
     87 #endif
     88  Class,  // Handled as same as `let` after parsing.
     89  Import,
     90  BodyLevelFunction,
     91  ModuleBodyLevelFunction,
     92  LexicalFunction,
     93  SloppyLexicalFunction,
     94  VarForAnnexBLexicalFunction,
     95  SimpleCatchParameter,
     96  CatchParameter,
     97  PrivateName,
     98  Synthetic,
     99  PrivateMethod,  // slot to store nonstatic private method
    100 };
    101 
    102 // Class field kind.
    103 enum class FieldPlacement : uint8_t { Unspecified, Instance, Static };
    104 
    105 static inline BindingKind DeclarationKindToBindingKind(DeclarationKind kind) {
    106  switch (kind) {
    107    case DeclarationKind::PositionalFormalParameter:
    108    case DeclarationKind::FormalParameter:
    109    case DeclarationKind::CoverArrowParameter:
    110      return BindingKind::FormalParameter;
    111 
    112    case DeclarationKind::Var:
    113    case DeclarationKind::BodyLevelFunction:
    114    case DeclarationKind::ModuleBodyLevelFunction:
    115    case DeclarationKind::VarForAnnexBLexicalFunction:
    116      return BindingKind::Var;
    117 
    118    case DeclarationKind::Let:
    119    case DeclarationKind::Class:
    120    case DeclarationKind::LexicalFunction:
    121    case DeclarationKind::SloppyLexicalFunction:
    122    case DeclarationKind::SimpleCatchParameter:
    123    case DeclarationKind::CatchParameter:
    124      return BindingKind::Let;
    125 
    126    case DeclarationKind::Const:
    127      return BindingKind::Const;
    128 
    129 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
    130    case DeclarationKind::AwaitUsing:
    131    case DeclarationKind::Using:
    132      return BindingKind::Using;
    133 #endif
    134 
    135    case DeclarationKind::Import:
    136      return BindingKind::Import;
    137 
    138    case DeclarationKind::Synthetic:
    139    case DeclarationKind::PrivateName:
    140      return BindingKind::Synthetic;
    141 
    142    case DeclarationKind::PrivateMethod:
    143      return BindingKind::PrivateMethod;
    144  }
    145 
    146  MOZ_CRASH("Bad DeclarationKind");
    147 }
    148 
    149 static inline bool DeclarationKindIsLexical(DeclarationKind kind) {
    150  return BindingKindIsLexical(DeclarationKindToBindingKind(kind));
    151 }
    152 
    153 // Used in Parser and BytecodeEmitter to track the kind of a private name.
    154 enum class PrivateNameKind : uint8_t {
    155  None,
    156  Field,
    157  Method,
    158  Getter,
    159  Setter,
    160  GetterSetter,
    161 };
    162 
    163 enum class ClosedOver : bool { No = false, Yes = true };
    164 
    165 // Used in Parser to track declared names.
    166 class DeclaredNameInfo {
    167  uint32_t pos_;
    168  DeclarationKind kind_;
    169 
    170  // If the declared name is a binding, whether the binding is closed
    171  // over. Its value is meaningless if the declared name is not a binding
    172  // (i.e., a 'var' declared name in a non-var scope).
    173  bool closedOver_;
    174 
    175  PrivateNameKind privateNameKind_;
    176 
    177  // Only updated for private names (see noteDeclaredPrivateName),
    178  // tracks if declaration was instance or static to allow issuing
    179  // early errors in the case where we mismatch instance and static
    180  // private getter/setters.
    181  FieldPlacement placement_;
    182 
    183 public:
    184  explicit DeclaredNameInfo(DeclarationKind kind, uint32_t pos,
    185                            ClosedOver closedOver = ClosedOver::No)
    186      : pos_(pos),
    187        kind_(kind),
    188        closedOver_(bool(closedOver)),
    189        privateNameKind_(PrivateNameKind::None),
    190        placement_(FieldPlacement::Unspecified) {
    191 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
    192    // TODO: present we are brute forcing our way to
    193    // enforce creating an environment object whenever we encounter
    194    // a using declaration. This is temporary for prototyping
    195    // this must be optimized. (Bug 1899502)
    196    if (kind == DeclarationKind::Using || kind == DeclarationKind::AwaitUsing) {
    197      closedOver_ = true;
    198    }
    199 #endif
    200  }
    201 
    202  // Needed for InlineMap.
    203  DeclaredNameInfo() = default;
    204 
    205  DeclarationKind kind() const { return kind_; }
    206 
    207  static const uint32_t npos = uint32_t(-1);
    208 
    209  uint32_t pos() const { return pos_; }
    210 
    211  void alterKind(DeclarationKind kind) { kind_ = kind; }
    212 
    213  void setClosedOver() { closedOver_ = true; }
    214 
    215  bool closedOver() const { return closedOver_; }
    216 
    217  void setPrivateNameKind(PrivateNameKind privateNameKind) {
    218    privateNameKind_ = privateNameKind;
    219  }
    220 
    221  void setFieldPlacement(FieldPlacement placement) {
    222    MOZ_ASSERT(placement != FieldPlacement::Unspecified);
    223    placement_ = placement;
    224  }
    225 
    226  PrivateNameKind privateNameKind() const { return privateNameKind_; }
    227 
    228  FieldPlacement placement() const { return placement_; }
    229 };
    230 
    231 // Used in BytecodeEmitter to map names to locations.
    232 class NameLocation {
    233 public:
    234  enum class Kind : uint8_t {
    235    // Cannot statically determine where the name lives. Needs to walk the
    236    // environment chain to search for the name.
    237    Dynamic,
    238 
    239    // The name lives on the global or is a global lexical binding. Search
    240    // for the name on the global scope.
    241    Global,
    242 
    243    // Special mode used only when emitting self-hosted scripts. See
    244    // BytecodeEmitter::lookupName.
    245    Intrinsic,
    246 
    247    // In a named lambda, the name is the callee itself.
    248    NamedLambdaCallee,
    249 
    250    // The name is a positional formal parameter name and can be retrieved
    251    // directly from the stack using slot_.
    252    ArgumentSlot,
    253 
    254    // The name is not closed over and lives on the frame in slot_.
    255    FrameSlot,
    256 
    257    // The name is closed over and lives on an environment hops_ away in slot_.
    258    EnvironmentCoordinate,
    259 
    260    // The name is closed over and lives on an environment hops_ away in slot_,
    261    // where one or more of the environments may be a DebugEnvironmentProxy
    262    DebugEnvironmentCoordinate,
    263 
    264    // An imported name in a module.
    265    Import,
    266 
    267    // Cannot statically determine where the synthesized var for Annex
    268    // B.3.3 lives.
    269    DynamicAnnexBVar
    270  };
    271 
    272 private:
    273  // Where the name lives.
    274  Kind kind_;
    275 
    276  // If the name is not Dynamic or DynamicAnnexBVar, the kind of the
    277  // binding.
    278  BindingKind bindingKind_;
    279 
    280  // If the name is closed over and accessed via EnvironmentCoordinate, the
    281  // number of dynamic environments to skip.
    282  //
    283  // Otherwise UINT16_MAX.
    284  uint16_t hops_;
    285 
    286  // If the name lives on the frame, the slot frame.
    287  //
    288  // If the name is closed over and accessed via EnvironmentCoordinate, the
    289  // slot on the environment.
    290  //
    291  // Otherwise 0.
    292  uint32_t slot_ : ENVCOORD_SLOT_BITS;
    293 
    294  static_assert(LOCALNO_BITS == ENVCOORD_SLOT_BITS,
    295                "Frame and environment slots must be same sized.");
    296 
    297  NameLocation(Kind kind, BindingKind bindingKind, uint16_t hops = UINT16_MAX,
    298               uint32_t slot = 0)
    299      : kind_(kind), bindingKind_(bindingKind), hops_(hops), slot_(slot) {}
    300 
    301 public:
    302  // Default constructor for InlineMap.
    303  NameLocation() = default;
    304 
    305  static NameLocation Dynamic() {
    306    return NameLocation(Kind::Dynamic, BindingKind::Import);
    307  }
    308 
    309  static NameLocation Global(BindingKind bindKind) {
    310    MOZ_ASSERT(bindKind != BindingKind::FormalParameter);
    311    return NameLocation(Kind::Global, bindKind);
    312  }
    313 
    314  static NameLocation Intrinsic() {
    315    return NameLocation(Kind::Intrinsic, BindingKind::Var);
    316  }
    317 
    318  static NameLocation NamedLambdaCallee() {
    319    return NameLocation(Kind::NamedLambdaCallee,
    320                        BindingKind::NamedLambdaCallee);
    321  }
    322 
    323  static NameLocation ArgumentSlot(uint16_t slot) {
    324    return NameLocation(Kind::ArgumentSlot, BindingKind::FormalParameter, 0,
    325                        slot);
    326  }
    327 
    328  static NameLocation FrameSlot(BindingKind bindKind, uint32_t slot) {
    329    MOZ_ASSERT(slot < LOCALNO_LIMIT);
    330    return NameLocation(Kind::FrameSlot, bindKind, 0, slot);
    331  }
    332 
    333  static NameLocation EnvironmentCoordinate(BindingKind bindKind, uint16_t hops,
    334                                            uint32_t slot) {
    335    MOZ_ASSERT(slot < ENVCOORD_SLOT_LIMIT);
    336    return NameLocation(Kind::EnvironmentCoordinate, bindKind, hops, slot);
    337  }
    338  static NameLocation DebugEnvironmentCoordinate(BindingKind bindKind,
    339                                                 uint16_t hops, uint32_t slot) {
    340    MOZ_ASSERT(slot < ENVCOORD_SLOT_LIMIT);
    341    return NameLocation(Kind::DebugEnvironmentCoordinate, bindKind, hops, slot);
    342  }
    343 
    344  static NameLocation Import() {
    345    return NameLocation(Kind::Import, BindingKind::Import);
    346  }
    347 
    348  static NameLocation DynamicAnnexBVar() {
    349    return NameLocation(Kind::DynamicAnnexBVar, BindingKind::Var);
    350  }
    351 
    352  bool operator==(const NameLocation& other) const {
    353    return kind_ == other.kind_ && bindingKind_ == other.bindingKind_ &&
    354           hops_ == other.hops_ && slot_ == other.slot_;
    355  }
    356 
    357  bool operator!=(const NameLocation& other) const { return !(*this == other); }
    358 
    359  Kind kind() const { return kind_; }
    360 
    361  uint16_t argumentSlot() const {
    362    MOZ_ASSERT(kind_ == Kind::ArgumentSlot);
    363    return mozilla::AssertedCast<uint16_t>(slot_);
    364  }
    365 
    366  uint32_t frameSlot() const {
    367    MOZ_ASSERT(kind_ == Kind::FrameSlot);
    368    return slot_;
    369  }
    370 
    371  NameLocation addHops(uint16_t more) {
    372    MOZ_ASSERT(hops_ < ENVCOORD_HOPS_LIMIT - more);
    373    MOZ_ASSERT(kind_ == Kind::EnvironmentCoordinate);
    374    return NameLocation(kind_, bindingKind_, hops_ + more, slot_);
    375  }
    376 
    377  class EnvironmentCoordinate environmentCoordinate() const {
    378    MOZ_ASSERT(kind_ == Kind::EnvironmentCoordinate ||
    379               kind_ == Kind::DebugEnvironmentCoordinate);
    380    class EnvironmentCoordinate coord;
    381    coord.setHops(hops_);
    382    coord.setSlot(slot_);
    383    return coord;
    384  }
    385 
    386  BindingKind bindingKind() const {
    387    MOZ_ASSERT(kind_ != Kind::Dynamic);
    388    return bindingKind_;
    389  }
    390 
    391  bool isLexical() const { return BindingKindIsLexical(bindingKind()); }
    392 
    393  bool isConst() const {
    394    return bindingKind() == BindingKind::Const ||
    395           bindingKind() == BindingKind::Using;
    396  }
    397 
    398  bool isSynthetic() const { return bindingKind() == BindingKind::Synthetic; }
    399 
    400  bool isPrivateMethod() const {
    401    return bindingKind() == BindingKind::PrivateMethod;
    402  }
    403 
    404  bool hasKnownSlot() const {
    405    return kind_ == Kind::ArgumentSlot || kind_ == Kind::FrameSlot ||
    406           kind_ == Kind::EnvironmentCoordinate;
    407  }
    408 };
    409 
    410 }  // namespace frontend
    411 }  // namespace js
    412 
    413 #endif  // frontend_NameAnalysisTypes_h