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 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
);
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
,
69 js::FillImmutableFlagsFromCompileOptionsForFunction(options
,
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
,
82 : SharedContext(fc
, Kind::Global
, options
, directives
, extent
),
83 scopeKind_(scopeKind
),
85 MOZ_ASSERT(scopeKind
== ScopeKind::Global
||
86 scopeKind
== ScopeKind::NonSyntactic
);
87 MOZ_ASSERT(thisBinding_
== ThisBinding::Global
);
90 EvalSharedContext::EvalSharedContext(FrontendContext
* fc
,
91 CompilationState
& compilationState
,
93 : SharedContext(fc
, Kind::Eval
, compilationState
.input
.options
,
94 compilationState
.directives
, extent
),
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
,
119 : SuspendableContext(fc
, Kind::FunctionBox
, compilationState
.input
.options
,
121 generatorKind
== GeneratorKind::Generator
,
122 asyncKind
== FunctionAsyncKind::AsyncFunction
),
123 compilationState_(compilationState
),
125 funcDataIndex_(index
),
126 flags_(FunctionFlags::clearMutableflags(flags
)),
128 wasEmittedByEnclosingScript_(false),
131 hasParameterExprs(false),
132 hasDestructuringArgs(false),
133 hasDuplicateParameters(false),
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();
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.
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
;
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;
206 auto isWith
= [](ParseContext::Statement
* stmt
) {
207 return stmt
->kind() == StatementKind::With
;
210 inWith_
= enclosing
->findInnermostStatement(isWith
);
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
);
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
;
240 allowNewTarget_
= true;
241 allowSuperProperty_
= flags_
.allowSuperProperty();
243 if (kind
== FunctionSyntaxKind::DerivedClassConstructor
) {
244 setDerivedClassConstructor();
245 allowSuperCall_
= true;
246 thisBinding_
= ThisBinding::DerivedConstructor
;
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
) {
291 if (!compilationState_
.asmJS
->moduleMap
.putNew(index(), module
)) {
292 js::ReportOutOfMemory(fc_
);
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),
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
);
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());
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();
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