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"
35 SharedContext::SharedContext(FrontendContext
* fc
, Kind kind
,
36 const JS::ReadOnlyCompileOptions
& options
,
37 Directives directives
, SourceExtent extent
)
40 allowNewTarget_(false),
41 allowSuperProperty_(false),
42 allowSuperCall_(false),
43 allowArguments_(true),
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
);
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
,
68 js::FillImmutableFlagsFromCompileOptionsForFunction(options
,
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
,
81 : SharedContext(fc
, Kind::Global
, options
, directives
, extent
),
82 scopeKind_(scopeKind
),
84 MOZ_ASSERT(scopeKind
== ScopeKind::Global
||
85 scopeKind
== ScopeKind::NonSyntactic
);
86 MOZ_ASSERT(thisBinding_
== ThisBinding::Global
);
89 EvalSharedContext::EvalSharedContext(FrontendContext
* fc
,
90 CompilationState
& compilationState
,
92 : SharedContext(fc
, Kind::Eval
, compilationState
.input
.options
,
93 compilationState
.directives
, extent
),
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
,
118 : SuspendableContext(fc
, Kind::FunctionBox
, compilationState
.input
.options
,
120 generatorKind
== GeneratorKind::Generator
,
121 asyncKind
== FunctionAsyncKind::AsyncFunction
),
122 compilationState_(compilationState
),
124 funcDataIndex_(index
),
125 flags_(FunctionFlags::clearMutableflags(flags
)),
127 wasEmittedByEnclosingScript_(false),
130 hasParameterExprs(false),
131 hasDestructuringArgs(false),
132 hasDuplicateParameters(false),
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();
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.
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
;
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;
205 auto isWith
= [](ParseContext::Statement
* stmt
) {
206 return stmt
->kind() == StatementKind::With
;
209 inWith_
= enclosing
->findInnermostStatement(isWith
);
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
);
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
;
239 allowNewTarget_
= true;
240 allowSuperProperty_
= flags_
.allowSuperProperty();
242 if (kind
== FunctionSyntaxKind::DerivedClassConstructor
) {
243 setDerivedClassConstructor();
244 allowSuperCall_
= true;
245 thisBinding_
= ThisBinding::DerivedConstructor
;
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
) {
290 if (!compilationState_
.asmJS
->moduleMap
.putNew(index(), module
)) {
291 js::ReportOutOfMemory(fc_
);
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),
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
);
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());
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();
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