summaryrefslogtreecommitdiffstats
path: root/js/src/frontend/SharedContext.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/frontend/SharedContext.cpp')
-rw-r--r--js/src/frontend/SharedContext.cpp409
1 files changed, 409 insertions, 0 deletions
diff --git a/js/src/frontend/SharedContext.cpp b/js/src/frontend/SharedContext.cpp
new file mode 100644
index 0000000000..7fa3b724fb
--- /dev/null
+++ b/js/src/frontend/SharedContext.cpp
@@ -0,0 +1,409 @@
+/* -*- 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/SharedContext.h"
+
+#include "mozilla/RefPtr.h"
+
+#include "frontend/CompilationStencil.h"
+#include "frontend/FunctionSyntaxKind.h" // FunctionSyntaxKind
+#include "frontend/ModuleSharedContext.h"
+#include "frontend/ParseContext.h"
+#include "frontend/ParseNode.h"
+#include "frontend/ParserAtom.h"
+#include "frontend/ScopeIndex.h"
+#include "frontend/ScriptIndex.h"
+#include "frontend/Stencil.h"
+#include "js/CompileOptions.h"
+#include "js/Vector.h"
+#include "vm/FunctionFlags.h" // js::FunctionFlags
+#include "vm/GeneratorAndAsyncKind.h" // js::GeneratorKind, js::FunctionAsyncKind
+#include "vm/JSScript.h" // js::FillImmutableFlagsFromCompileOptionsForTopLevel, js::FillImmutableFlagsFromCompileOptionsForFunction
+#include "vm/StencilEnums.h" // ImmutableScriptFlagsEnum
+
+#include "frontend/ParseContext-inl.h"
+
+namespace js {
+
+class ModuleBuilder;
+
+namespace frontend {
+
+SharedContext::SharedContext(FrontendContext* fc, Kind kind,
+ const JS::ReadOnlyCompileOptions& options,
+ Directives directives, SourceExtent extent)
+ : fc_(fc),
+ extent_(extent),
+ allowNewTarget_(false),
+ allowSuperProperty_(false),
+ allowSuperCall_(false),
+ allowArguments_(true),
+ inWith_(false),
+ inClass_(false),
+ localStrict(false),
+ hasExplicitUseStrict_(false),
+ isScriptExtraFieldCopiedToStencil(false) {
+ // Compute the script kind "input" flags.
+ if (kind == Kind::FunctionBox) {
+ setFlag(ImmutableFlags::IsFunction);
+ } else if (kind == Kind::Module) {
+ MOZ_ASSERT(!options.nonSyntacticScope);
+ setFlag(ImmutableFlags::IsModule);
+ } else if (kind == Kind::Eval) {
+ setFlag(ImmutableFlags::IsForEval);
+ } else {
+ MOZ_ASSERT(kind == Kind::Global);
+ }
+
+ // Initialize the transitive "input" flags. These are applied to all
+ // SharedContext in this compilation and generally cannot be determined from
+ // the source text alone.
+ if (isTopLevelContext()) {
+ js::FillImmutableFlagsFromCompileOptionsForTopLevel(options,
+ immutableFlags_);
+ } else {
+ js::FillImmutableFlagsFromCompileOptionsForFunction(options,
+ immutableFlags_);
+ }
+
+ // Initialize the strict flag. This may be updated by the parser as we observe
+ // further directives in the body.
+ setFlag(ImmutableFlags::Strict, directives.strict());
+}
+
+GlobalSharedContext::GlobalSharedContext(
+ FrontendContext* fc, ScopeKind scopeKind,
+ const JS::ReadOnlyCompileOptions& options, Directives directives,
+ SourceExtent extent)
+ : SharedContext(fc, Kind::Global, options, directives, extent),
+ scopeKind_(scopeKind),
+ bindings(nullptr) {
+ MOZ_ASSERT(scopeKind == ScopeKind::Global ||
+ scopeKind == ScopeKind::NonSyntactic);
+ MOZ_ASSERT(thisBinding_ == ThisBinding::Global);
+}
+
+EvalSharedContext::EvalSharedContext(FrontendContext* fc,
+ CompilationState& compilationState,
+ SourceExtent extent)
+ : SharedContext(fc, Kind::Eval, compilationState.input.options,
+ compilationState.directives, extent),
+ bindings(nullptr) {
+ // Eval inherits syntax and binding rules from enclosing environment.
+ allowNewTarget_ = compilationState.scopeContext.allowNewTarget;
+ allowSuperProperty_ = compilationState.scopeContext.allowSuperProperty;
+ allowSuperCall_ = compilationState.scopeContext.allowSuperCall;
+ allowArguments_ = compilationState.scopeContext.allowArguments;
+ thisBinding_ = compilationState.scopeContext.thisBinding;
+ inWith_ = compilationState.scopeContext.inWith;
+}
+
+SuspendableContext::SuspendableContext(
+ FrontendContext* fc, Kind kind, const JS::ReadOnlyCompileOptions& options,
+ Directives directives, SourceExtent extent, bool isGenerator, bool isAsync)
+ : SharedContext(fc, kind, options, directives, extent) {
+ setFlag(ImmutableFlags::IsGenerator, isGenerator);
+ setFlag(ImmutableFlags::IsAsync, isAsync);
+}
+
+FunctionBox::FunctionBox(FrontendContext* fc, SourceExtent extent,
+ CompilationState& compilationState,
+ Directives directives, GeneratorKind generatorKind,
+ FunctionAsyncKind asyncKind, bool isInitialCompilation,
+ TaggedParserAtomIndex atom, FunctionFlags flags,
+ ScriptIndex index)
+ : SuspendableContext(fc, Kind::FunctionBox, compilationState.input.options,
+ directives, extent,
+ generatorKind == GeneratorKind::Generator,
+ asyncKind == FunctionAsyncKind::AsyncFunction),
+ compilationState_(compilationState),
+ atom_(atom),
+ funcDataIndex_(index),
+ flags_(FunctionFlags::clearMutableflags(flags)),
+ emitBytecode(false),
+ wasEmittedByEnclosingScript_(false),
+ isAnnexB(false),
+ useAsm(false),
+ hasParameterExprs(false),
+ hasDestructuringArgs(false),
+ hasDuplicateParameters(false),
+ hasExprBody_(false),
+ allowReturn_(true),
+ isFunctionFieldCopiedToStencil(false),
+ isInitialCompilation(isInitialCompilation),
+ isStandalone(false) {}
+
+void FunctionBox::initFromLazyFunction(const ScriptStencilExtra& extra,
+ ScopeContext& scopeContext,
+ FunctionSyntaxKind kind) {
+ initFromScriptStencilExtra(extra);
+ initStandaloneOrLazy(scopeContext, kind);
+}
+
+void FunctionBox::initFromScriptStencilExtra(const ScriptStencilExtra& extra) {
+ immutableFlags_ = extra.immutableFlags;
+ extent_ = extra.extent;
+}
+
+void FunctionBox::initWithEnclosingParseContext(ParseContext* enclosing,
+ FunctionSyntaxKind kind) {
+ SharedContext* sc = enclosing->sc();
+
+ // HasModuleGoal and useAsm are inherited from enclosing context.
+ useAsm = sc->isFunctionBox() && sc->asFunctionBox()->useAsmOrInsideUseAsm();
+ setHasModuleGoal(sc->hasModuleGoal());
+
+ // Arrow functions don't have their own `this` binding.
+ if (flags_.isArrow()) {
+ allowNewTarget_ = sc->allowNewTarget();
+ allowSuperProperty_ = sc->allowSuperProperty();
+ allowSuperCall_ = sc->allowSuperCall();
+ allowArguments_ = sc->allowArguments();
+ thisBinding_ = sc->thisBinding();
+ } else {
+ if (IsConstructorKind(kind)) {
+ // Record this function into the enclosing class statement so that
+ // finishClassConstructor can final processing. Due to aborted syntax
+ // parses (eg, because of asm.js), this may have already been set with an
+ // early FunctionBox. In that case, the FunctionNode should still match.
+ auto classStmt =
+ enclosing->findInnermostStatement<ParseContext::ClassStatement>();
+ MOZ_ASSERT(classStmt);
+ MOZ_ASSERT(classStmt->constructorBox == nullptr ||
+ classStmt->constructorBox->functionNode == this->functionNode);
+ classStmt->constructorBox = this;
+ }
+
+ allowNewTarget_ = true;
+ allowSuperProperty_ = flags_.allowSuperProperty();
+
+ if (kind == FunctionSyntaxKind::DerivedClassConstructor) {
+ setDerivedClassConstructor();
+ allowSuperCall_ = true;
+ thisBinding_ = ThisBinding::DerivedConstructor;
+ } else {
+ thisBinding_ = ThisBinding::Function;
+ }
+
+ if (kind == FunctionSyntaxKind::FieldInitializer ||
+ kind == FunctionSyntaxKind::StaticClassBlock) {
+ setSyntheticFunction();
+ allowArguments_ = false;
+ if (kind == FunctionSyntaxKind::StaticClassBlock) {
+ allowSuperCall_ = false;
+ allowReturn_ = false;
+ }
+ }
+ }
+
+ if (sc->inWith()) {
+ inWith_ = true;
+ } else {
+ auto isWith = [](ParseContext::Statement* stmt) {
+ return stmt->kind() == StatementKind::With;
+ };
+
+ inWith_ = enclosing->findInnermostStatement(isWith);
+ }
+
+ if (sc->inClass()) {
+ inClass_ = true;
+ } else {
+ auto isClass = [](ParseContext::Statement* stmt) {
+ return stmt->kind() == StatementKind::Class;
+ };
+
+ inClass_ = enclosing->findInnermostStatement(isClass);
+ }
+}
+
+void FunctionBox::initStandalone(ScopeContext& scopeContext,
+ FunctionSyntaxKind kind) {
+ initStandaloneOrLazy(scopeContext, kind);
+
+ isStandalone = true;
+}
+
+void FunctionBox::initStandaloneOrLazy(ScopeContext& scopeContext,
+ FunctionSyntaxKind kind) {
+ if (flags_.isArrow()) {
+ allowNewTarget_ = scopeContext.allowNewTarget;
+ allowSuperProperty_ = scopeContext.allowSuperProperty;
+ allowSuperCall_ = scopeContext.allowSuperCall;
+ allowArguments_ = scopeContext.allowArguments;
+ thisBinding_ = scopeContext.thisBinding;
+ } else {
+ allowNewTarget_ = true;
+ allowSuperProperty_ = flags_.allowSuperProperty();
+
+ if (kind == FunctionSyntaxKind::DerivedClassConstructor) {
+ setDerivedClassConstructor();
+ allowSuperCall_ = true;
+ thisBinding_ = ThisBinding::DerivedConstructor;
+ } else {
+ thisBinding_ = ThisBinding::Function;
+ }
+
+ if (kind == FunctionSyntaxKind::FieldInitializer) {
+ setSyntheticFunction();
+ allowArguments_ = false;
+ }
+ }
+
+ inWith_ = scopeContext.inWith;
+ inClass_ = scopeContext.inClass;
+}
+
+void FunctionBox::setEnclosingScopeForInnerLazyFunction(ScopeIndex scopeIndex) {
+ // For lazy functions inside a function which is being compiled, we cache
+ // the incomplete scope object while compiling, and store it to the
+ // BaseScript once the enclosing script successfully finishes compilation
+ // in FunctionBox::finish.
+ MOZ_ASSERT(enclosingScopeIndex_.isNothing());
+ enclosingScopeIndex_ = mozilla::Some(scopeIndex);
+ if (isFunctionFieldCopiedToStencil) {
+ copyUpdatedEnclosingScopeIndex();
+ }
+}
+
+bool FunctionBox::setAsmJSModule(const JS::WasmModule* module) {
+ MOZ_ASSERT(!isFunctionFieldCopiedToStencil);
+
+ MOZ_ASSERT(flags_.kind() == FunctionFlags::NormalFunction);
+
+ // Update flags we will use to allocate the JSFunction.
+ flags_.clearBaseScript();
+ flags_.setIsExtended();
+ flags_.setKind(FunctionFlags::AsmJS);
+
+ if (!compilationState_.asmJS) {
+ compilationState_.asmJS =
+ fc_->getAllocator()->new_<StencilAsmJSContainer>();
+ if (!compilationState_.asmJS) {
+ return false;
+ }
+ }
+
+ if (!compilationState_.asmJS->moduleMap.putNew(index(), module)) {
+ js::ReportOutOfMemory(fc_);
+ return false;
+ }
+ return true;
+}
+
+ModuleSharedContext::ModuleSharedContext(
+ FrontendContext* fc, const JS::ReadOnlyCompileOptions& options,
+ ModuleBuilder& builder, SourceExtent extent)
+ : SuspendableContext(fc, Kind::Module, options, Directives(true), extent,
+ /* isGenerator = */ false,
+ /* isAsync = */ false),
+ bindings(nullptr),
+ builder(builder) {
+ thisBinding_ = ThisBinding::Module;
+ setFlag(ImmutableFlags::HasModuleGoal);
+}
+
+ScriptStencil& FunctionBox::functionStencil() const {
+ return compilationState_.scriptData[funcDataIndex_];
+}
+
+ScriptStencilExtra& FunctionBox::functionExtraStencil() const {
+ return compilationState_.scriptExtra[funcDataIndex_];
+}
+
+void SharedContext::copyScriptExtraFields(ScriptStencilExtra& scriptExtra) {
+ MOZ_ASSERT(!isScriptExtraFieldCopiedToStencil);
+
+ scriptExtra.immutableFlags = immutableFlags_;
+ scriptExtra.extent = extent_;
+
+ isScriptExtraFieldCopiedToStencil = true;
+}
+
+void FunctionBox::finishScriptFlags() {
+ MOZ_ASSERT(!isScriptExtraFieldCopiedToStencil);
+
+ using ImmutableFlags = ImmutableScriptFlagsEnum;
+ immutableFlags_.setFlag(ImmutableFlags::HasMappedArgsObj, hasMappedArgsObj());
+}
+
+void FunctionBox::copyFunctionFields(ScriptStencil& script) {
+ MOZ_ASSERT(&script == &functionStencil());
+ MOZ_ASSERT(!isFunctionFieldCopiedToStencil);
+
+ if (atom_) {
+ compilationState_.parserAtoms.markUsedByStencil(atom_,
+ ParserAtom::Atomize::Yes);
+ script.functionAtom = atom_;
+ }
+ script.functionFlags = flags_;
+ if (enclosingScopeIndex_) {
+ script.setLazyFunctionEnclosingScopeIndex(*enclosingScopeIndex_);
+ }
+ if (wasEmittedByEnclosingScript_) {
+ script.setWasEmittedByEnclosingScript();
+ }
+
+ isFunctionFieldCopiedToStencil = true;
+}
+
+void FunctionBox::copyFunctionExtraFields(ScriptStencilExtra& scriptExtra) {
+ if (useMemberInitializers()) {
+ scriptExtra.setMemberInitializers(memberInitializers());
+ }
+
+ scriptExtra.nargs = nargs_;
+}
+
+void FunctionBox::copyUpdatedImmutableFlags() {
+ if (isInitialCompilation) {
+ ScriptStencilExtra& scriptExtra = functionExtraStencil();
+ scriptExtra.immutableFlags = immutableFlags_;
+ }
+}
+
+void FunctionBox::copyUpdatedExtent() {
+ ScriptStencilExtra& scriptExtra = functionExtraStencil();
+ scriptExtra.extent = extent_;
+}
+
+void FunctionBox::copyUpdatedMemberInitializers() {
+ MOZ_ASSERT(useMemberInitializers());
+ if (isInitialCompilation) {
+ ScriptStencilExtra& scriptExtra = functionExtraStencil();
+ scriptExtra.setMemberInitializers(memberInitializers());
+ } else {
+ // We are delazifying and the original PrivateScriptData has the member
+ // initializer information already. See: JSScript::fullyInitFromStencil.
+ }
+}
+
+void FunctionBox::copyUpdatedEnclosingScopeIndex() {
+ ScriptStencil& script = functionStencil();
+ if (enclosingScopeIndex_) {
+ script.setLazyFunctionEnclosingScopeIndex(*enclosingScopeIndex_);
+ }
+}
+
+void FunctionBox::copyUpdatedAtomAndFlags() {
+ ScriptStencil& script = functionStencil();
+ if (atom_) {
+ compilationState_.parserAtoms.markUsedByStencil(atom_,
+ ParserAtom::Atomize::Yes);
+ script.functionAtom = atom_;
+ }
+ script.functionFlags = flags_;
+}
+
+void FunctionBox::copyUpdatedWasEmitted() {
+ ScriptStencil& script = functionStencil();
+ if (wasEmittedByEnclosingScript_) {
+ script.setWasEmittedByEnclosingScript();
+ }
+}
+
+} // namespace frontend
+} // namespace js