tor-browser

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

SwitchEmitter.h (14106B)


      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_SwitchEmitter_h
      8 #define frontend_SwitchEmitter_h
      9 
     10 #include "mozilla/Assertions.h"  // MOZ_ASSERT
     11 #include "mozilla/Attributes.h"  // MOZ_STACK_CLASS
     12 #include "mozilla/Maybe.h"       // mozilla::Maybe
     13 
     14 #include <stddef.h>  // size_t
     15 #include <stdint.h>  // int32_t, uint32_t
     16 
     17 #include "frontend/BytecodeControlStructures.h"  // BreakableControl
     18 #include "frontend/EmitterScope.h"               // EmitterScope
     19 #include "frontend/JumpList.h"                   // JumpList, JumpTarget
     20 #include "frontend/TDZCheckCache.h"              // TDZCheckCache
     21 #include "js/AllocPolicy.h"                      // SystemAllocPolicy
     22 #include "js/Value.h"                            // JSVAL_INT_MAX, JSVAL_INT_MIN
     23 #include "js/Vector.h"                           // Vector
     24 #include "vm/Scope.h"                            // LexicalScope
     25 
     26 namespace js {
     27 namespace frontend {
     28 
     29 struct BytecodeEmitter;
     30 
     31 // Class for emitting bytecode for switch-case-default block.
     32 //
     33 // Usage: (check for the return value is omitted for simplicity)
     34 //
     35 //   `switch (discriminant) { case c1_expr: c1_body; }`
     36 //     SwitchEmitter se(this);
     37 //     se.emitDiscriminant(offset_of_switch);
     38 //     emit(discriminant);
     39 //
     40 //     se.validateCaseCount(1);
     41 //     se.emitCond();
     42 //
     43 //     se.prepareForCaseValue();
     44 //     emit(c1_expr);
     45 //     se.emitCaseJump();
     46 //
     47 //     se.emitCaseBody();
     48 //     emit(c1_body);
     49 //
     50 //     se.emitEnd();
     51 //
     52 //   `switch (discriminant) { case c1_expr: c1_body; case c2_expr: c2_body;
     53 //                            default: def_body; }`
     54 //     SwitchEmitter se(this);
     55 //     se.emitDiscriminant(offset_of_switch);
     56 //     emit(discriminant);
     57 //
     58 //     se.validateCaseCount(2);
     59 //     se.emitCond();
     60 //
     61 //     se.prepareForCaseValue();
     62 //     emit(c1_expr);
     63 //     se.emitCaseJump();
     64 //
     65 //     se.prepareForCaseValue();
     66 //     emit(c2_expr);
     67 //     se.emitCaseJump();
     68 //
     69 //     se.emitCaseBody();
     70 //     emit(c1_body);
     71 //
     72 //     se.emitCaseBody();
     73 //     emit(c2_body);
     74 //
     75 //     se.emitDefaultBody();
     76 //     emit(def_body);
     77 //
     78 //     se.emitEnd();
     79 //
     80 //   `switch (discriminant) { case c1_expr: c1_body; case c2_expr: c2_body; }`
     81 //   with Table Switch
     82 //     SwitchEmitter::TableGenerator tableGen(this);
     83 //     tableGen.addNumber(c1_expr_value);
     84 //     tableGen.addNumber(c2_expr_value);
     85 //     tableGen.finish(2);
     86 //
     87 //     // If `!tableGen.isValid()` here, `emitCond` should be used instead.
     88 //
     89 //     SwitchEmitter se(this);
     90 //     se.emitDiscriminant(offset_of_switch);
     91 //     emit(discriminant);
     92 //     se.validateCaseCount(2);
     93 //     se.emitTable(tableGen);
     94 //
     95 //     se.emitCaseBody(c1_expr_value, tableGen);
     96 //     emit(c1_body);
     97 //
     98 //     se.emitCaseBody(c2_expr_value, tableGen);
     99 //     emit(c2_body);
    100 //
    101 //     se.emitEnd();
    102 //
    103 //   `switch (discriminant) { case c1_expr: c1_body; case c2_expr: c2_body;
    104 //                            default: def_body; }`
    105 //   with Table Switch
    106 //     SwitchEmitter::TableGenerator tableGen(bce);
    107 //     tableGen.addNumber(c1_expr_value);
    108 //     tableGen.addNumber(c2_expr_value);
    109 //     tableGen.finish(2);
    110 //
    111 //     // If `!tableGen.isValid()` here, `emitCond` should be used instead.
    112 //
    113 //     SwitchEmitter se(this);
    114 //     se.emitDiscriminant(offset_of_switch);
    115 //     emit(discriminant);
    116 //     se.validateCaseCount(2);
    117 //     se.emitTable(tableGen);
    118 //
    119 //     se.emitCaseBody(c1_expr_value, tableGen);
    120 //     emit(c1_body);
    121 //
    122 //     se.emitCaseBody(c2_expr_value, tableGen);
    123 //     emit(c2_body);
    124 //
    125 //     se.emitDefaultBody();
    126 //     emit(def_body);
    127 //
    128 //     se.emitEnd();
    129 //
    130 //   `switch (discriminant) { case c1_expr: c1_body; }`
    131 //   in case c1_body contains lexical bindings
    132 //     SwitchEmitter se(this);
    133 //     se.emitDiscriminant(offset_of_switch);
    134 //     emit(discriminant);
    135 //
    136 //     se.validateCaseCount(1);
    137 //
    138 //     se.emitLexical(bindings);
    139 //
    140 //     se.emitCond();
    141 //
    142 //     se.prepareForCaseValue();
    143 //     emit(c1_expr);
    144 //     se.emitCaseJump();
    145 //
    146 //     se.emitCaseBody();
    147 //     emit(c1_body);
    148 //
    149 //     se.emitEnd();
    150 //
    151 //   `switch (discriminant) { case c1_expr: c1_body; }`
    152 //   in case c1_body contains hosted functions
    153 //     SwitchEmitter se(this);
    154 //     se.emitDiscriminant(offset_of_switch);
    155 //     emit(discriminant);
    156 //
    157 //     se.validateCaseCount(1);
    158 //
    159 //     se.emitLexical(bindings);
    160 //     emit(hosted functions);
    161 //
    162 //     se.emitCond();
    163 //
    164 //     se.prepareForCaseValue();
    165 //     emit(c1_expr);
    166 //     se.emitCaseJump();
    167 //
    168 //     se.emitCaseBody();
    169 //     emit(c1_body);
    170 //
    171 //     se.emitEnd();
    172 //
    173 class MOZ_STACK_CLASS SwitchEmitter {
    174  // Bytecode for each case.
    175  //
    176  // Cond Switch (uses an equality comparison for each case)
    177  //     {discriminant}
    178  //
    179  //     {c1_expr}
    180  //     JSOp::Case c1
    181  //
    182  //     JSOp::JumpTarget
    183  //     {c2_expr}
    184  //     JSOp::Case c2
    185  //
    186  //     ...
    187  //
    188  //     JSOp::JumpTarget
    189  //     JSOp::Default default
    190  //
    191  //   c1:
    192  //     JSOp::JumpTarget
    193  //     {c1_body}
    194  //     JSOp::Goto end
    195  //
    196  //   c2:
    197  //     JSOp::JumpTarget
    198  //     {c2_body}
    199  //     JSOp::Goto end
    200  //
    201  //   default:
    202  //   end:
    203  //     JSOp::JumpTarget
    204  //
    205  // Table Switch
    206  //     {discriminant}
    207  //     JSOp::TableSwitch c1, c2, ...
    208  //
    209  //   c1:
    210  //     JSOp::JumpTarget
    211  //     {c1_body}
    212  //     JSOp::Goto end
    213  //
    214  //   c2:
    215  //     JSOp::JumpTarget
    216  //     {c2_body}
    217  //     JSOp::Goto end
    218  //
    219  //   ...
    220  //
    221  //   end:
    222  //     JSOp::JumpTarget
    223 
    224 public:
    225  enum class Kind { Table, Cond };
    226 
    227  // Class for generating optimized table switch data.
    228  class MOZ_STACK_CLASS TableGenerator {
    229    BytecodeEmitter* bce_;
    230 
    231    // Bit array for given numbers.
    232    mozilla::Maybe<js::Vector<size_t, 128, SystemAllocPolicy>> intmap_;
    233 
    234    // The length of the intmap_.
    235    int32_t intmapBitLength_ = 0;
    236 
    237    // The length of the table.
    238    uint32_t tableLength_ = 0;
    239 
    240    // The lower and higher bounds of the table.
    241    int32_t low_ = JSVAL_INT_MAX, high_ = JSVAL_INT_MIN;
    242 
    243    // Whether the table is still valid.
    244    bool valid_ = true;
    245 
    246 #ifdef DEBUG
    247    bool finished_ = false;
    248 #endif
    249 
    250   public:
    251    explicit TableGenerator(BytecodeEmitter* bce) : bce_(bce) {}
    252 
    253    void setInvalid() { valid_ = false; }
    254    [[nodiscard]] bool isValid() const { return valid_; }
    255    [[nodiscard]] bool isInvalid() const { return !valid_; }
    256 
    257    // Add the given number to the table.  The number is the value of
    258    // `expr` for `case expr:` syntax.
    259    [[nodiscard]] bool addNumber(int32_t caseValue);
    260 
    261    // Finish generating the table.
    262    // `caseCount` should be the number of cases in the switch statement,
    263    // excluding the default case.
    264    void finish(uint32_t caseCount);
    265 
    266   private:
    267    friend SwitchEmitter;
    268 
    269    // The following methods can be used only after calling `finish`.
    270 
    271    // Returns the lower bound of the added numbers.
    272    int32_t low() const {
    273      MOZ_ASSERT(finished_);
    274      return low_;
    275    }
    276 
    277    // Returns the higher bound of the numbers.
    278    int32_t high() const {
    279      MOZ_ASSERT(finished_);
    280      return high_;
    281    }
    282 
    283    // Returns the index in SwitchEmitter.caseOffsets_ for table switch.
    284    uint32_t toCaseIndex(int32_t caseValue) const;
    285 
    286    // Returns the length of the table.
    287    // This method can be called only if `isValid()` is true.
    288    uint32_t tableLength() const;
    289  };
    290 
    291 private:
    292  BytecodeEmitter* bce_;
    293 
    294  // `kind_` should be set to the correct value in emitCond/emitTable.
    295  Kind kind_ = Kind::Cond;
    296 
    297  // True if there's explicit default case.
    298  bool hasDefault_ = false;
    299 
    300  // The number of cases in the switch statement, excluding the default case.
    301  uint32_t caseCount_ = 0;
    302 
    303  // Internal index for case jump and case body, used by cond switch.
    304  uint32_t caseIndex_ = 0;
    305 
    306  // Bytecode offset after emitting `discriminant`.
    307  BytecodeOffset top_;
    308 
    309  // Bytecode offset of the previous JSOp::Case.
    310  BytecodeOffset lastCaseOffset_;
    311 
    312  // Bytecode offset of the JSOp::JumpTarget for default body.
    313  JumpTarget defaultJumpTargetOffset_;
    314 
    315  // Bytecode offset of the JSOp::Default.
    316  JumpList condSwitchDefaultOffset_;
    317 
    318  // Instantiated when there's lexical scope for entire switch.
    319  mozilla::Maybe<TDZCheckCache> tdzCacheLexical_;
    320  mozilla::Maybe<EmitterScope> emitterScope_;
    321 
    322  // Instantiated while emitting case expression and case/default body.
    323  mozilla::Maybe<TDZCheckCache> tdzCacheCaseAndBody_;
    324 
    325  // Control for switch.
    326  mozilla::Maybe<BreakableControl> controlInfo_;
    327 
    328  uint32_t switchPos_ = 0;
    329 
    330  // Cond Switch:
    331  //   Offset of each JSOp::Case.
    332  // Table Switch:
    333  //   Offset of each JSOp::JumpTarget for case.
    334  js::Vector<BytecodeOffset, 32, SystemAllocPolicy> caseOffsets_;
    335 
    336  // The state of this emitter.
    337  //
    338  // +-------+ emitDiscriminant +--------------+
    339  // | Start |----------------->| Discriminant |-+
    340  // +-------+                  +--------------+ |
    341  //                                             |
    342  // +-------------------------------------------+
    343  // |
    344  // |                              validateCaseCount +-----------+
    345  // +->+------------------------>+------------------>| CaseCount |-+
    346  //    |                         ^                   +-----------+ |
    347  //    | emitLexical +---------+ |                                 |
    348  //    +------------>| Lexical |-+                                 |
    349  //                  +---------+                                   |
    350  //                                                                |
    351  // +--------------------------------------------------------------+
    352  // |
    353  // | emitTable +-------+
    354  // +---------->| Table |----------------------------------->+-+
    355  // |           +-------+                                    ^ |
    356  // |                                                        | |
    357  // | emitCond  +------+                                     | |
    358  // +---------->| Cond |-+------------------------------->+->+ |
    359  //             +------+ |                                ^    |
    360  //                      |                                |    |
    361  //   +------------------+                                |    |
    362  //   |                                                   |    |
    363  //   |prepareForCaseValue  +-----------+                 |    |
    364  //   +----------+--------->| CaseValue |                 |    |
    365  //              ^          +-----------+                 |    |
    366  //              |             |                          |    |
    367  //              |             | emitCaseJump +------+    |    |
    368  //              |             +------------->| Case |->+-+    |
    369  //              |                            +------+  |      |
    370  //              |                                      |      |
    371  //              +--------------------------------------+      |
    372  //                                                            |
    373  // +----------------------------------------------------------+
    374  // |
    375  // |                                              emitEnd +-----+
    376  // +-+----------------------------------------->+-------->| End |
    377  //   |                                          ^         +-----+
    378  //   |      emitCaseBody    +----------+        |
    379  //   +->+-+---------------->| CaseBody |--->+-+-+
    380  //      ^ |                 +----------+    ^ |
    381  //      | |                                 | |
    382  //      | | emitDefaultBody +-------------+ | |
    383  //      | +---------------->| DefaultBody |-+ |
    384  //      |                   +-------------+   |
    385  //      |                                     |
    386  //      +-------------------------------------+
    387  //
    388 protected:
    389  enum class State {
    390    // The initial state.
    391    Start,
    392 
    393    // After calling emitDiscriminant.
    394    Discriminant,
    395 
    396    // After calling validateCaseCount.
    397    CaseCount,
    398 
    399    // After calling emitLexical.
    400    Lexical,
    401 
    402    // After calling emitCond.
    403    Cond,
    404 
    405    // After calling emitTable.
    406    Table,
    407 
    408    // After calling prepareForCaseValue.
    409    CaseValue,
    410 
    411    // After calling emitCaseJump.
    412    Case,
    413 
    414    // After calling emitCaseBody.
    415    CaseBody,
    416 
    417    // After calling emitDefaultBody.
    418    DefaultBody,
    419 
    420    // After calling emitEnd.
    421    End
    422  };
    423  State state_ = State::Start;
    424 
    425 public:
    426  explicit SwitchEmitter(BytecodeEmitter* bce);
    427 
    428  // `switchPos` is the offset in the source code for the character below:
    429  //
    430  //   switch ( cond ) { ... }
    431  //   ^
    432  //   |
    433  //   switchPos
    434  [[nodiscard]] bool emitDiscriminant(uint32_t switchPos);
    435 
    436  // `caseCount` should be the number of cases in the switch statement,
    437  // excluding the default case.
    438  [[nodiscard]] bool validateCaseCount(uint32_t caseCount);
    439 
    440  // `bindings` is a lexical scope for the entire switch, in case there's
    441  // let/const effectively directly under case or default blocks.
    442  [[nodiscard]] bool emitLexical(LexicalScope::ParserData* bindings);
    443 
    444  [[nodiscard]] bool emitCond();
    445  [[nodiscard]] bool emitTable(const TableGenerator& tableGen);
    446 
    447  [[nodiscard]] bool prepareForCaseValue();
    448  [[nodiscard]] bool emitCaseJump();
    449 
    450  [[nodiscard]] bool emitCaseBody();
    451  [[nodiscard]] bool emitCaseBody(int32_t caseValue,
    452                                  const TableGenerator& tableGen);
    453  [[nodiscard]] bool emitDefaultBody();
    454  [[nodiscard]] bool emitEnd();
    455 
    456 private:
    457  [[nodiscard]] bool emitCaseOrDefaultJump(uint32_t caseIndex, bool isDefault);
    458  [[nodiscard]] bool emitImplicitDefault();
    459 };
    460 
    461 // Class for emitting bytecode for switch-case-default block that doesn't
    462 // correspond to a syntactic `switch`.
    463 // Compared to SwitchEmitter, this class doesn't require `emitDiscriminant`,
    464 // and the discriminant can already be on the stack. Usage is otherwise
    465 // the same as SwitchEmitter.
    466 class MOZ_STACK_CLASS InternalSwitchEmitter : public SwitchEmitter {
    467 public:
    468  explicit InternalSwitchEmitter(BytecodeEmitter* bce);
    469 };
    470 
    471 } /* namespace frontend */
    472 } /* namespace js */
    473 
    474 #endif /* frontend_SwitchEmitter_h */