tor-browser

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

BytecodeSection.h (12628B)


      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_BytecodeSection_h
      8 #define frontend_BytecodeSection_h
      9 
     10 #include "mozilla/Attributes.h"  // MOZ_STACK_CLASS
     11 #include "mozilla/Maybe.h"       // mozilla::Maybe
     12 #include "mozilla/Span.h"        // mozilla::Span
     13 
     14 #include <stddef.h>  // ptrdiff_t, size_t
     15 #include <stdint.h>  // uint16_t, int32_t, uint32_t
     16 
     17 #include "frontend/AbstractScopePtr.h"  // AbstractScopePtr, ScopeIndex
     18 #include "frontend/BytecodeOffset.h"    // BytecodeOffset
     19 #include "frontend/CompilationStencil.h"  // CompilationStencil, CompilationGCOutput, CompilationAtomCache
     20 #include "frontend/FrontendContext.h"  // FrontendContext
     21 #include "frontend/JumpList.h"         // JumpTarget
     22 #include "frontend/NameCollections.h"  // AtomIndexMap, PooledMapPtr
     23 #include "frontend/ParseNode.h"        // BigIntLiteral
     24 #include "frontend/ParserAtom.h"  // ParserAtomsTable, TaggedParserAtomIndex, ParserAtom
     25 #include "frontend/SourceNotes.h"  // SrcNote
     26 #include "frontend/Stencil.h"      // Stencils
     27 #include "js/ColumnNumber.h"       // JS::LimitedColumnNumberOneOrigin
     28 #include "js/TypeDecls.h"          // jsbytecode, JSContext
     29 #include "js/Vector.h"             // Vector
     30 #include "vm/SharedStencil.h"      // TryNote, ScopeNote, GCThingIndex
     31 #include "vm/StencilEnums.h"       // TryNoteKind
     32 
     33 namespace js {
     34 namespace frontend {
     35 
     36 class FunctionBox;
     37 
     38 struct MOZ_STACK_CLASS GCThingList {
     39  // The BCE accumulates TaggedScriptThingIndex items so use a vector type. We
     40  // reserve some stack slots to avoid allocating for most small scripts.
     41  using ScriptThingsStackVector = Vector<TaggedScriptThingIndex, 8>;
     42 
     43  CompilationState& compilationState;
     44  ScriptThingsStackVector vector;
     45 
     46  // Index of the first scope in the vector.
     47  mozilla::Maybe<GCThingIndex> firstScopeIndex;
     48 
     49  explicit GCThingList(FrontendContext* fc, CompilationState& compilationState)
     50      : compilationState(compilationState), vector(fc) {}
     51 
     52  [[nodiscard]] bool append(TaggedParserAtomIndex atom,
     53                            ParserAtom::Atomize atomize, GCThingIndex* index) {
     54    *index = GCThingIndex(vector.length());
     55    compilationState.parserAtoms.markUsedByStencil(atom, atomize);
     56    if (!vector.emplaceBack(atom)) {
     57      return false;
     58    }
     59    return true;
     60  }
     61  [[nodiscard]] bool append(ScopeIndex scope, GCThingIndex* index) {
     62    *index = GCThingIndex(vector.length());
     63    if (!vector.emplaceBack(scope)) {
     64      return false;
     65    }
     66    if (!firstScopeIndex) {
     67      firstScopeIndex.emplace(*index);
     68    }
     69    return true;
     70  }
     71  [[nodiscard]] bool append(BigIntLiteral* literal, GCThingIndex* index) {
     72    *index = GCThingIndex(vector.length());
     73    if (!vector.emplaceBack(literal->index())) {
     74      return false;
     75    }
     76    return true;
     77  }
     78  [[nodiscard]] bool append(RegExpLiteral* literal, GCThingIndex* index) {
     79    *index = GCThingIndex(vector.length());
     80    if (!vector.emplaceBack(literal->index())) {
     81      return false;
     82    }
     83    return true;
     84  }
     85  [[nodiscard]] bool append(ObjLiteralIndex objlit, GCThingIndex* index) {
     86    *index = GCThingIndex(vector.length());
     87    if (!vector.emplaceBack(objlit)) {
     88      return false;
     89    }
     90    return true;
     91  }
     92  [[nodiscard]] bool append(FunctionBox* funbox, GCThingIndex* index);
     93 
     94  [[nodiscard]] bool appendEmptyGlobalScope(GCThingIndex* index) {
     95    *index = GCThingIndex(vector.length());
     96    EmptyGlobalScopeType emptyGlobalScope;
     97    if (!vector.emplaceBack(emptyGlobalScope)) {
     98      return false;
     99    }
    100    if (!firstScopeIndex) {
    101      firstScopeIndex.emplace(*index);
    102    }
    103    return true;
    104  }
    105 
    106  uint32_t length() const { return vector.length(); }
    107 
    108  const ScriptThingsStackVector& objects() const { return vector; }
    109 
    110  AbstractScopePtr getScope(size_t index) const;
    111 
    112  // Index of scope within CompilationStencil or Nothing is the scope is
    113  // EmptyGlobalScopeType.
    114  mozilla::Maybe<ScopeIndex> getScopeIndex(size_t index) const;
    115 
    116  TaggedParserAtomIndex getAtom(size_t index) const;
    117 
    118  AbstractScopePtr firstScope() const {
    119    MOZ_ASSERT(firstScopeIndex.isSome());
    120    return getScope(*firstScopeIndex);
    121  }
    122 };
    123 
    124 [[nodiscard]] bool EmitScriptThingsVector(
    125    JSContext* cx, const CompilationAtomCache& atomCache,
    126    const CompilationStencil& stencil, CompilationGCOutput& gcOutput,
    127    mozilla::Span<const TaggedScriptThingIndex> things,
    128    mozilla::Span<JS::GCCellPtr> output);
    129 
    130 struct CGTryNoteList {
    131  Vector<TryNote, 0> list;
    132  explicit CGTryNoteList(FrontendContext* fc) : list(fc) {}
    133 
    134  [[nodiscard]] bool append(TryNoteKind kind, uint32_t stackDepth,
    135                            BytecodeOffset start, BytecodeOffset end);
    136  mozilla::Span<const TryNote> span() const {
    137    return {list.begin(), list.length()};
    138  }
    139  size_t length() const { return list.length(); }
    140 };
    141 
    142 struct CGScopeNoteList {
    143  Vector<ScopeNote, 0> list;
    144  explicit CGScopeNoteList(FrontendContext* fc) : list(fc) {}
    145 
    146  [[nodiscard]] bool append(GCThingIndex scopeIndex, BytecodeOffset offset,
    147                            uint32_t parent);
    148  void recordEnd(uint32_t index, BytecodeOffset offset);
    149  void recordEndFunctionBodyVar(uint32_t index);
    150  mozilla::Span<const ScopeNote> span() const {
    151    return {list.begin(), list.length()};
    152  }
    153  size_t length() const { return list.length(); }
    154 
    155 private:
    156  void recordEndImpl(uint32_t index, uint32_t offset);
    157 };
    158 
    159 struct CGResumeOffsetList {
    160  Vector<uint32_t, 0> list;
    161  explicit CGResumeOffsetList(FrontendContext* fc) : list(fc) {}
    162 
    163  [[nodiscard]] bool append(uint32_t offset) { return list.append(offset); }
    164  mozilla::Span<const uint32_t> span() const {
    165    return {list.begin(), list.length()};
    166  }
    167  size_t length() const { return list.length(); }
    168 };
    169 
    170 static constexpr size_t MaxBytecodeLength = INT32_MAX;
    171 static constexpr size_t MaxSrcNotesLength = INT32_MAX;
    172 
    173 // Have a few inline elements, so as to avoid heap allocation for tiny
    174 // sequences.  See bug 1390526.
    175 using BytecodeVector = Vector<jsbytecode, 64>;
    176 using SrcNotesVector = Vector<js::SrcNote, 64>;
    177 
    178 // Bytecode and all data directly associated with specific opcode/index inside
    179 // bytecode is stored in this class.
    180 class BytecodeSection {
    181 public:
    182  BytecodeSection(FrontendContext* fc, uint32_t lineNum,
    183                  JS::LimitedColumnNumberOneOrigin column);
    184 
    185  // ---- Bytecode ----
    186 
    187  BytecodeVector& code() { return code_; }
    188  const BytecodeVector& code() const { return code_; }
    189 
    190  jsbytecode* code(BytecodeOffset offset) {
    191    return code_.begin() + offset.value();
    192  }
    193  BytecodeOffset offset() const {
    194    return BytecodeOffset(code_.end() - code_.begin());
    195  }
    196 
    197  // ---- Source notes ----
    198 
    199  SrcNotesVector& notes() { return notes_; }
    200  const SrcNotesVector& notes() const { return notes_; }
    201 
    202  BytecodeOffset lastNoteOffset() const { return lastNoteOffset_; }
    203  void setLastNoteOffset(BytecodeOffset offset) { lastNoteOffset_ = offset; }
    204 
    205  // ---- Jump ----
    206 
    207  BytecodeOffset lastTargetOffset() const { return lastTarget_.offset; }
    208  void setLastTargetOffset(BytecodeOffset offset) {
    209    lastTarget_.offset = offset;
    210  }
    211 
    212  // ---- Stack ----
    213 
    214  int32_t stackDepth() const { return stackDepth_; }
    215  void setStackDepth(int32_t depth) { stackDepth_ = depth; }
    216 
    217  uint32_t maxStackDepth() const { return maxStackDepth_; }
    218 
    219  void updateDepth(JSOp op, BytecodeOffset target);
    220 
    221  // ---- Try notes ----
    222 
    223  CGTryNoteList& tryNoteList() { return tryNoteList_; };
    224  const CGTryNoteList& tryNoteList() const { return tryNoteList_; };
    225 
    226  // ---- Scope ----
    227 
    228  CGScopeNoteList& scopeNoteList() { return scopeNoteList_; };
    229  const CGScopeNoteList& scopeNoteList() const { return scopeNoteList_; };
    230 
    231  // ---- Generator ----
    232 
    233  CGResumeOffsetList& resumeOffsetList() { return resumeOffsetList_; }
    234  const CGResumeOffsetList& resumeOffsetList() const {
    235    return resumeOffsetList_;
    236  }
    237 
    238  uint32_t numYields() const { return numYields_; }
    239  void addNumYields() { numYields_++; }
    240 
    241  // ---- Line and column ----
    242 
    243  uint32_t currentLine() const { return currentLine_; }
    244  JS::LimitedColumnNumberOneOrigin lastColumn() const { return lastColumn_; }
    245  void setCurrentLine(uint32_t line, uint32_t sourceOffset) {
    246    currentLine_ = line;
    247    lastColumn_ = JS::LimitedColumnNumberOneOrigin();
    248    lastSourceOffset_ = sourceOffset;
    249  }
    250 
    251  void setLastColumn(JS::LimitedColumnNumberOneOrigin column, uint32_t offset) {
    252    lastColumn_ = column;
    253    lastSourceOffset_ = offset;
    254  }
    255 
    256  void updateSeparatorPosition() {
    257    lastSeparatorCodeOffset_ = code().length();
    258    lastSeparatorSourceOffset_ = lastSourceOffset_;
    259    lastSeparatorLine_ = currentLine_;
    260    lastSeparatorColumn_ = lastColumn_;
    261  }
    262 
    263  void updateSeparatorPositionIfPresent() {
    264    if (lastSeparatorCodeOffset_ == code().length()) {
    265      lastSeparatorSourceOffset_ = lastSourceOffset_;
    266      lastSeparatorLine_ = currentLine_;
    267      lastSeparatorColumn_ = lastColumn_;
    268    }
    269  }
    270 
    271  bool isDuplicateLocation() const {
    272    return lastSeparatorLine_ == currentLine_ &&
    273           lastSeparatorColumn_ == lastColumn_;
    274  }
    275 
    276  bool atSeparator(uint32_t offset) const {
    277    return lastSeparatorSourceOffset_ == offset;
    278  }
    279 
    280  // ---- JIT ----
    281 
    282  uint32_t numICEntries() const { return numICEntries_; }
    283  void incrementNumICEntries() {
    284    MOZ_ASSERT(numICEntries_ != UINT32_MAX, "Shouldn't overflow");
    285    numICEntries_++;
    286  }
    287  void setNumICEntries(uint32_t entries) { numICEntries_ = entries; }
    288 
    289 private:
    290  // ---- Bytecode ----
    291 
    292  // Bytecode.
    293  BytecodeVector code_;
    294 
    295  // ---- Source notes ----
    296 
    297  // Source notes
    298  SrcNotesVector notes_;
    299 
    300  // Code offset for last source note
    301  BytecodeOffset lastNoteOffset_;
    302 
    303  // ---- Jump ----
    304 
    305  // Last jump target emitted.
    306  JumpTarget lastTarget_;
    307 
    308  // ---- Stack ----
    309 
    310  // Maximum number of expression stack slots so far.
    311  uint32_t maxStackDepth_ = 0;
    312 
    313  // Current stack depth in script frame.
    314  int32_t stackDepth_ = 0;
    315 
    316  // ---- Try notes ----
    317 
    318  // List of emitted try notes.
    319  CGTryNoteList tryNoteList_;
    320 
    321  // ---- Scope ----
    322 
    323  // List of emitted block scope notes.
    324  CGScopeNoteList scopeNoteList_;
    325 
    326  // ---- Generator ----
    327 
    328  // Certain ops (yield, await) have an entry in the script's resumeOffsets
    329  // list. This can be used to map from the op's resumeIndex to the bytecode
    330  // offset of the next pc. This indirection makes it easy to resume in the JIT
    331  // (because BaselineScript stores a resumeIndex => native code array).
    332  CGResumeOffsetList resumeOffsetList_;
    333 
    334  // Number of yield instructions emitted. Does not include JSOp::Await.
    335  uint32_t numYields_ = 0;
    336 
    337  // ---- Line and column ----
    338 
    339  // Line number for srcnotes.
    340  //
    341  // WARNING: If this becomes out of sync with already-emitted srcnotes,
    342  // we can get undefined behavior.
    343  uint32_t currentLine_;
    344 
    345  // Column index in UTF-16 code units on currentLine_ of last
    346  // SrcNoteType::ColSpan-annotated opcode.
    347  //
    348  // WARNING: If this becomes out of sync with already-emitted srcnotes,
    349  // we can get undefined behavior.
    350  JS::LimitedColumnNumberOneOrigin lastColumn_;
    351 
    352  // The last code unit used for srcnotes.
    353  uint32_t lastSourceOffset_ = 0;
    354 
    355  // The offset, line and column numbers of the last opcode for the
    356  // breakpoint for step execution.
    357  uint32_t lastSeparatorCodeOffset_ = 0;
    358  uint32_t lastSeparatorSourceOffset_ = 0;
    359  uint32_t lastSeparatorLine_ = 0;
    360  JS::LimitedColumnNumberOneOrigin lastSeparatorColumn_;
    361 
    362  // ---- JIT ----
    363 
    364  // Number of ICEntries in the script. There's one ICEntry for each JOF_IC op
    365  // and, if the script is a function, for |this| and each formal argument.
    366  uint32_t numICEntries_ = 0;
    367 };
    368 
    369 // Data that is not directly associated with specific opcode/index inside
    370 // bytecode, but referred from bytecode is stored in this class.
    371 class PerScriptData {
    372 public:
    373  PerScriptData(FrontendContext* fc,
    374                frontend::CompilationState& compilationState);
    375 
    376  [[nodiscard]] bool init(FrontendContext* fc);
    377 
    378  GCThingList& gcThingList() { return gcThingList_; }
    379  const GCThingList& gcThingList() const { return gcThingList_; }
    380 
    381  PooledMapPtr<AtomIndexMap>& atomIndices() { return atomIndices_; }
    382  const PooledMapPtr<AtomIndexMap>& atomIndices() const { return atomIndices_; }
    383 
    384 private:
    385  // List of emitted scopes/objects/bigints.
    386  GCThingList gcThingList_;
    387 
    388  // Map from atom to index.
    389  PooledMapPtr<AtomIndexMap> atomIndices_;
    390 };
    391 
    392 } /* namespace frontend */
    393 } /* namespace js */
    394 
    395 #endif /* frontend_BytecodeSection_h */