tor-browser

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

PrivateOpEmitter.h (6972B)


      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_PrivateOpEmitter_h
      8 #define frontend_PrivateOpEmitter_h
      9 
     10 #include "mozilla/Attributes.h"
     11 #include "mozilla/Maybe.h"
     12 
     13 #include <stddef.h>
     14 
     15 #include "frontend/NameAnalysisTypes.h"  // NameLocation
     16 #include "frontend/ParserAtom.h"         // TaggedParserAtomIndex
     17 
     18 namespace js {
     19 namespace frontend {
     20 
     21 struct BytecodeEmitter;
     22 enum class ValueUsage;
     23 
     24 // Class for emitting bytecode for operations on private members of objects.
     25 //
     26 // Usage is similar to PropOpEmitter, but the name of the private member must
     27 // be passed to the constructor; prepare*() methods aren't necessary; and
     28 // `delete obj.#member` and `super.#member` aren't supported because both are
     29 // SyntaxErrors.
     30 //
     31 // Usage: (error checking is omitted for simplicity)
     32 //
     33 //   `obj.#member;`
     34 //     PrivateOpEmitter xoe(this,
     35 //                          privateName,
     36 //                          PrivateOpEmitter::Kind::Get);
     37 //     emit(obj);
     38 //     xoe.emitReference();
     39 //     xoe.emitGet();
     40 //
     41 //   `obj.#member();`
     42 //     PrivateOpEmitter xoe(this,
     43 //                          privateName,
     44 //                          PrivateOpEmitter::Kind::Call);
     45 //     emit(obj);
     46 //     xoe.emitReference();
     47 //     xoe.emitGet();
     48 //     emit_call_here();
     49 //
     50 //   `new obj.#member();`
     51 //     The same, but use PrivateOpEmitter::Kind::Get.
     52 //
     53 //   `obj.#field++;`
     54 //     PrivateOpEmitter xoe(this,
     55 //                          privateName,
     56 //                          PrivateOpEmitter::Kind::PostIncrement);
     57 //     emit(obj);
     58 //     xoe.emitReference();
     59 //     xoe.emitIncDec();
     60 //
     61 //   `obj.#field = value;`
     62 //     PrivateOpEmitter xoe(this,
     63 //                          privateName,
     64 //                          PrivateOpEmitter::Kind::SimpleAssignment);
     65 //     emit(obj);
     66 //     xoe.emitReference();
     67 //     emit(value);
     68 //     xoe.emitAssignment();
     69 //
     70 //   `obj.#field += value;`
     71 //     PrivateOpEmitter xoe(this,
     72 //                          privateName,
     73 //                          PrivateOpEmitter::Kind::CompoundAssignment);
     74 //     emit(obj);
     75 //     xoe.emitReference();
     76 //     emit(JSOp::Dup2);
     77 //     xoe.emitGet();
     78 //     emit(value);
     79 //     emit_add_op_here();
     80 //     xoe.emitAssignment();
     81 //
     82 class MOZ_STACK_CLASS PrivateOpEmitter {
     83 public:
     84  enum class Kind {
     85    Get,
     86    Call,
     87    Delete,
     88    PostIncrement,
     89    PreIncrement,
     90    PostDecrement,
     91    PreDecrement,
     92    SimpleAssignment,
     93    PropInit,
     94    CompoundAssignment,
     95    ErgonomicBrandCheck,
     96  };
     97 
     98 private:
     99  BytecodeEmitter* bce_;
    100 
    101  Kind kind_;
    102 
    103  // Name of the private member, e.g. "#field".
    104  TaggedParserAtomIndex name_;
    105 
    106  // Location of the slot containing the private name symbol; or, for a
    107  // non-static private method, the slot containing the method.
    108  mozilla::Maybe<NameLocation> loc_;
    109 
    110  // For non-static private method accesses, the location of the relevant
    111  // `.privateBrand` binding. Otherwise, `Nothing`.
    112  mozilla::Maybe<NameLocation> brandLoc_{};
    113 
    114 #ifdef DEBUG
    115  // The state of this emitter.
    116  //
    117  // +-------+  emitReference  +-----------+
    118  // | Start |---------------->| Reference |
    119  // +-------+                 +-----+-----+
    120  //                                 |
    121  //     +---------------------------+
    122  //     |
    123  //     |
    124  //     | [Get]
    125  //     |   emitGet
    126  //     | [Call] [Get]                  [CompoundAssignment]
    127  //     |   emitGetForCallOrNew +-----+   emitAssignment
    128  //     +---------------------->| Get |-------------------+
    129  //     |                       +-----+                   |
    130  //     | [PostIncrement]                                 |
    131  //     | [PreIncrement]                                  |
    132  //     | [PostDecrement]                                 |
    133  //     | [PreDecrement]                                  |
    134  //     |   emitIncDec                                    |
    135  //     +------------------------------------------------>+
    136  //     |                                                 |
    137  //     | [SimpleAssignment]                              |
    138  //     | [PropInit]                                      V
    139  //     |   emitAssignment                          +------------+
    140  //     +------------------------------------------>| Assignment |
    141  //                                                 +------------+
    142  enum class State {
    143    // The initial state.
    144    Start,
    145 
    146    // After calling emitReference.
    147    Reference,
    148 
    149    // After calling emitGet.
    150    Get,
    151 
    152    // After calling emitAssignment or emitIncDec.
    153    Assignment,
    154  };
    155  State state_ = State::Start;
    156 #endif
    157 
    158 public:
    159  PrivateOpEmitter(BytecodeEmitter* bce, Kind kind, TaggedParserAtomIndex name);
    160 
    161 private:
    162  [[nodiscard]] bool isCall() const { return kind_ == Kind::Call; }
    163 
    164  [[nodiscard]] bool isSimpleAssignment() const {
    165    return kind_ == Kind::SimpleAssignment;
    166  }
    167 
    168  [[nodiscard]] bool isFieldInit() const { return kind_ == Kind::PropInit; }
    169 
    170  [[nodiscard]] bool isBrandCheck() const {
    171    return kind_ == Kind::ErgonomicBrandCheck;
    172  }
    173 
    174  [[nodiscard]] bool isCompoundAssignment() const {
    175    return kind_ == Kind::CompoundAssignment;
    176  }
    177 
    178  [[nodiscard]] bool isIncDec() const {
    179    return isPostIncDec() || isPreIncDec();
    180  }
    181 
    182  [[nodiscard]] bool isPostIncDec() const {
    183    return kind_ == Kind::PostIncrement || kind_ == Kind::PostDecrement;
    184  }
    185 
    186  [[nodiscard]] bool isPreIncDec() const {
    187    return kind_ == Kind::PreIncrement || kind_ == Kind::PreDecrement;
    188  }
    189 
    190  [[nodiscard]] bool isInc() const {
    191    return kind_ == Kind::PostIncrement || kind_ == Kind::PreIncrement;
    192  }
    193 
    194  [[nodiscard]] bool init();
    195 
    196  // Emit a GetAliasedLexical or similar instruction.
    197  [[nodiscard]] bool emitLoad(TaggedParserAtomIndex name,
    198                              const NameLocation& loc);
    199 
    200  [[nodiscard]] bool emitLoadPrivateBrand();
    201 
    202 public:
    203  // Emit bytecode to check for the presence/absence of a private field/brand.
    204  //
    205  // Given OBJ KEY on the stack, where KEY is a private name symbol, the
    206  // emitted code will throw if OBJ does not have the given KEY.
    207  //
    208  // If `isFieldInit()`, the check is reversed: the code will throw if OBJ
    209  // already has the KEY.
    210  //
    211  // If `isBrandCheck()`, the check verifies RHS is an object (throwing if not).
    212  //
    213  // The bytecode leaves OBJ KEY BOOL on the stack. Caller is responsible for
    214  // consuming or popping it.
    215  [[nodiscard]] bool emitBrandCheck();
    216 
    217  [[nodiscard]] bool emitReference();
    218  [[nodiscard]] bool emitGet();
    219  [[nodiscard]] bool emitGetForCallOrNew();
    220  [[nodiscard]] bool emitAssignment();
    221  [[nodiscard]] bool emitIncDec(ValueUsage valueUsage);
    222 
    223  size_t numReferenceSlots() const { return 2; }
    224 };
    225 
    226 } /* namespace frontend */
    227 } /* namespace js */
    228 
    229 #endif /* frontend_PrivateOpEmitter_h */