tor-browser

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

EmitterScope.h (9536B)


      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_EmitterScope_h
      8 #define frontend_EmitterScope_h
      9 
     10 #include "mozilla/Attributes.h"
     11 #include "mozilla/Maybe.h"
     12 
     13 #include <stdint.h>
     14 
     15 #include "ds/Nestable.h"
     16 #include "frontend/AbstractScopePtr.h"
     17 #include "frontend/NameAnalysisTypes.h"
     18 #include "frontend/NameCollections.h"
     19 #include "frontend/Stencil.h"
     20 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
     21 #  include "frontend/UsingEmitter.h"
     22 #endif
     23 #include "vm/Opcodes.h"        // JSOp
     24 #include "vm/SharedStencil.h"  // GCThingIndex
     25 
     26 namespace js {
     27 namespace frontend {
     28 
     29 struct BytecodeEmitter;
     30 class EvalSharedContext;
     31 class FunctionBox;
     32 class GlobalSharedContext;
     33 class ModuleSharedContext;
     34 class TaggedParserAtomIndex;
     35 
     36 // A scope that introduces bindings.
     37 class MOZ_STACK_CLASS EmitterScope : public Nestable<EmitterScope> {
     38  // The cache of bound names that may be looked up in the
     39  // scope. Initially populated as the set of names this scope binds. As
     40  // names are looked up in enclosing scopes, they are cached on the
     41  // current scope.
     42  PooledMapPtr<NameLocationMap> nameCache_;
     43 
     44  // If this scope's cache does not include free names, such as the
     45  // global scope, the NameLocation to return.
     46  mozilla::Maybe<NameLocation> fallbackFreeNameLocation_;
     47 
     48  // True if there is a corresponding EnvironmentObject on the environment
     49  // chain, false if all bindings are stored in frame slots on the stack.
     50  bool hasEnvironment_;
     51 
     52 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
     53  mozilla::Maybe<UsingEmitter> usingEmitter_;
     54 
     55 private:
     56  BlockKind blockKind_ = BlockKind::Other;
     57 #endif
     58 
     59  // The number of enclosing environments. Used for error checking.
     60  uint16_t environmentChainLength_;
     61 
     62  // The next usable slot on the frame for not-closed over bindings.
     63  //
     64  // The initial frame slot when assigning slots to bindings is the
     65  // enclosing scope's nextFrameSlot. For the first scope in a frame,
     66  // the initial frame slot is 0.
     67  uint32_t nextFrameSlot_;
     68 
     69  // The index in the BytecodeEmitter's interned scope vector, otherwise
     70  // ScopeNote::NoScopeIndex.
     71  GCThingIndex scopeIndex_;
     72 
     73  // If kind is Lexical, Catch, or With, the index in the BytecodeEmitter's
     74  // block scope note list. Otherwise ScopeNote::NoScopeNote.
     75  uint32_t noteIndex_;
     76 
     77  [[nodiscard]] bool ensureCache(BytecodeEmitter* bce);
     78 
     79  [[nodiscard]] bool checkSlotLimits(BytecodeEmitter* bce,
     80                                     const ParserBindingIter& bi);
     81 
     82  [[nodiscard]] bool checkEnvironmentChainLength(BytecodeEmitter* bce);
     83 
     84  void updateFrameFixedSlots(BytecodeEmitter* bce, const ParserBindingIter& bi);
     85 
     86  [[nodiscard]] bool putNameInCache(BytecodeEmitter* bce,
     87                                    TaggedParserAtomIndex name,
     88                                    NameLocation loc);
     89 
     90  mozilla::Maybe<NameLocation> lookupInCache(BytecodeEmitter* bce,
     91                                             TaggedParserAtomIndex name);
     92 
     93  EmitterScope* enclosing(BytecodeEmitter** bce) const;
     94 
     95  mozilla::Maybe<ScopeIndex> enclosingScopeIndex(BytecodeEmitter* bce) const;
     96 
     97  static bool nameCanBeFree(BytecodeEmitter* bce, TaggedParserAtomIndex name);
     98 
     99  NameLocation searchAndCache(BytecodeEmitter* bce, TaggedParserAtomIndex name);
    100 
    101  [[nodiscard]] bool internEmptyGlobalScopeAsBody(BytecodeEmitter* bce);
    102 
    103  [[nodiscard]] bool internScopeStencil(BytecodeEmitter* bce, ScopeIndex index);
    104 
    105  [[nodiscard]] bool internBodyScopeStencil(BytecodeEmitter* bce,
    106                                            ScopeIndex index);
    107  [[nodiscard]] bool appendScopeNote(BytecodeEmitter* bce);
    108 
    109  [[nodiscard]] bool clearFrameSlotRange(BytecodeEmitter* bce, JSOp opcode,
    110                                         uint32_t slotStart,
    111                                         uint32_t slotEnd) const;
    112 
    113  [[nodiscard]] bool deadZoneFrameSlotRange(BytecodeEmitter* bce,
    114                                            uint32_t slotStart,
    115                                            uint32_t slotEnd) const {
    116    return clearFrameSlotRange(bce, JSOp::Uninitialized, slotStart, slotEnd);
    117  }
    118 
    119 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
    120  void setHasDisposables(BytecodeEmitter* bce) {
    121    if (!usingEmitter_.isSome()) {
    122      usingEmitter_.emplace(bce);
    123    }
    124  }
    125 #endif
    126 
    127 public:
    128  explicit EmitterScope(BytecodeEmitter* bce);
    129 
    130  void dump(BytecodeEmitter* bce);
    131 
    132  [[nodiscard]] bool enterLexical(BytecodeEmitter* bce, ScopeKind kind,
    133                                  LexicalScope::ParserData* bindings
    134 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
    135                                  ,
    136                                  BlockKind blockKind = BlockKind::Other
    137 #endif
    138  );
    139  [[nodiscard]] bool enterClassBody(BytecodeEmitter* bce, ScopeKind kind,
    140                                    ClassBodyScope::ParserData* bindings);
    141  [[nodiscard]] bool enterNamedLambda(BytecodeEmitter* bce,
    142                                      FunctionBox* funbox);
    143  [[nodiscard]] bool enterFunction(BytecodeEmitter* bce, FunctionBox* funbox);
    144  [[nodiscard]] bool enterFunctionExtraBodyVar(BytecodeEmitter* bce,
    145                                               FunctionBox* funbox);
    146  [[nodiscard]] bool enterGlobal(BytecodeEmitter* bce,
    147                                 GlobalSharedContext* globalsc);
    148  [[nodiscard]] bool enterEval(BytecodeEmitter* bce, EvalSharedContext* evalsc);
    149  [[nodiscard]] bool enterModule(BytecodeEmitter* module,
    150                                 ModuleSharedContext* modulesc);
    151  [[nodiscard]] bool enterWith(BytecodeEmitter* bce);
    152  [[nodiscard]] bool deadZoneFrameSlots(BytecodeEmitter* bce) const;
    153 
    154  [[nodiscard]] bool leave(BytecodeEmitter* bce, bool nonLocal = false);
    155 
    156  GCThingIndex index() const {
    157    MOZ_ASSERT(scopeIndex_ != ScopeNote::NoScopeIndex,
    158               "Did you forget to intern a Scope?");
    159    return scopeIndex_;
    160  }
    161 
    162  uint32_t noteIndex() const { return noteIndex_; }
    163 
    164  AbstractScopePtr scope(const BytecodeEmitter* bce) const;
    165  mozilla::Maybe<ScopeIndex> scopeIndex(const BytecodeEmitter* bce) const;
    166 
    167  bool hasEnvironment() const { return hasEnvironment_; }
    168 
    169 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
    170 private:
    171  // Disposable Scope here refers to any scope
    172  // with using bindings in it for now that is
    173  // a lexical scope and a module scope.
    174  [[nodiscard]] bool prepareForDisposableScopeBody(BytecodeEmitter* bce);
    175 
    176  [[nodiscard]] bool emitDisposableScopeBodyEnd(BytecodeEmitter* bce);
    177 
    178 public:
    179  [[nodiscard]] bool prepareForModuleDisposableScopeBody(BytecodeEmitter* bce);
    180 
    181  [[nodiscard]] bool emitModuleDisposableScopeBodyEnd(BytecodeEmitter* bce);
    182 
    183  [[nodiscard]] bool prepareForDisposableAssignment(UsingHint hint);
    184 
    185  bool hasDisposables() const { return usingEmitter_.isSome(); }
    186 
    187  bool hasAsyncDisposables() const {
    188    return hasDisposables() && usingEmitter_->hasAwaitUsing();
    189  }
    190 #endif
    191 
    192  // The first frame slot used.
    193  uint32_t frameSlotStart() const {
    194    if (EmitterScope* inFrame = enclosingInFrame()) {
    195      return inFrame->nextFrameSlot_;
    196    }
    197    return 0;
    198  }
    199 
    200  // The last frame slot used + 1.
    201  uint32_t frameSlotEnd() const { return nextFrameSlot_; }
    202 
    203  EmitterScope* enclosingInFrame() const {
    204    return Nestable<EmitterScope>::enclosing();
    205  }
    206 
    207  NameLocation lookup(BytecodeEmitter* bce, TaggedParserAtomIndex name);
    208 
    209  // Find both the slot associated with a private name and the location of the
    210  // corresponding `.privateBrand` binding.
    211  //
    212  // Simply doing two separate lookups, one for `name` and another for
    213  // `.privateBrand`, would give the wrong answer in this case:
    214  //
    215  //     class Outer {
    216  //       #outerMethod() { reutrn "ok"; }
    217  //
    218  //       test() {
    219  //         class Inner {
    220  //           #innerMethod() {}
    221  //           test(outer) {
    222  //             return outer.#outerMethod();
    223  //           }
    224  //         }
    225  //         return new Inner().test(this);
    226  //       }
    227  //     }
    228  //
    229  //    new Outer().test();  // should return "ok"
    230  //
    231  // At the point in Inner.test where `#outerMethod` is called, we need to
    232  // check for the private brand of `Outer`, not `Inner`; but both class bodies
    233  // have `.privateBrand` bindings. In a normal `lookup`, the inner binding
    234  // would shadow the outer one.
    235  //
    236  // This method instead sets `brandLoc` to the location of the `.privateBrand`
    237  // binding in the same class body as the private name `name`, ignoring
    238  // shadowing. If `name` refers to a name that is actually stamped onto the
    239  // target object (anything other than a non-static private method), then
    240  // `brandLoc` is set to Nothing.
    241  void lookupPrivate(BytecodeEmitter* bce, TaggedParserAtomIndex name,
    242                     NameLocation& loc, mozilla::Maybe<NameLocation>& brandLoc);
    243 
    244  mozilla::Maybe<NameLocation> locationBoundInScope(TaggedParserAtomIndex name,
    245                                                    EmitterScope* target);
    246 
    247  // For a given emitter scope, return the number of enclosing environments in
    248  // the current compilation (this excludes environments that could enclose the
    249  // compilation, like would happen for an eval copmilation).
    250  static uint32_t CountEnclosingCompilationEnvironments(
    251      BytecodeEmitter* bce, EmitterScope* emitterScope);
    252 };
    253 
    254 } /* namespace frontend */
    255 } /* namespace js */
    256 
    257 #endif /* frontend_EmitterScope_h */