tor-browser

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

IfEmitter.h (9701B)


      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_IfEmitter_h
      8 #define frontend_IfEmitter_h
      9 
     10 #include "mozilla/Attributes.h"
     11 #include "mozilla/Maybe.h"
     12 
     13 #include <stdint.h>
     14 
     15 #include "frontend/JumpList.h"
     16 #include "frontend/TDZCheckCache.h"
     17 
     18 namespace js {
     19 namespace frontend {
     20 
     21 struct BytecodeEmitter;
     22 
     23 class MOZ_STACK_CLASS BranchEmitterBase {
     24 public:
     25  // Whether the then-clause, the else-clause, or else-if condition may
     26  // contain declaration or access to lexical variables, which means they
     27  // should have their own TDZCheckCache.  Basically TDZCheckCache should be
     28  // created for each basic block, which then-clause, else-clause, and
     29  // else-if condition are, but for internally used branches which are
     30  // known not to touch lexical variables we can skip creating TDZCheckCache
     31  // for them.
     32  //
     33  // See the comment for TDZCheckCache class for more details.
     34  enum class LexicalKind {
     35    // For syntactic branches (if, if-else, and conditional expression),
     36    // which basically may contain declaration or accesses to lexical
     37    // variables inside then-clause, else-clause, and else-if condition.
     38    MayContainLexicalAccessInBranch,
     39 
     40    // For internally used branches which don't touch lexical variables
     41    // inside then-clause, else-clause, nor else-if condition.
     42    NoLexicalAccessInBranch
     43  };
     44 
     45 protected:
     46  BytecodeEmitter* bce_;
     47 
     48  // Jump around the then clause, to the beginning of the else clause.
     49  JumpList jumpAroundThen_;
     50 
     51  // Jump around the else clause, to the end of the entire branch.
     52  JumpList jumpsAroundElse_;
     53 
     54  // The stack depth before emitting the then block.
     55  // Used for restoring stack depth before emitting the else block.
     56  // Also used for assertion to make sure then and else blocks pushed the
     57  // same number of values.
     58  int32_t thenDepth_ = 0;
     59 
     60  enum class ConditionKind { Positive, Negative };
     61  LexicalKind lexicalKind_;
     62 
     63  mozilla::Maybe<TDZCheckCache> tdzCache_;
     64 
     65 #ifdef DEBUG
     66  // The number of values pushed in the then and else blocks.
     67  int32_t pushed_ = 0;
     68  bool calculatedPushed_ = false;
     69 #endif
     70 
     71 protected:
     72  BranchEmitterBase(BytecodeEmitter* bce, LexicalKind lexicalKind);
     73 
     74  [[nodiscard]] bool emitThenInternal(ConditionKind conditionKind);
     75  void calculateOrCheckPushed();
     76  [[nodiscard]] bool emitElseInternal();
     77  [[nodiscard]] bool emitEndInternal();
     78 
     79 public:
     80 #ifdef DEBUG
     81  // Returns the number of values pushed onto the value stack inside
     82  // `then_block` and `else_block`.
     83  // Can be used in assertion after emitting if-then-else.
     84  int32_t pushed() const { return pushed_; }
     85 
     86  // Returns the number of values popped onto the value stack inside
     87  // `then_block` and `else_block`.
     88  // Can be used in assertion after emitting if-then-else.
     89  int32_t popped() const { return -pushed_; }
     90 #endif
     91 };
     92 
     93 // Class for emitting bytecode for blocks like if-then-else.
     94 //
     95 // This class can be used to emit single if-then-else block, or cascading
     96 // else-if blocks.
     97 //
     98 // Usage: (check for the return value is omitted for simplicity)
     99 //
    100 //   `if (cond) then_block`
    101 //     IfEmitter ifThen(this);
    102 //     ifThen.emitIf(Some(offset_of_if));
    103 //     emit(cond);
    104 //     ifThen.emitThen();
    105 //     emit(then_block);
    106 //     ifThen.emitEnd();
    107 //
    108 //   `if (!cond) then_block`
    109 //     IfEmitter ifThen(this);
    110 //     ifThen.emitIf(Some(offset_of_if));
    111 //     emit(cond);
    112 //     ifThen.emitThen(IfEmitter::ConditionKind::Negative);
    113 //     emit(then_block);
    114 //     ifThen.emitEnd();
    115 //
    116 //   `if (cond) then_block else else_block`
    117 //     IfEmitter ifThenElse(this);
    118 //     ifThen.emitIf(Some(offset_of_if));
    119 //     emit(cond);
    120 //     ifThenElse.emitThenElse();
    121 //     emit(then_block);
    122 //     ifThenElse.emitElse();
    123 //     emit(else_block);
    124 //     ifThenElse.emitEnd();
    125 //
    126 //   `if (c1) b1 else if (c2) b2 else if (c3) b3 else b4`
    127 //     IfEmitter ifThenElse(this);
    128 //     ifThen.emitIf(Some(offset_of_if));
    129 //     emit(c1);
    130 //     ifThenElse.emitThenElse();
    131 //     emit(b1);
    132 //     ifThenElse.emitElseIf(Some(offset_of_if));
    133 //     emit(c2);
    134 //     ifThenElse.emitThenElse();
    135 //     emit(b2);
    136 //     ifThenElse.emitElseIf(Some(offset_of_if));
    137 //     emit(c3);
    138 //     ifThenElse.emitThenElse();
    139 //     emit(b3);
    140 //     ifThenElse.emitElse();
    141 //     emit(b4);
    142 //     ifThenElse.emitEnd();
    143 //
    144 class MOZ_STACK_CLASS IfEmitter : public BranchEmitterBase {
    145 public:
    146  using ConditionKind = BranchEmitterBase::ConditionKind;
    147 
    148 protected:
    149 #ifdef DEBUG
    150  // The state of this emitter.
    151  //
    152  // +-------+ emitIf +----+
    153  // | Start |------->| If |-+
    154  // +-------+        +----+ |
    155  //                         |
    156  //    +--------------------+
    157  //    |
    158  //    v emitThen +------+                               emitEnd +-----+
    159  // +->+--------->| Then |---------------------------->+-------->| End |
    160  // ^  |          +------+                             ^         +-----+
    161  // |  |                                               |
    162  // |  |                                               |
    163  // |  |                                               |
    164  // |  | emitThenElse +----------+   emitElse +------+ |
    165  // |  +------------->| ThenElse |-+--------->| Else |-+
    166  // |                 +----------+ |          +------+
    167  // |                              |
    168  // |                              | emitElseIf +--------+
    169  // |                              +----------->| ElseIf |-+
    170  // |                                           +--------+ |
    171  // |                                                      |
    172  // +------------------------------------------------------+
    173  enum class State {
    174    // The initial state.
    175    Start,
    176 
    177    // After calling emitIf.
    178    If,
    179 
    180    // After calling emitThen.
    181    Then,
    182 
    183    // After calling emitThenElse.
    184    ThenElse,
    185 
    186    // After calling emitElse.
    187    Else,
    188 
    189    // After calling emitElseIf.
    190    ElseIf,
    191 
    192    // After calling emitEnd.
    193    End
    194  };
    195  State state_ = State::Start;
    196 #endif
    197 
    198 protected:
    199  // For InternalIfEmitter.
    200  IfEmitter(BytecodeEmitter* bce, LexicalKind lexicalKind);
    201 
    202 public:
    203  explicit IfEmitter(BytecodeEmitter* bce);
    204 
    205  // `ifPos` is the offset in the source code for the character below:
    206  //
    207  //   if ( cond ) { ... } else if ( cond2 ) { ... }
    208  //   ^                        ^
    209  //   |                        |
    210  //   |                        ifPos for emitElseIf
    211  //   |
    212  //   ifPos for emitIf
    213  //
    214  // Can be Nothing() if not available.
    215  [[nodiscard]] bool emitIf(const mozilla::Maybe<uint32_t>& ifPos);
    216 
    217  [[nodiscard]] bool emitThen(
    218      ConditionKind conditionKind = ConditionKind::Positive);
    219  [[nodiscard]] bool emitThenElse(
    220      ConditionKind conditionKind = ConditionKind::Positive);
    221 
    222  [[nodiscard]] bool emitElseIf(const mozilla::Maybe<uint32_t>& ifPos);
    223  [[nodiscard]] bool emitElse();
    224 
    225  [[nodiscard]] bool emitEnd();
    226 };
    227 
    228 // Class for emitting bytecode for blocks like if-then-else which doesn't touch
    229 // lexical variables.
    230 //
    231 // See the comments above NoLexicalAccessInBranch for more details when to use
    232 // this instead of IfEmitter.
    233 // Compared to IfEmitter, this class doesn't have emitIf method, given that
    234 // it doesn't have syntactic `if`, and also the `cond` value can be already
    235 // on the stack.
    236 //
    237 // Usage: (check for the return value is omitted for simplicity)
    238 //
    239 //   `if (cond) then_block else else_block` (effectively)
    240 //     emit(cond);
    241 //     InternalIfEmitter ifThenElse(this);
    242 //     ifThenElse.emitThenElse();
    243 //     emit(then_block);
    244 //     ifThenElse.emitElse();
    245 //     emit(else_block);
    246 //     ifThenElse.emitEnd();
    247 //
    248 class MOZ_STACK_CLASS InternalIfEmitter : public IfEmitter {
    249 public:
    250  explicit InternalIfEmitter(
    251      BytecodeEmitter* bce,
    252      LexicalKind lexicalKind =
    253          BranchEmitterBase::LexicalKind::NoLexicalAccessInBranch);
    254 };
    255 
    256 // Class for emitting bytecode for conditional expression.
    257 //
    258 // Usage: (check for the return value is omitted for simplicity)
    259 //
    260 //   `cond ? then_expr : else_expr`
    261 //     CondEmitter condElse(this);
    262 //     condElse.emitCond();
    263 //     emit(cond);
    264 //     condElse.emitThenElse();
    265 //     emit(then_expr);
    266 //     condElse.emitElse();
    267 //     emit(else_expr);
    268 //     condElse.emitEnd();
    269 //
    270 class MOZ_STACK_CLASS CondEmitter : public BranchEmitterBase {
    271 #ifdef DEBUG
    272  // The state of this emitter.
    273  //
    274  // +-------+ emitCond +------+ emitThenElse +----------+
    275  // | Start |--------->| Cond |------------->| ThenElse |-+
    276  // +-------+          +------+              +----------+ |
    277  //                                                       |
    278  //                                     +-----------------+
    279  //                                     |
    280  //                                     | emitElse +------+ emitEnd +-----+
    281  //                                     +--------->| Else |-------->| End |
    282  //                                                +------+         +-----+
    283  enum class State {
    284    // The initial state.
    285    Start,
    286 
    287    // After calling emitCond.
    288    Cond,
    289 
    290    // After calling emitThenElse.
    291    ThenElse,
    292 
    293    // After calling emitElse.
    294    Else,
    295 
    296    // After calling emitEnd.
    297    End
    298  };
    299  State state_ = State::Start;
    300 #endif
    301 
    302 public:
    303  explicit CondEmitter(BytecodeEmitter* bce);
    304 
    305  [[nodiscard]] bool emitCond();
    306  [[nodiscard]] bool emitThenElse(
    307      ConditionKind conditionKind = ConditionKind::Positive);
    308  [[nodiscard]] bool emitElse();
    309  [[nodiscard]] bool emitEnd();
    310 };
    311 
    312 } /* namespace frontend */
    313 } /* namespace js */
    314 
    315 #endif /* frontend_IfEmitter_h */