tor-browser

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

CallOrNewEmitter.h (12806B)


      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_CallOrNewEmitter_h
      8 #define frontend_CallOrNewEmitter_h
      9 
     10 #include "mozilla/Attributes.h"
     11 #include "mozilla/Maybe.h"
     12 
     13 #include <stdint.h>
     14 
     15 #include "frontend/ElemOpEmitter.h"
     16 #include "frontend/IfEmitter.h"
     17 #include "frontend/PrivateOpEmitter.h"
     18 #include "frontend/PropOpEmitter.h"
     19 #include "frontend/ValueUsage.h"
     20 #include "vm/BytecodeUtil.h"
     21 #include "vm/Opcodes.h"
     22 
     23 namespace js {
     24 namespace frontend {
     25 
     26 struct BytecodeEmitter;
     27 class TaggedParserAtomIndex;
     28 
     29 // Class for emitting bytecode for call or new expression.
     30 //
     31 // Usage: (check for the return value is omitted for simplicity)
     32 //
     33 //   `print(arg);`
     34 //     CallOrNewEmitter cone(this, JSOp::Call,
     35 //                           CallOrNewEmitter::ArgumentsKind::Other,
     36 //                           ValueUsage::WantValue);
     37 //     cone.emitNameCallee(print);
     38 //     cone.emitThis();
     39 //     cone.prepareForNonSpreadArguments();
     40 //     emit(arg);
     41 //     cone.emitEnd(1, offset_of_callee);
     42 //
     43 //   `callee.prop(arg1, arg2);`
     44 //     CallOrNewEmitter cone(this, JSOp::Call,
     45 //                           CallOrNewEmitter::ArgumentsKind::Other,
     46 //                           ValueUsage::WantValue);
     47 //     PropOpEmitter& poe = cone.prepareForPropCallee(false);
     48 //     ... emit `callee.prop` with `poe` here...
     49 //     cone.emitThis();
     50 //     cone.prepareForNonSpreadArguments();
     51 //     emit(arg1);
     52 //     emit(arg2);
     53 //     cone.emitEnd(2, offset_of_callee);
     54 //
     55 //   `callee[key](arg);`
     56 //     CallOrNewEmitter cone(this, JSOp::Call,
     57 //                           CallOrNewEmitter::ArgumentsKind::Other,
     58 //                           ValueUsage::WantValue);
     59 //     ElemOpEmitter& eoe = cone.prepareForElemCallee(false);
     60 //     ... emit `callee[key]` with `eoe` here...
     61 //     cone.emitThis();
     62 //     cone.prepareForNonSpreadArguments();
     63 //     emit(arg);
     64 //     cone.emitEnd(1, offset_of_callee);
     65 //
     66 //   `callee.#method(arg);`
     67 //     CallOrNewEmitter cone(this, JSOp::Call,
     68 //                           CallOrNewEmitter::ArgumentsKind::Other,
     69 //                           ValueUsage::WantValue);
     70 //     PrivateOpEmitter& xoe = cone.prepareForPrivateCallee();
     71 //     ... emit `callee.#method` with `xoe` here...
     72 //     cone.prepareForNonSpreadArguments();
     73 //     emit(arg);
     74 //     cone.emitEnd(1, offset_of_callee);
     75 //
     76 //   `(function() { ... })(arg);`
     77 //     CallOrNewEmitter cone(this, JSOp::Call,
     78 //                           CallOrNewEmitter::ArgumentsKind::Other,
     79 //                           ValueUsage::WantValue);
     80 //     cone.prepareForFunctionCallee();
     81 //     emit(function);
     82 //     cone.emitThis();
     83 //     cone.prepareForNonSpreadArguments();
     84 //     emit(arg);
     85 //     cone.emitEnd(1, offset_of_callee);
     86 //
     87 //   `super(arg);`
     88 //     CallOrNewEmitter cone(this, JSOp::Call,
     89 //                           CallOrNewEmitter::ArgumentsKind::Other,
     90 //                           ValueUsage::WantValue);
     91 //     cone.emitSuperCallee();
     92 //     cone.emitThis();
     93 //     cone.prepareForNonSpreadArguments();
     94 //     emit(arg);
     95 //     cone.emitEnd(1, offset_of_callee);
     96 //
     97 //   `(some_other_expression)(arg);`
     98 //     CallOrNewEmitter cone(this, JSOp::Call,
     99 //                           CallOrNewEmitter::ArgumentsKind::Other,
    100 //                           ValueUsage::WantValue);
    101 //     cone.prepareForOtherCallee();
    102 //     emit(some_other_expression);
    103 //     cone.emitThis();
    104 //     cone.prepareForNonSpreadArguments();
    105 //     emit(arg);
    106 //     cone.emitEnd(1, offset_of_callee);
    107 //
    108 //   `print(...arg);`
    109 //     CallOrNewEmitter cone(this, JSOp::SpreadCall,
    110 //                           CallOrNewEmitter::ArgumentsKind::SingleSpread,
    111 //                           ValueUsage::WantValue);
    112 //     cone.emitNameCallee(print);
    113 //     cone.emitThis();
    114 //     if (cone.wantSpreadOperand()) {
    115 //       emit(arg)
    116 //     }
    117 //     cone.emitSpreadArgumentsTest();
    118 //     emit([...arg]);
    119 //     cone.emitEnd(1, offset_of_callee);
    120 //
    121 //   `new f(arg);`
    122 //     CallOrNewEmitter cone(this, JSOp::New,
    123 //                           CallOrNewEmitter::ArgumentsKind::Other,
    124 //                           ValueUsage::WantValue);
    125 //     cone.emitNameCallee(f);
    126 //     cone.emitThis();
    127 //     cone.prepareForNonSpreadArguments();
    128 //     emit(arg);
    129 //     cone.emitEnd(1, offset_of_callee);
    130 //
    131 class MOZ_STACK_CLASS CallOrNewEmitter {
    132 public:
    133  enum class ArgumentsKind {
    134    Other,
    135 
    136    // Specify this for the following case:
    137    //
    138    //   g(...input);
    139    //
    140    // This enables optimization to avoid allocating an intermediate array
    141    // for spread operation.
    142    //
    143    // wantSpreadOperand() returns true when this is specified.
    144    SingleSpread,
    145 
    146    // Used for default derived class constructors:
    147    //
    148    //   constructor(...args) {
    149    //      super(...args);
    150    //   }
    151    //
    152    // The rest-parameter is directly passed through to the `super` call without
    153    // using the iteration protocol.
    154    PassthroughRest,
    155  };
    156 
    157 private:
    158  BytecodeEmitter* bce_;
    159 
    160  // The opcode for the call or new.
    161  JSOp op_;
    162 
    163  // Whether the call is a spread call with single parameter or not.
    164  // See the comment in emitSpreadArgumentsTest for more details.
    165  ArgumentsKind argumentsKind_;
    166 
    167  // The branch for spread call optimization.
    168  mozilla::Maybe<InternalIfEmitter> ifNotOptimizable_;
    169 
    170  mozilla::Maybe<PropOpEmitter> poe_;
    171  mozilla::Maybe<ElemOpEmitter> eoe_;
    172  mozilla::Maybe<PrivateOpEmitter> xoe_;
    173 
    174  // The state of this emitter.
    175  //
    176  // +-------+   emitNameCallee           +------------+
    177  // | Start |-+------------------------->| NameCallee |------+
    178  // +-------+ |                          +------------+      |
    179  //           |                                              |
    180  //           | prepareForPropCallee     +------------+      v
    181  //           +------------------------->| PropCallee |----->+
    182  //           |                          +------------+      |
    183  //           |                                              |
    184  //           | prepareForElemCallee     +------------+      v
    185  //           +------------------------->| ElemCallee |----->+
    186  //           |                          +------------+      |
    187  //           |                                              |
    188  //           | prepareForPrivateCallee  +---------------+   v
    189  //           +------------------------->| PrivateCallee |-->+
    190  //           |                          +---------------+   |
    191  //           |                                              |
    192  //           | prepareForFunctionCallee +----------------+  v
    193  //           +------------------------->| FunctionCallee |->+
    194  //           |                          +----------------+  |
    195  //           |                                              |
    196  //           | emitSuperCallee          +-------------+     v
    197  //           +------------------------->| SuperCallee |---->+
    198  //           |                          +-------------+     |
    199  //           |                                              |
    200  //           | prepareForOtherCallee    +-------------+     v
    201  //           +------------------------->| OtherCallee |---->+
    202  //                                      +-------------+     |
    203  //                                                          |
    204  // +--------------------------------------------------------+
    205  // |
    206  // | emitThis +------+
    207  // +--------->| This |-+
    208  //            +------+ |
    209  //                     |
    210  // +-------------------+
    211  // |
    212  // | [!isSpread]
    213  // |   prepareForNonSpreadArguments    +-----------+ emitEnd +-----+
    214  // +------------------------------->+->| Arguments |-------->| End |
    215  // |                                ^  +-----------+         +-----+
    216  // |                                |
    217  // |                                +<------------------------------------+
    218  // |                                |                                     |
    219  // |                                | emitSpreadArgumentsTestEnd          |
    220  // |                                |                                     |
    221  // |                                |         +-----------------+         |
    222  // |                                +---------| SpreadIteration |------+  |
    223  // |                                          +-----------------+      |  |
    224  // |                                +----------------------------------+  |
    225  // |                                |                                     |
    226  // |                                | wantSpreadIteration                 |
    227  // |                                |                                     |
    228  // |                                |         +---------------------+     |
    229  // |                                +---------| SpreadArgumentsTest |--+  |
    230  // |                                          +---------------------+  |  |
    231  // | [isSpread]                                                        |  |
    232  // |   wantSpreadOperand +-------------------+ emitSpreadArgumentsTest |  |
    233  // +-------------------->| WantSpreadOperand |-------------------------+  |
    234  // |                     +-------------------+                            |
    235  // |                                                                      |
    236  // |                                                                      |
    237  // |                                                                      |
    238  // | [isSpread]                                                           |
    239  // |   prepareForSpreadArguments                                          |
    240  // +----------------------------------------------------------------------+
    241  enum class State {
    242    // The initial state.
    243    Start,
    244 
    245    // After calling emitNameCallee.
    246    NameCallee,
    247 
    248    // After calling prepareForPropCallee.
    249    PropCallee,
    250 
    251    // After calling prepareForElemCallee.
    252    ElemCallee,
    253 
    254    // After calling prepareForPrivateCallee.
    255    PrivateCallee,
    256 
    257    // After calling prepareForFunctionCallee.
    258    FunctionCallee,
    259 
    260    // After calling emitSuperCallee.
    261    SuperCallee,
    262 
    263    // After calling prepareForOtherCallee.
    264    OtherCallee,
    265 
    266    // After calling emitThis.
    267    This,
    268 
    269    // After calling wantSpreadOperand.
    270    WantSpreadOperand,
    271 
    272    // After calling emitSpreadArgumentsTest.
    273    SpreadArgumentsTest,
    274 
    275    // After calling wantSpreadIteration.
    276    SpreadIteration,
    277 
    278    // After calling prepareForNonSpreadArguments.
    279    Arguments,
    280 
    281    // After calling emitEnd.
    282    End
    283  };
    284  State state_ = State::Start;
    285 
    286 public:
    287  CallOrNewEmitter(BytecodeEmitter* bce, JSOp op, ArgumentsKind argumentsKind,
    288                   ValueUsage valueUsage);
    289 
    290 private:
    291  [[nodiscard]] bool isCall() const {
    292    return op_ == JSOp::Call || op_ == JSOp::CallIgnoresRv ||
    293           op_ == JSOp::SpreadCall || isEval();
    294  }
    295 
    296  [[nodiscard]] bool isNew() const {
    297    return op_ == JSOp::New || op_ == JSOp::SpreadNew;
    298  }
    299 
    300  [[nodiscard]] bool isSuperCall() const {
    301    return op_ == JSOp::SuperCall || op_ == JSOp::SpreadSuperCall;
    302  }
    303 
    304  [[nodiscard]] bool isEval() const {
    305    return op_ == JSOp::Eval || op_ == JSOp::StrictEval ||
    306           op_ == JSOp::SpreadEval || op_ == JSOp::StrictSpreadEval;
    307  }
    308 
    309  [[nodiscard]] bool isSpread() const { return IsSpreadOp(op_); }
    310 
    311  [[nodiscard]] bool isSingleSpread() const {
    312    return argumentsKind_ == ArgumentsKind::SingleSpread;
    313  }
    314 
    315  [[nodiscard]] bool isPassthroughRest() const {
    316    return argumentsKind_ == ArgumentsKind::PassthroughRest;
    317  }
    318 
    319 public:
    320  [[nodiscard]] bool emitNameCallee(TaggedParserAtomIndex name);
    321  [[nodiscard]] PropOpEmitter& prepareForPropCallee(bool isSuperProp);
    322  [[nodiscard]] ElemOpEmitter& prepareForElemCallee(bool isSuperElem);
    323  [[nodiscard]] PrivateOpEmitter& prepareForPrivateCallee(
    324      TaggedParserAtomIndex privateName);
    325  [[nodiscard]] bool prepareForFunctionCallee();
    326  [[nodiscard]] bool emitSuperCallee();
    327  [[nodiscard]] bool prepareForOtherCallee();
    328 
    329  [[nodiscard]] bool emitThis();
    330 
    331  [[nodiscard]] bool prepareForNonSpreadArguments();
    332  [[nodiscard]] bool prepareForSpreadArguments();
    333 
    334  // See the usage in the comment at the top of the class.
    335  [[nodiscard]] bool wantSpreadOperand();
    336  [[nodiscard]] bool emitSpreadArgumentsTest();
    337  [[nodiscard]] bool emitSpreadArgumentsTestEnd();
    338  [[nodiscard]] bool wantSpreadIteration();
    339 
    340  // Parameters are the offset in the source code for each character below:
    341  //
    342  //   callee(arg);
    343  //   ^
    344  //   |
    345  //   beginPos
    346  [[nodiscard]] bool emitEnd(uint32_t argc, uint32_t beginPos);
    347 };
    348 
    349 } /* namespace frontend */
    350 } /* namespace js */
    351 
    352 #endif /* frontend_CallOrNewEmitter_h */