tor-browser

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

BytecodeControlStructures.h (6560B)


      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_BytecodeControlStructures_h
      8 #define frontend_BytecodeControlStructures_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 <stdint.h>  // int32_t, uint32_t
     15 
     16 #include "ds/Nestable.h"              // Nestable
     17 #include "frontend/BytecodeOffset.h"  // BytecodeOffset
     18 #include "frontend/JumpList.h"        // JumpList, JumpTarget
     19 #include "frontend/ParserAtom.h"      // TaggedParserAtomIndex
     20 #include "frontend/SharedContext.h"  // StatementKind, StatementKindIsLoop, StatementKindIsUnlabeledBreakTarget
     21 #include "frontend/TDZCheckCache.h"  // TDZCheckCache
     22 #include "vm/StencilEnums.h"         // TryNoteKind
     23 
     24 namespace js {
     25 namespace frontend {
     26 
     27 struct BytecodeEmitter;
     28 class EmitterScope;
     29 
     30 // This class just like Nestable is not annotated with MOZ_STACK_CLASS
     31 // in order to allow specific cases where subclasses need to be
     32 // be allocated on heap.
     33 class NestableControl : public Nestable<NestableControl> {
     34  StatementKind kind_;
     35 
     36  // The innermost scope when this was pushed.
     37  EmitterScope* emitterScope_;
     38 
     39 protected:
     40  NestableControl(BytecodeEmitter* bce, StatementKind kind);
     41 
     42 public:
     43  using Nestable<NestableControl>::enclosing;
     44  using Nestable<NestableControl>::findNearest;
     45 
     46  StatementKind kind() const { return kind_; }
     47 
     48  EmitterScope* emitterScope() const { return emitterScope_; }
     49 
     50  template <typename T>
     51  bool is() const;
     52 
     53  template <typename T>
     54  T& as() {
     55    MOZ_ASSERT(this->is<T>());
     56    return static_cast<T&>(*this);
     57  }
     58 };
     59 
     60 class MOZ_STACK_CLASS BreakableControl : public NestableControl {
     61 public:
     62  // Offset of the last break.
     63  JumpList breaks;
     64 
     65  BreakableControl(BytecodeEmitter* bce, StatementKind kind);
     66 
     67  [[nodiscard]] bool patchBreaks(BytecodeEmitter* bce);
     68 };
     69 template <>
     70 inline bool NestableControl::is<BreakableControl>() const {
     71  return StatementKindIsUnlabeledBreakTarget(kind_) ||
     72         kind_ == StatementKind::Label;
     73 }
     74 
     75 class MOZ_STACK_CLASS LabelControl : public BreakableControl {
     76  TaggedParserAtomIndex label_;
     77 
     78  // The code offset when this was pushed. Used for effectfulness checking.
     79  BytecodeOffset startOffset_;
     80 
     81 public:
     82  LabelControl(BytecodeEmitter* bce, TaggedParserAtomIndex label,
     83               BytecodeOffset startOffset);
     84 
     85  TaggedParserAtomIndex label() const { return label_; }
     86 
     87  BytecodeOffset startOffset() const { return startOffset_; }
     88 };
     89 template <>
     90 inline bool NestableControl::is<LabelControl>() const {
     91  return kind_ == StatementKind::Label;
     92 }
     93 
     94 class LoopControl : public BreakableControl {
     95  // Loops' children are emitted in dominance order, so they can always
     96  // have a TDZCheckCache.
     97  TDZCheckCache tdzCache_;
     98 
     99  // Here's the basic structure of a loop:
    100  //
    101  //   head:
    102  //     JSOp::LoopHead
    103  //     {loop condition/body}
    104  //
    105  //   continueTarget:
    106  //     {loop update if present}
    107  //
    108  //     # Loop end, backward jump
    109  //     JSOp::Goto/JSOp::JumpIfTrue head
    110  //
    111  //   breakTarget:
    112 
    113  // The bytecode offset of JSOp::LoopHead.
    114  JumpTarget head_;
    115 
    116  // Stack depth when this loop was pushed on the control stack.
    117  int32_t stackDepth_;
    118 
    119  // The loop nesting depth. Used as a hint to Ion.
    120  uint32_t loopDepth_;
    121 
    122 public:
    123  // Offset of the last continue in the loop.
    124  JumpList continues;
    125 
    126  LoopControl(BytecodeEmitter* bce, StatementKind loopKind);
    127 
    128  BytecodeOffset headOffset() const { return head_.offset; }
    129 
    130  [[nodiscard]] bool emitContinueTarget(BytecodeEmitter* bce);
    131 
    132  // `nextPos` is the offset in the source code for the character that
    133  // corresponds to the next instruction after JSOp::LoopHead.
    134  // Can be Nothing() if not available.
    135  [[nodiscard]] bool emitLoopHead(BytecodeEmitter* bce,
    136                                  const mozilla::Maybe<uint32_t>& nextPos);
    137 
    138  [[nodiscard]] bool emitLoopEnd(BytecodeEmitter* bce, JSOp op,
    139                                 TryNoteKind tryNoteKind);
    140 };
    141 template <>
    142 inline bool NestableControl::is<LoopControl>() const {
    143  return StatementKindIsLoop(kind_);
    144 }
    145 
    146 enum class NonLocalExitKind { Continue, Break, Return };
    147 
    148 class TryFinallyContinuation {
    149 public:
    150  TryFinallyContinuation(NestableControl* target, NonLocalExitKind kind)
    151      : target_(target), kind_(kind) {}
    152 
    153  NestableControl* target_;
    154  NonLocalExitKind kind_;
    155 };
    156 
    157 // TryFinallyControl is not annotated with MOZ_STACK_CLASS in order to allow
    158 // for TryEmitter to be allocated on heap which uses this class to track jumps
    159 // to the finally block.
    160 class TryFinallyControl : public NestableControl {
    161  bool emittingSubroutine_ = false;
    162 
    163 public:
    164  // Offset of the last jump to this `finally`.
    165  JumpList finallyJumps_;
    166 
    167  js::Vector<TryFinallyContinuation, 4, SystemAllocPolicy> continuations_;
    168 
    169  TryFinallyControl(BytecodeEmitter* bce, StatementKind kind);
    170 
    171  void setEmittingSubroutine() { emittingSubroutine_ = true; }
    172 
    173  bool emittingSubroutine() const { return emittingSubroutine_; }
    174 
    175  enum SpecialContinuations { Fallthrough, Count };
    176  bool allocateContinuation(NestableControl* target, NonLocalExitKind kind,
    177                            uint32_t* idx);
    178  bool emitContinuations(BytecodeEmitter* bce);
    179 };
    180 template <>
    181 inline bool NestableControl::is<TryFinallyControl>() const {
    182  return kind_ == StatementKind::Try || kind_ == StatementKind::Finally;
    183 }
    184 
    185 class NonLocalExitControl {
    186  BytecodeEmitter* bce_;
    187  const uint32_t savedScopeNoteIndex_;
    188  const int savedDepth_;
    189  uint32_t openScopeNoteIndex_;
    190  NonLocalExitKind kind_;
    191 
    192  // The offset of a `JSOp::SetRval` that can be rewritten as a
    193  // `JSOp::Return` if we don't generate any code for this
    194  // NonLocalExitControl.
    195  BytecodeOffset setRvalOffset_ = BytecodeOffset::invalidOffset();
    196 
    197  [[nodiscard]] bool leaveScope(EmitterScope* es);
    198 
    199 public:
    200  NonLocalExitControl(const NonLocalExitControl&) = delete;
    201  NonLocalExitControl(BytecodeEmitter* bce, NonLocalExitKind kind);
    202  ~NonLocalExitControl();
    203 
    204  [[nodiscard]] bool emitNonLocalJump(NestableControl* target,
    205                                      NestableControl* startingAfter = nullptr);
    206  [[nodiscard]] bool emitReturn(BytecodeOffset setRvalOffset);
    207 };
    208 
    209 } /* namespace frontend */
    210 } /* namespace js */
    211 
    212 #endif /* frontend_BytecodeControlStructures_h */