Bug 1865597 - Add error checking when initializing parallel marking and disable on...
[gecko.git] / js / src / frontend / SharedContext.cpp
blob7fa3b724fb09a57cc3a8f84ceab1c6a4ac88a3a1
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/. */
7 #include "frontend/SharedContext.h"
9 #include "mozilla/RefPtr.h"
11 #include "frontend/CompilationStencil.h"
12 #include "frontend/FunctionSyntaxKind.h" // FunctionSyntaxKind
13 #include "frontend/ModuleSharedContext.h"
14 #include "frontend/ParseContext.h"
15 #include "frontend/ParseNode.h"
16 #include "frontend/ParserAtom.h"
17 #include "frontend/ScopeIndex.h"
18 #include "frontend/ScriptIndex.h"
19 #include "frontend/Stencil.h"
20 #include "js/CompileOptions.h"
21 #include "js/Vector.h"
22 #include "vm/FunctionFlags.h" // js::FunctionFlags
23 #include "vm/GeneratorAndAsyncKind.h" // js::GeneratorKind, js::FunctionAsyncKind
24 #include "vm/JSScript.h" // js::FillImmutableFlagsFromCompileOptionsForTopLevel, js::FillImmutableFlagsFromCompileOptionsForFunction
25 #include "vm/StencilEnums.h" // ImmutableScriptFlagsEnum
27 #include "frontend/ParseContext-inl.h"
29 namespace js {
31 class ModuleBuilder;
33 namespace frontend {
35 SharedContext::SharedContext(FrontendContext* fc, Kind kind,
36 const JS::ReadOnlyCompileOptions& options,
37 Directives directives, SourceExtent extent)
38 : fc_(fc),
39 extent_(extent),
40 allowNewTarget_(false),
41 allowSuperProperty_(false),
42 allowSuperCall_(false),
43 allowArguments_(true),
44 inWith_(false),
45 inClass_(false),
46 localStrict(false),
47 hasExplicitUseStrict_(false),
48 isScriptExtraFieldCopiedToStencil(false) {
49 // Compute the script kind "input" flags.
50 if (kind == Kind::FunctionBox) {
51 setFlag(ImmutableFlags::IsFunction);
52 } else if (kind == Kind::Module) {
53 MOZ_ASSERT(!options.nonSyntacticScope);
54 setFlag(ImmutableFlags::IsModule);
55 } else if (kind == Kind::Eval) {
56 setFlag(ImmutableFlags::IsForEval);
57 } else {
58 MOZ_ASSERT(kind == Kind::Global);
61 // Initialize the transitive "input" flags. These are applied to all
62 // SharedContext in this compilation and generally cannot be determined from
63 // the source text alone.
64 if (isTopLevelContext()) {
65 js::FillImmutableFlagsFromCompileOptionsForTopLevel(options,
66 immutableFlags_);
67 } else {
68 js::FillImmutableFlagsFromCompileOptionsForFunction(options,
69 immutableFlags_);
72 // Initialize the strict flag. This may be updated by the parser as we observe
73 // further directives in the body.
74 setFlag(ImmutableFlags::Strict, directives.strict());
77 GlobalSharedContext::GlobalSharedContext(
78 FrontendContext* fc, ScopeKind scopeKind,
79 const JS::ReadOnlyCompileOptions& options, Directives directives,
80 SourceExtent extent)
81 : SharedContext(fc, Kind::Global, options, directives, extent),
82 scopeKind_(scopeKind),
83 bindings(nullptr) {
84 MOZ_ASSERT(scopeKind == ScopeKind::Global ||
85 scopeKind == ScopeKind::NonSyntactic);
86 MOZ_ASSERT(thisBinding_ == ThisBinding::Global);
89 EvalSharedContext::EvalSharedContext(FrontendContext* fc,
90 CompilationState& compilationState,
91 SourceExtent extent)
92 : SharedContext(fc, Kind::Eval, compilationState.input.options,
93 compilationState.directives, extent),
94 bindings(nullptr) {
95 // Eval inherits syntax and binding rules from enclosing environment.
96 allowNewTarget_ = compilationState.scopeContext.allowNewTarget;
97 allowSuperProperty_ = compilationState.scopeContext.allowSuperProperty;
98 allowSuperCall_ = compilationState.scopeContext.allowSuperCall;
99 allowArguments_ = compilationState.scopeContext.allowArguments;
100 thisBinding_ = compilationState.scopeContext.thisBinding;
101 inWith_ = compilationState.scopeContext.inWith;
104 SuspendableContext::SuspendableContext(
105 FrontendContext* fc, Kind kind, const JS::ReadOnlyCompileOptions& options,
106 Directives directives, SourceExtent extent, bool isGenerator, bool isAsync)
107 : SharedContext(fc, kind, options, directives, extent) {
108 setFlag(ImmutableFlags::IsGenerator, isGenerator);
109 setFlag(ImmutableFlags::IsAsync, isAsync);
112 FunctionBox::FunctionBox(FrontendContext* fc, SourceExtent extent,
113 CompilationState& compilationState,
114 Directives directives, GeneratorKind generatorKind,
115 FunctionAsyncKind asyncKind, bool isInitialCompilation,
116 TaggedParserAtomIndex atom, FunctionFlags flags,
117 ScriptIndex index)
118 : SuspendableContext(fc, Kind::FunctionBox, compilationState.input.options,
119 directives, extent,
120 generatorKind == GeneratorKind::Generator,
121 asyncKind == FunctionAsyncKind::AsyncFunction),
122 compilationState_(compilationState),
123 atom_(atom),
124 funcDataIndex_(index),
125 flags_(FunctionFlags::clearMutableflags(flags)),
126 emitBytecode(false),
127 wasEmittedByEnclosingScript_(false),
128 isAnnexB(false),
129 useAsm(false),
130 hasParameterExprs(false),
131 hasDestructuringArgs(false),
132 hasDuplicateParameters(false),
133 hasExprBody_(false),
134 allowReturn_(true),
135 isFunctionFieldCopiedToStencil(false),
136 isInitialCompilation(isInitialCompilation),
137 isStandalone(false) {}
139 void FunctionBox::initFromLazyFunction(const ScriptStencilExtra& extra,
140 ScopeContext& scopeContext,
141 FunctionSyntaxKind kind) {
142 initFromScriptStencilExtra(extra);
143 initStandaloneOrLazy(scopeContext, kind);
146 void FunctionBox::initFromScriptStencilExtra(const ScriptStencilExtra& extra) {
147 immutableFlags_ = extra.immutableFlags;
148 extent_ = extra.extent;
151 void FunctionBox::initWithEnclosingParseContext(ParseContext* enclosing,
152 FunctionSyntaxKind kind) {
153 SharedContext* sc = enclosing->sc();
155 // HasModuleGoal and useAsm are inherited from enclosing context.
156 useAsm = sc->isFunctionBox() && sc->asFunctionBox()->useAsmOrInsideUseAsm();
157 setHasModuleGoal(sc->hasModuleGoal());
159 // Arrow functions don't have their own `this` binding.
160 if (flags_.isArrow()) {
161 allowNewTarget_ = sc->allowNewTarget();
162 allowSuperProperty_ = sc->allowSuperProperty();
163 allowSuperCall_ = sc->allowSuperCall();
164 allowArguments_ = sc->allowArguments();
165 thisBinding_ = sc->thisBinding();
166 } else {
167 if (IsConstructorKind(kind)) {
168 // Record this function into the enclosing class statement so that
169 // finishClassConstructor can final processing. Due to aborted syntax
170 // parses (eg, because of asm.js), this may have already been set with an
171 // early FunctionBox. In that case, the FunctionNode should still match.
172 auto classStmt =
173 enclosing->findInnermostStatement<ParseContext::ClassStatement>();
174 MOZ_ASSERT(classStmt);
175 MOZ_ASSERT(classStmt->constructorBox == nullptr ||
176 classStmt->constructorBox->functionNode == this->functionNode);
177 classStmt->constructorBox = this;
180 allowNewTarget_ = true;
181 allowSuperProperty_ = flags_.allowSuperProperty();
183 if (kind == FunctionSyntaxKind::DerivedClassConstructor) {
184 setDerivedClassConstructor();
185 allowSuperCall_ = true;
186 thisBinding_ = ThisBinding::DerivedConstructor;
187 } else {
188 thisBinding_ = ThisBinding::Function;
191 if (kind == FunctionSyntaxKind::FieldInitializer ||
192 kind == FunctionSyntaxKind::StaticClassBlock) {
193 setSyntheticFunction();
194 allowArguments_ = false;
195 if (kind == FunctionSyntaxKind::StaticClassBlock) {
196 allowSuperCall_ = false;
197 allowReturn_ = false;
202 if (sc->inWith()) {
203 inWith_ = true;
204 } else {
205 auto isWith = [](ParseContext::Statement* stmt) {
206 return stmt->kind() == StatementKind::With;
209 inWith_ = enclosing->findInnermostStatement(isWith);
212 if (sc->inClass()) {
213 inClass_ = true;
214 } else {
215 auto isClass = [](ParseContext::Statement* stmt) {
216 return stmt->kind() == StatementKind::Class;
219 inClass_ = enclosing->findInnermostStatement(isClass);
223 void FunctionBox::initStandalone(ScopeContext& scopeContext,
224 FunctionSyntaxKind kind) {
225 initStandaloneOrLazy(scopeContext, kind);
227 isStandalone = true;
230 void FunctionBox::initStandaloneOrLazy(ScopeContext& scopeContext,
231 FunctionSyntaxKind kind) {
232 if (flags_.isArrow()) {
233 allowNewTarget_ = scopeContext.allowNewTarget;
234 allowSuperProperty_ = scopeContext.allowSuperProperty;
235 allowSuperCall_ = scopeContext.allowSuperCall;
236 allowArguments_ = scopeContext.allowArguments;
237 thisBinding_ = scopeContext.thisBinding;
238 } else {
239 allowNewTarget_ = true;
240 allowSuperProperty_ = flags_.allowSuperProperty();
242 if (kind == FunctionSyntaxKind::DerivedClassConstructor) {
243 setDerivedClassConstructor();
244 allowSuperCall_ = true;
245 thisBinding_ = ThisBinding::DerivedConstructor;
246 } else {
247 thisBinding_ = ThisBinding::Function;
250 if (kind == FunctionSyntaxKind::FieldInitializer) {
251 setSyntheticFunction();
252 allowArguments_ = false;
256 inWith_ = scopeContext.inWith;
257 inClass_ = scopeContext.inClass;
260 void FunctionBox::setEnclosingScopeForInnerLazyFunction(ScopeIndex scopeIndex) {
261 // For lazy functions inside a function which is being compiled, we cache
262 // the incomplete scope object while compiling, and store it to the
263 // BaseScript once the enclosing script successfully finishes compilation
264 // in FunctionBox::finish.
265 MOZ_ASSERT(enclosingScopeIndex_.isNothing());
266 enclosingScopeIndex_ = mozilla::Some(scopeIndex);
267 if (isFunctionFieldCopiedToStencil) {
268 copyUpdatedEnclosingScopeIndex();
272 bool FunctionBox::setAsmJSModule(const JS::WasmModule* module) {
273 MOZ_ASSERT(!isFunctionFieldCopiedToStencil);
275 MOZ_ASSERT(flags_.kind() == FunctionFlags::NormalFunction);
277 // Update flags we will use to allocate the JSFunction.
278 flags_.clearBaseScript();
279 flags_.setIsExtended();
280 flags_.setKind(FunctionFlags::AsmJS);
282 if (!compilationState_.asmJS) {
283 compilationState_.asmJS =
284 fc_->getAllocator()->new_<StencilAsmJSContainer>();
285 if (!compilationState_.asmJS) {
286 return false;
290 if (!compilationState_.asmJS->moduleMap.putNew(index(), module)) {
291 js::ReportOutOfMemory(fc_);
292 return false;
294 return true;
297 ModuleSharedContext::ModuleSharedContext(
298 FrontendContext* fc, const JS::ReadOnlyCompileOptions& options,
299 ModuleBuilder& builder, SourceExtent extent)
300 : SuspendableContext(fc, Kind::Module, options, Directives(true), extent,
301 /* isGenerator = */ false,
302 /* isAsync = */ false),
303 bindings(nullptr),
304 builder(builder) {
305 thisBinding_ = ThisBinding::Module;
306 setFlag(ImmutableFlags::HasModuleGoal);
309 ScriptStencil& FunctionBox::functionStencil() const {
310 return compilationState_.scriptData[funcDataIndex_];
313 ScriptStencilExtra& FunctionBox::functionExtraStencil() const {
314 return compilationState_.scriptExtra[funcDataIndex_];
317 void SharedContext::copyScriptExtraFields(ScriptStencilExtra& scriptExtra) {
318 MOZ_ASSERT(!isScriptExtraFieldCopiedToStencil);
320 scriptExtra.immutableFlags = immutableFlags_;
321 scriptExtra.extent = extent_;
323 isScriptExtraFieldCopiedToStencil = true;
326 void FunctionBox::finishScriptFlags() {
327 MOZ_ASSERT(!isScriptExtraFieldCopiedToStencil);
329 using ImmutableFlags = ImmutableScriptFlagsEnum;
330 immutableFlags_.setFlag(ImmutableFlags::HasMappedArgsObj, hasMappedArgsObj());
333 void FunctionBox::copyFunctionFields(ScriptStencil& script) {
334 MOZ_ASSERT(&script == &functionStencil());
335 MOZ_ASSERT(!isFunctionFieldCopiedToStencil);
337 if (atom_) {
338 compilationState_.parserAtoms.markUsedByStencil(atom_,
339 ParserAtom::Atomize::Yes);
340 script.functionAtom = atom_;
342 script.functionFlags = flags_;
343 if (enclosingScopeIndex_) {
344 script.setLazyFunctionEnclosingScopeIndex(*enclosingScopeIndex_);
346 if (wasEmittedByEnclosingScript_) {
347 script.setWasEmittedByEnclosingScript();
350 isFunctionFieldCopiedToStencil = true;
353 void FunctionBox::copyFunctionExtraFields(ScriptStencilExtra& scriptExtra) {
354 if (useMemberInitializers()) {
355 scriptExtra.setMemberInitializers(memberInitializers());
358 scriptExtra.nargs = nargs_;
361 void FunctionBox::copyUpdatedImmutableFlags() {
362 if (isInitialCompilation) {
363 ScriptStencilExtra& scriptExtra = functionExtraStencil();
364 scriptExtra.immutableFlags = immutableFlags_;
368 void FunctionBox::copyUpdatedExtent() {
369 ScriptStencilExtra& scriptExtra = functionExtraStencil();
370 scriptExtra.extent = extent_;
373 void FunctionBox::copyUpdatedMemberInitializers() {
374 MOZ_ASSERT(useMemberInitializers());
375 if (isInitialCompilation) {
376 ScriptStencilExtra& scriptExtra = functionExtraStencil();
377 scriptExtra.setMemberInitializers(memberInitializers());
378 } else {
379 // We are delazifying and the original PrivateScriptData has the member
380 // initializer information already. See: JSScript::fullyInitFromStencil.
384 void FunctionBox::copyUpdatedEnclosingScopeIndex() {
385 ScriptStencil& script = functionStencil();
386 if (enclosingScopeIndex_) {
387 script.setLazyFunctionEnclosingScopeIndex(*enclosingScopeIndex_);
391 void FunctionBox::copyUpdatedAtomAndFlags() {
392 ScriptStencil& script = functionStencil();
393 if (atom_) {
394 compilationState_.parserAtoms.markUsedByStencil(atom_,
395 ParserAtom::Atomize::Yes);
396 script.functionAtom = atom_;
398 script.functionFlags = flags_;
401 void FunctionBox::copyUpdatedWasEmitted() {
402 ScriptStencil& script = functionStencil();
403 if (wasEmittedByEnclosingScript_) {
404 script.setWasEmittedByEnclosingScript();
408 } // namespace frontend
409 } // namespace js