Backed out changeset 2450366cf7ca (bug 1891629) for causing win msix mochitest failures
[gecko.git] / js / src / frontend / SharedContext.cpp
blob488e3bd384ba4209161d61fd20e951ec55dd001e
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 eligibleForArgumentsLength(true) {
50 // Compute the script kind "input" flags.
51 if (kind == Kind::FunctionBox) {
52 setFlag(ImmutableFlags::IsFunction);
53 } else if (kind == Kind::Module) {
54 MOZ_ASSERT(!options.nonSyntacticScope);
55 setFlag(ImmutableFlags::IsModule);
56 } else if (kind == Kind::Eval) {
57 setFlag(ImmutableFlags::IsForEval);
58 } else {
59 MOZ_ASSERT(kind == Kind::Global);
62 // Initialize the transitive "input" flags. These are applied to all
63 // SharedContext in this compilation and generally cannot be determined from
64 // the source text alone.
65 if (isTopLevelContext()) {
66 js::FillImmutableFlagsFromCompileOptionsForTopLevel(options,
67 immutableFlags_);
68 } else {
69 js::FillImmutableFlagsFromCompileOptionsForFunction(options,
70 immutableFlags_);
73 // Initialize the strict flag. This may be updated by the parser as we observe
74 // further directives in the body.
75 setFlag(ImmutableFlags::Strict, directives.strict());
78 GlobalSharedContext::GlobalSharedContext(
79 FrontendContext* fc, ScopeKind scopeKind,
80 const JS::ReadOnlyCompileOptions& options, Directives directives,
81 SourceExtent extent)
82 : SharedContext(fc, Kind::Global, options, directives, extent),
83 scopeKind_(scopeKind),
84 bindings(nullptr) {
85 MOZ_ASSERT(scopeKind == ScopeKind::Global ||
86 scopeKind == ScopeKind::NonSyntactic);
87 MOZ_ASSERT(thisBinding_ == ThisBinding::Global);
90 EvalSharedContext::EvalSharedContext(FrontendContext* fc,
91 CompilationState& compilationState,
92 SourceExtent extent)
93 : SharedContext(fc, Kind::Eval, compilationState.input.options,
94 compilationState.directives, extent),
95 bindings(nullptr) {
96 // Eval inherits syntax and binding rules from enclosing environment.
97 allowNewTarget_ = compilationState.scopeContext.allowNewTarget;
98 allowSuperProperty_ = compilationState.scopeContext.allowSuperProperty;
99 allowSuperCall_ = compilationState.scopeContext.allowSuperCall;
100 allowArguments_ = compilationState.scopeContext.allowArguments;
101 thisBinding_ = compilationState.scopeContext.thisBinding;
102 inWith_ = compilationState.scopeContext.inWith;
105 SuspendableContext::SuspendableContext(
106 FrontendContext* fc, Kind kind, const JS::ReadOnlyCompileOptions& options,
107 Directives directives, SourceExtent extent, bool isGenerator, bool isAsync)
108 : SharedContext(fc, kind, options, directives, extent) {
109 setFlag(ImmutableFlags::IsGenerator, isGenerator);
110 setFlag(ImmutableFlags::IsAsync, isAsync);
113 FunctionBox::FunctionBox(FrontendContext* fc, SourceExtent extent,
114 CompilationState& compilationState,
115 Directives directives, GeneratorKind generatorKind,
116 FunctionAsyncKind asyncKind, bool isInitialCompilation,
117 TaggedParserAtomIndex atom, FunctionFlags flags,
118 ScriptIndex index)
119 : SuspendableContext(fc, Kind::FunctionBox, compilationState.input.options,
120 directives, extent,
121 generatorKind == GeneratorKind::Generator,
122 asyncKind == FunctionAsyncKind::AsyncFunction),
123 compilationState_(compilationState),
124 atom_(atom),
125 funcDataIndex_(index),
126 flags_(FunctionFlags::clearMutableflags(flags)),
127 emitBytecode(false),
128 wasEmittedByEnclosingScript_(false),
129 isAnnexB(false),
130 useAsm(false),
131 hasParameterExprs(false),
132 hasDestructuringArgs(false),
133 hasDuplicateParameters(false),
134 hasExprBody_(false),
135 allowReturn_(true),
136 isFunctionFieldCopiedToStencil(false),
137 isInitialCompilation(isInitialCompilation),
138 isStandalone(false) {}
140 void FunctionBox::initFromLazyFunction(const ScriptStencilExtra& extra,
141 ScopeContext& scopeContext,
142 FunctionSyntaxKind kind) {
143 initFromScriptStencilExtra(extra);
144 initStandaloneOrLazy(scopeContext, kind);
147 void FunctionBox::initFromScriptStencilExtra(const ScriptStencilExtra& extra) {
148 immutableFlags_ = extra.immutableFlags;
149 extent_ = extra.extent;
152 void FunctionBox::initWithEnclosingParseContext(ParseContext* enclosing,
153 FunctionSyntaxKind kind) {
154 SharedContext* sc = enclosing->sc();
156 // HasModuleGoal and useAsm are inherited from enclosing context.
157 useAsm = sc->isFunctionBox() && sc->asFunctionBox()->useAsmOrInsideUseAsm();
158 setHasModuleGoal(sc->hasModuleGoal());
160 // Arrow functions don't have their own `this` binding.
161 if (flags_.isArrow()) {
162 allowNewTarget_ = sc->allowNewTarget();
163 allowSuperProperty_ = sc->allowSuperProperty();
164 allowSuperCall_ = sc->allowSuperCall();
165 allowArguments_ = sc->allowArguments();
166 thisBinding_ = sc->thisBinding();
167 } else {
168 if (IsConstructorKind(kind)) {
169 // Record this function into the enclosing class statement so that
170 // finishClassConstructor can final processing. Due to aborted syntax
171 // parses (eg, because of asm.js), this may have already been set with an
172 // early FunctionBox. In that case, the FunctionNode should still match.
173 auto classStmt =
174 enclosing->findInnermostStatement<ParseContext::ClassStatement>();
175 MOZ_ASSERT(classStmt);
176 MOZ_ASSERT(classStmt->constructorBox == nullptr ||
177 classStmt->constructorBox->functionNode == this->functionNode);
178 classStmt->constructorBox = this;
181 allowNewTarget_ = true;
182 allowSuperProperty_ = flags_.allowSuperProperty();
184 if (kind == FunctionSyntaxKind::DerivedClassConstructor) {
185 setDerivedClassConstructor();
186 allowSuperCall_ = true;
187 thisBinding_ = ThisBinding::DerivedConstructor;
188 } else {
189 thisBinding_ = ThisBinding::Function;
192 if (kind == FunctionSyntaxKind::FieldInitializer ||
193 kind == FunctionSyntaxKind::StaticClassBlock) {
194 setSyntheticFunction();
195 allowArguments_ = false;
196 if (kind == FunctionSyntaxKind::StaticClassBlock) {
197 allowSuperCall_ = false;
198 allowReturn_ = false;
203 if (sc->inWith()) {
204 inWith_ = true;
205 } else {
206 auto isWith = [](ParseContext::Statement* stmt) {
207 return stmt->kind() == StatementKind::With;
210 inWith_ = enclosing->findInnermostStatement(isWith);
213 if (sc->inClass()) {
214 inClass_ = true;
215 } else {
216 auto isClass = [](ParseContext::Statement* stmt) {
217 return stmt->kind() == StatementKind::Class;
220 inClass_ = enclosing->findInnermostStatement(isClass);
224 void FunctionBox::initStandalone(ScopeContext& scopeContext,
225 FunctionSyntaxKind kind) {
226 initStandaloneOrLazy(scopeContext, kind);
228 isStandalone = true;
231 void FunctionBox::initStandaloneOrLazy(ScopeContext& scopeContext,
232 FunctionSyntaxKind kind) {
233 if (flags_.isArrow()) {
234 allowNewTarget_ = scopeContext.allowNewTarget;
235 allowSuperProperty_ = scopeContext.allowSuperProperty;
236 allowSuperCall_ = scopeContext.allowSuperCall;
237 allowArguments_ = scopeContext.allowArguments;
238 thisBinding_ = scopeContext.thisBinding;
239 } else {
240 allowNewTarget_ = true;
241 allowSuperProperty_ = flags_.allowSuperProperty();
243 if (kind == FunctionSyntaxKind::DerivedClassConstructor) {
244 setDerivedClassConstructor();
245 allowSuperCall_ = true;
246 thisBinding_ = ThisBinding::DerivedConstructor;
247 } else {
248 thisBinding_ = ThisBinding::Function;
251 if (kind == FunctionSyntaxKind::FieldInitializer) {
252 setSyntheticFunction();
253 allowArguments_ = false;
257 inWith_ = scopeContext.inWith;
258 inClass_ = scopeContext.inClass;
261 void FunctionBox::setEnclosingScopeForInnerLazyFunction(ScopeIndex scopeIndex) {
262 // For lazy functions inside a function which is being compiled, we cache
263 // the incomplete scope object while compiling, and store it to the
264 // BaseScript once the enclosing script successfully finishes compilation
265 // in FunctionBox::finish.
266 MOZ_ASSERT(enclosingScopeIndex_.isNothing());
267 enclosingScopeIndex_ = mozilla::Some(scopeIndex);
268 if (isFunctionFieldCopiedToStencil) {
269 copyUpdatedEnclosingScopeIndex();
273 bool FunctionBox::setAsmJSModule(const JS::WasmModule* module) {
274 MOZ_ASSERT(!isFunctionFieldCopiedToStencil);
276 MOZ_ASSERT(flags_.kind() == FunctionFlags::NormalFunction);
278 // Update flags we will use to allocate the JSFunction.
279 flags_.clearBaseScript();
280 flags_.setIsExtended();
281 flags_.setKind(FunctionFlags::AsmJS);
283 if (!compilationState_.asmJS) {
284 compilationState_.asmJS =
285 fc_->getAllocator()->new_<StencilAsmJSContainer>();
286 if (!compilationState_.asmJS) {
287 return false;
291 if (!compilationState_.asmJS->moduleMap.putNew(index(), module)) {
292 js::ReportOutOfMemory(fc_);
293 return false;
295 return true;
298 ModuleSharedContext::ModuleSharedContext(
299 FrontendContext* fc, const JS::ReadOnlyCompileOptions& options,
300 ModuleBuilder& builder, SourceExtent extent)
301 : SuspendableContext(fc, Kind::Module, options, Directives(true), extent,
302 /* isGenerator = */ false,
303 /* isAsync = */ false),
304 bindings(nullptr),
305 builder(builder) {
306 thisBinding_ = ThisBinding::Module;
307 setFlag(ImmutableFlags::HasModuleGoal);
310 ScriptStencil& FunctionBox::functionStencil() const {
311 return compilationState_.scriptData[funcDataIndex_];
314 ScriptStencilExtra& FunctionBox::functionExtraStencil() const {
315 return compilationState_.scriptExtra[funcDataIndex_];
318 void SharedContext::copyScriptExtraFields(ScriptStencilExtra& scriptExtra) {
319 MOZ_ASSERT(!isScriptExtraFieldCopiedToStencil);
321 scriptExtra.immutableFlags = immutableFlags_;
322 scriptExtra.extent = extent_;
324 isScriptExtraFieldCopiedToStencil = true;
327 void FunctionBox::finishScriptFlags() {
328 MOZ_ASSERT(!isScriptExtraFieldCopiedToStencil);
330 using ImmutableFlags = ImmutableScriptFlagsEnum;
331 immutableFlags_.setFlag(ImmutableFlags::HasMappedArgsObj, hasMappedArgsObj());
334 void FunctionBox::copyFunctionFields(ScriptStencil& script) {
335 MOZ_ASSERT(&script == &functionStencil());
336 MOZ_ASSERT(!isFunctionFieldCopiedToStencil);
338 if (atom_) {
339 compilationState_.parserAtoms.markUsedByStencil(atom_,
340 ParserAtom::Atomize::Yes);
341 script.functionAtom = atom_;
343 script.functionFlags = flags_;
344 if (enclosingScopeIndex_) {
345 script.setLazyFunctionEnclosingScopeIndex(*enclosingScopeIndex_);
347 if (wasEmittedByEnclosingScript_) {
348 script.setWasEmittedByEnclosingScript();
351 isFunctionFieldCopiedToStencil = true;
354 void FunctionBox::copyFunctionExtraFields(ScriptStencilExtra& scriptExtra) {
355 if (useMemberInitializers()) {
356 scriptExtra.setMemberInitializers(memberInitializers());
359 scriptExtra.nargs = nargs_;
362 void FunctionBox::copyUpdatedImmutableFlags() {
363 if (isInitialCompilation) {
364 ScriptStencilExtra& scriptExtra = functionExtraStencil();
365 scriptExtra.immutableFlags = immutableFlags_;
369 void FunctionBox::copyUpdatedExtent() {
370 ScriptStencilExtra& scriptExtra = functionExtraStencil();
371 scriptExtra.extent = extent_;
374 void FunctionBox::copyUpdatedMemberInitializers() {
375 MOZ_ASSERT(useMemberInitializers());
376 if (isInitialCompilation) {
377 ScriptStencilExtra& scriptExtra = functionExtraStencil();
378 scriptExtra.setMemberInitializers(memberInitializers());
379 } else {
380 // We are delazifying and the original PrivateScriptData has the member
381 // initializer information already. See: JSScript::fullyInitFromStencil.
385 void FunctionBox::copyUpdatedEnclosingScopeIndex() {
386 ScriptStencil& script = functionStencil();
387 if (enclosingScopeIndex_) {
388 script.setLazyFunctionEnclosingScopeIndex(*enclosingScopeIndex_);
392 void FunctionBox::copyUpdatedAtomAndFlags() {
393 ScriptStencil& script = functionStencil();
394 if (atom_) {
395 compilationState_.parserAtoms.markUsedByStencil(atom_,
396 ParserAtom::Atomize::Yes);
397 script.functionAtom = atom_;
399 script.functionFlags = flags_;
402 void FunctionBox::copyUpdatedWasEmitted() {
403 ScriptStencil& script = functionStencil();
404 if (wasEmittedByEnclosingScript_) {
405 script.setWasEmittedByEnclosingScript();
409 } // namespace frontend
410 } // namespace js