tor-browser

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

BytecodeSection.cpp (6489B)


      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 #include "frontend/BytecodeSection.h"
      8 
      9 #include "mozilla/Assertions.h"  // MOZ_ASSERT
     10 
     11 #include "frontend/AbstractScopePtr.h"    // ScopeIndex
     12 #include "frontend/CompilationStencil.h"  // CompilationStencil
     13 #include "frontend/FrontendContext.h"     // FrontendContext
     14 #include "frontend/SharedContext.h"       // FunctionBox
     15 #include "js/ColumnNumber.h"              // JS::LimitedColumnNumberOneOrigin
     16 #include "vm/BytecodeUtil.h"              // INDEX_LIMIT, StackUses, StackDefs
     17 #include "vm/GlobalObject.h"
     18 #include "vm/JSContext.h"     // JSContext
     19 #include "vm/RegExpObject.h"  // RegexpObject
     20 #include "vm/Scope.h"         // GlobalScope
     21 
     22 using namespace js;
     23 using namespace js::frontend;
     24 
     25 bool GCThingList::append(FunctionBox* funbox, GCThingIndex* index) {
     26  // Append the function to the vector and return the index in *index.
     27  *index = GCThingIndex(vector.length());
     28 
     29  if (!vector.emplaceBack(funbox->index())) {
     30    return false;
     31  }
     32  return true;
     33 }
     34 
     35 AbstractScopePtr GCThingList::getScope(size_t index) const {
     36  const TaggedScriptThingIndex& elem = vector[index];
     37  if (elem.isEmptyGlobalScope()) {
     38    // The empty enclosing scope should be stored by
     39    // CompilationInput::initForSelfHostingGlobal.
     40    return AbstractScopePtr::compilationEnclosingScope(compilationState);
     41  }
     42  return AbstractScopePtr(compilationState, elem.toScope());
     43 }
     44 
     45 mozilla::Maybe<ScopeIndex> GCThingList::getScopeIndex(size_t index) const {
     46  const TaggedScriptThingIndex& elem = vector[index];
     47  if (elem.isEmptyGlobalScope()) {
     48    return mozilla::Nothing();
     49  }
     50  return mozilla::Some(vector[index].toScope());
     51 }
     52 
     53 TaggedParserAtomIndex GCThingList::getAtom(size_t index) const {
     54  const TaggedScriptThingIndex& elem = vector[index];
     55  return elem.toAtom();
     56 }
     57 
     58 bool js::frontend::EmitScriptThingsVector(
     59    JSContext* cx, const CompilationAtomCache& atomCache,
     60    const CompilationStencil& stencil, CompilationGCOutput& gcOutput,
     61    mozilla::Span<const TaggedScriptThingIndex> things,
     62    mozilla::Span<JS::GCCellPtr> output) {
     63  MOZ_ASSERT(things.size() <= INDEX_LIMIT);
     64  MOZ_ASSERT(things.size() == output.size());
     65 
     66  for (uint32_t i = 0; i < things.size(); i++) {
     67    const auto& thing = things[i];
     68    switch (thing.tag()) {
     69      case TaggedScriptThingIndex::Kind::ParserAtomIndex:
     70      case TaggedScriptThingIndex::Kind::WellKnown: {
     71        JSString* str = atomCache.getExistingStringAt(cx, thing.toAtom());
     72        MOZ_ASSERT(str);
     73        output[i] = JS::GCCellPtr(str);
     74        break;
     75      }
     76      case TaggedScriptThingIndex::Kind::Null:
     77        output[i] = JS::GCCellPtr(nullptr);
     78        break;
     79      case TaggedScriptThingIndex::Kind::BigInt: {
     80        const BigIntStencil& data = stencil.bigIntData[thing.toBigInt()];
     81        BigInt* bi = data.createBigInt(cx);
     82        if (!bi) {
     83          return false;
     84        }
     85        output[i] = JS::GCCellPtr(bi);
     86        break;
     87      }
     88      case TaggedScriptThingIndex::Kind::ObjLiteral: {
     89        const ObjLiteralStencil& data =
     90            stencil.objLiteralData[thing.toObjLiteral()];
     91        JS::GCCellPtr ptr = data.create(cx, atomCache);
     92        if (!ptr) {
     93          return false;
     94        }
     95        output[i] = ptr;
     96        break;
     97      }
     98      case TaggedScriptThingIndex::Kind::RegExp: {
     99        RegExpStencil& data = stencil.regExpData[thing.toRegExp()];
    100        RegExpObject* regexp = data.createRegExp(cx, atomCache);
    101        if (!regexp) {
    102          return false;
    103        }
    104        output[i] = JS::GCCellPtr(regexp);
    105        break;
    106      }
    107      case TaggedScriptThingIndex::Kind::Scope:
    108        output[i] = JS::GCCellPtr(gcOutput.getScope(thing.toScope()));
    109        break;
    110      case TaggedScriptThingIndex::Kind::Function:
    111        output[i] = JS::GCCellPtr(gcOutput.getFunction(thing.toFunction()));
    112        break;
    113      case TaggedScriptThingIndex::Kind::EmptyGlobalScope: {
    114        Scope* scope = &cx->global()->emptyGlobalScope();
    115        output[i] = JS::GCCellPtr(scope);
    116        break;
    117      }
    118    }
    119  }
    120 
    121  return true;
    122 }
    123 
    124 bool CGTryNoteList::append(TryNoteKind kind, uint32_t stackDepth,
    125                           BytecodeOffset start, BytecodeOffset end) {
    126  MOZ_ASSERT(start <= end);
    127 
    128  // Offsets are given relative to sections, but we only expect main-section
    129  // to have TryNotes. In finish() we will fixup base offset.
    130 
    131  TryNote note(uint32_t(kind), stackDepth, start.toUint32(),
    132               (end - start).toUint32());
    133 
    134  return list.append(note);
    135 }
    136 
    137 bool CGScopeNoteList::append(GCThingIndex scopeIndex, BytecodeOffset offset,
    138                             uint32_t parent) {
    139  ScopeNote note;
    140  note.index = scopeIndex;
    141  note.start = offset.toUint32();
    142  note.length = 0;
    143  note.parent = parent;
    144 
    145  return list.append(note);
    146 }
    147 
    148 void CGScopeNoteList::recordEnd(uint32_t index, BytecodeOffset offset) {
    149  recordEndImpl(index, offset.toUint32());
    150 }
    151 
    152 void CGScopeNoteList::recordEndFunctionBodyVar(uint32_t index) {
    153  recordEndImpl(index, UINT32_MAX);
    154 }
    155 
    156 void CGScopeNoteList::recordEndImpl(uint32_t index, uint32_t offset) {
    157  MOZ_ASSERT(index < length());
    158  MOZ_ASSERT(list[index].length == 0);
    159  MOZ_ASSERT(offset >= list[index].start);
    160  list[index].length = offset - list[index].start;
    161 }
    162 
    163 BytecodeSection::BytecodeSection(FrontendContext* fc, uint32_t lineNum,
    164                                 JS::LimitedColumnNumberOneOrigin column)
    165    : code_(fc),
    166      notes_(fc),
    167      lastNoteOffset_(0),
    168      tryNoteList_(fc),
    169      scopeNoteList_(fc),
    170      resumeOffsetList_(fc),
    171      currentLine_(lineNum),
    172      lastColumn_(column) {}
    173 
    174 void BytecodeSection::updateDepth(JSOp op, BytecodeOffset target) {
    175  jsbytecode* pc = code(target);
    176 
    177  int nuses = StackUses(op, pc);
    178  int ndefs = StackDefs(op);
    179 
    180  stackDepth_ -= nuses;
    181  MOZ_ASSERT(stackDepth_ >= 0);
    182  stackDepth_ += ndefs;
    183 
    184  if (uint32_t(stackDepth_) > maxStackDepth_) {
    185    maxStackDepth_ = stackDepth_;
    186  }
    187 }
    188 
    189 PerScriptData::PerScriptData(FrontendContext* fc,
    190                             frontend::CompilationState& compilationState)
    191    : gcThingList_(fc, compilationState),
    192      atomIndices_(fc->nameCollectionPool()) {}
    193 
    194 bool PerScriptData::init(FrontendContext* fc) {
    195  return atomIndices_.acquire(fc);
    196 }