summaryrefslogtreecommitdiffstats
path: root/js/src/frontend/BytecodeSection.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/frontend/BytecodeSection.cpp')
-rw-r--r--js/src/frontend/BytecodeSection.cpp197
1 files changed, 197 insertions, 0 deletions
diff --git a/js/src/frontend/BytecodeSection.cpp b/js/src/frontend/BytecodeSection.cpp
new file mode 100644
index 0000000000..2391656405
--- /dev/null
+++ b/js/src/frontend/BytecodeSection.cpp
@@ -0,0 +1,197 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: set ts=8 sts=2 et sw=2 tw=80:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "frontend/BytecodeSection.h"
+
+#include "mozilla/Assertions.h" // MOZ_ASSERT
+#include "mozilla/ReverseIterator.h" // mozilla::Reversed
+
+#include "frontend/AbstractScopePtr.h" // ScopeIndex
+#include "frontend/CompilationInfo.h"
+#include "frontend/SharedContext.h" // FunctionBox
+#include "vm/BytecodeUtil.h" // INDEX_LIMIT, StackUses, StackDefs
+#include "vm/GlobalObject.h"
+#include "vm/JSContext.h" // JSContext
+#include "vm/RegExpObject.h" // RegexpObject
+#include "vm/Scope.h" // GlobalScope
+
+using namespace js;
+using namespace js::frontend;
+
+bool GCThingList::append(FunctionBox* funbox, GCThingIndex* index) {
+ // Append the function to the vector and return the index in *index.
+ *index = GCThingIndex(vector.length());
+
+ if (!vector.emplaceBack(funbox->index())) {
+ return false;
+ }
+ return true;
+}
+
+AbstractScopePtr GCThingList::getScope(size_t index) const {
+ const TaggedScriptThingIndex& elem = vector[index];
+ if (elem.isEmptyGlobalScope()) {
+ // The empty enclosing scope should be stored by
+ // CompilationInput::initForSelfHostingGlobal.
+ MOZ_ASSERT(stencil.input.enclosingScope);
+ MOZ_ASSERT(!stencil.input.enclosingScope->as<GlobalScope>().hasBindings());
+ return AbstractScopePtr(stencil.input.enclosingScope);
+ }
+ return AbstractScopePtr(compilationState, elem.toScope());
+}
+
+mozilla::Maybe<ScopeIndex> GCThingList::getScopeIndex(size_t index) const {
+ const TaggedScriptThingIndex& elem = vector[index];
+ if (elem.isEmptyGlobalScope()) {
+ return mozilla::Nothing();
+ }
+ return mozilla::Some(vector[index].toScope());
+}
+
+bool js::frontend::EmitScriptThingsVector(
+ JSContext* cx, CompilationInput& input, BaseCompilationStencil& stencil,
+ CompilationGCOutput& gcOutput,
+ mozilla::Span<const TaggedScriptThingIndex> things,
+ mozilla::Span<JS::GCCellPtr> output) {
+ MOZ_ASSERT(things.size() <= INDEX_LIMIT);
+ MOZ_ASSERT(things.size() == output.size());
+
+ auto& atomCache = input.atomCache;
+
+ for (uint32_t i = 0; i < things.size(); i++) {
+ const auto& thing = things[i];
+ switch (thing.tag()) {
+ case TaggedScriptThingIndex::Kind::ParserAtomIndex:
+ case TaggedScriptThingIndex::Kind::WellKnown: {
+ JSAtom* atom = atomCache.getExistingAtomAt(cx, thing.toAtom());
+ MOZ_ASSERT(atom);
+ output[i] = JS::GCCellPtr(atom);
+ break;
+ }
+ case TaggedScriptThingIndex::Kind::Null:
+ output[i] = JS::GCCellPtr(nullptr);
+ break;
+ case TaggedScriptThingIndex::Kind::BigInt: {
+ BigIntStencil& data = stencil.bigIntData[thing.toBigInt()];
+ BigInt* bi = data.createBigInt(cx);
+ if (!bi) {
+ return false;
+ }
+ output[i] = JS::GCCellPtr(bi);
+ break;
+ }
+ case TaggedScriptThingIndex::Kind::ObjLiteral: {
+ ObjLiteralStencil& data = stencil.objLiteralData[thing.toObjLiteral()];
+ JSObject* obj = data.create(cx, atomCache);
+ if (!obj) {
+ return false;
+ }
+ output[i] = JS::GCCellPtr(obj);
+ break;
+ }
+ case TaggedScriptThingIndex::Kind::RegExp: {
+ RegExpStencil& data = stencil.regExpData[thing.toRegExp()];
+ RegExpObject* regexp = data.createRegExp(cx, atomCache);
+ if (!regexp) {
+ return false;
+ }
+ output[i] = JS::GCCellPtr(regexp);
+ break;
+ }
+ case TaggedScriptThingIndex::Kind::Scope:
+ output[i] = JS::GCCellPtr(gcOutput.scopes[thing.toScope()]);
+ break;
+ case TaggedScriptThingIndex::Kind::Function:
+ output[i] = JS::GCCellPtr(gcOutput.functions[thing.toFunction()]);
+ break;
+ case TaggedScriptThingIndex::Kind::EmptyGlobalScope: {
+ Scope* scope = &cx->global()->emptyGlobalScope();
+ output[i] = JS::GCCellPtr(scope);
+ break;
+ }
+ }
+ }
+
+ return true;
+}
+
+bool CGTryNoteList::append(TryNoteKind kind, uint32_t stackDepth,
+ BytecodeOffset start, BytecodeOffset end) {
+ MOZ_ASSERT(start <= end);
+
+ // Offsets are given relative to sections, but we only expect main-section
+ // to have TryNotes. In finish() we will fixup base offset.
+
+ TryNote note(uint32_t(kind), stackDepth, start.toUint32(),
+ (end - start).toUint32());
+
+ return list.append(note);
+}
+
+bool CGScopeNoteList::append(GCThingIndex scopeIndex, BytecodeOffset offset,
+ uint32_t parent) {
+ ScopeNote note;
+ note.index = scopeIndex;
+ note.start = offset.toUint32();
+ note.length = 0;
+ note.parent = parent;
+
+ return list.append(note);
+}
+
+void CGScopeNoteList::recordEnd(uint32_t index, BytecodeOffset offset) {
+ recordEndImpl(index, offset.toUint32());
+}
+
+void CGScopeNoteList::recordEndFunctionBodyVar(uint32_t index) {
+ recordEndImpl(index, UINT32_MAX);
+}
+
+void CGScopeNoteList::recordEndImpl(uint32_t index, uint32_t offset) {
+ MOZ_ASSERT(index < length());
+ MOZ_ASSERT(list[index].length == 0);
+ MOZ_ASSERT(offset >= list[index].start);
+ list[index].length = offset - list[index].start;
+}
+
+JSObject* ObjLiteralStencil::create(JSContext* cx,
+ CompilationAtomCache& atomCache) const {
+ return InterpretObjLiteral(cx, atomCache, code_, flags_);
+}
+
+BytecodeSection::BytecodeSection(JSContext* cx, uint32_t lineNum,
+ uint32_t column)
+ : code_(cx),
+ notes_(cx),
+ lastNoteOffset_(0),
+ tryNoteList_(cx),
+ scopeNoteList_(cx),
+ resumeOffsetList_(cx),
+ currentLine_(lineNum),
+ lastColumn_(column) {}
+
+void BytecodeSection::updateDepth(BytecodeOffset target) {
+ jsbytecode* pc = code(target);
+
+ int nuses = StackUses(pc);
+ int ndefs = StackDefs(pc);
+
+ stackDepth_ -= nuses;
+ MOZ_ASSERT(stackDepth_ >= 0);
+ stackDepth_ += ndefs;
+
+ if (uint32_t(stackDepth_) > maxStackDepth_) {
+ maxStackDepth_ = stackDepth_;
+ }
+}
+
+PerScriptData::PerScriptData(JSContext* cx,
+ frontend::CompilationStencil& stencil,
+ frontend::CompilationState& compilationState)
+ : gcThingList_(cx, stencil, compilationState),
+ atomIndices_(cx->frontendCollectionPool()) {}
+
+bool PerScriptData::init(JSContext* cx) { return atomIndices_.acquire(cx); }