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 #ifndef frontend_CompilationStencil_h
8 #define frontend_CompilationStencil_h
10 #include "mozilla/AlreadyAddRefed.h" // already_AddRefed
11 #include "mozilla/Assertions.h" // MOZ_ASSERT, MOZ_RELEASE_ASSERT, MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE
12 #include "mozilla/Atomics.h" // mozilla::Atomic
13 #include "mozilla/Attributes.h" // MOZ_RAII, MOZ_STACK_CLASS
14 #include "mozilla/HashTable.h" // mozilla::HashMap, mozilla::DefaultHasher
15 #include "mozilla/Maybe.h" // mozilla::Maybe
16 #include "mozilla/MemoryReporting.h" // mozilla::MallocSizeOf
17 #include "mozilla/RefPtr.h" // RefPtr
18 #include "mozilla/Span.h" // mozilla::Span
19 #include "mozilla/Variant.h" // mozilla::Variant
21 #include <algorithm> // std::swap
22 #include <stddef.h> // size_t
23 #include <stdint.h> // uint32_t, uintptr_t
24 #include <type_traits> // std::is_pointer_v
25 #include <utility> // std::forward, std::move
27 #include "ds/LifoAlloc.h" // LifoAlloc, LifoAllocScope
28 #include "frontend/FrontendContext.h" // FrontendContext
29 #include "frontend/FunctionSyntaxKind.h" // FunctionSyntaxKind
30 #include "frontend/NameAnalysisTypes.h" // NameLocation
31 #include "frontend/ParserAtom.h" // ParserAtomsTable, ParserAtomIndex, TaggedParserAtomIndex, ParserAtomSpan
32 #include "frontend/ScopeIndex.h" // ScopeIndex
33 #include "frontend/ScriptIndex.h" // ScriptIndex
34 #include "frontend/SharedContext.h" // ThisBinding, InheritThis, Directives
35 #include "frontend/Stencil.h" // ScriptStencil, ScriptStencilExtra, ScopeStencil, RegExpStencil, BigIntStencil, ObjLiteralStencil, BaseParserScopeData, StencilModuleMetadata
36 #include "frontend/TaggedParserAtomIndexHasher.h" // TaggedParserAtomIndexHasher
37 #include "frontend/UsedNameTracker.h" // UsedNameTracker
38 #include "js/AllocPolicy.h" // SystemAllocPolicy, ReportOutOfMemory
39 #include "js/GCVector.h" // JS::GCVector
40 #include "js/RefCounted.h" // AtomicRefCounted
41 #include "js/RootingAPI.h" // JS::Handle
42 #include "js/Transcoding.h" // JS::TranscodeBuffer, JS::TranscodeRange
43 #include "js/UniquePtr.h" // js::UniquePtr
44 #include "js/Vector.h" // Vector
45 #include "js/WasmModule.h" // JS::WasmModule
46 #include "vm/FunctionFlags.h" // FunctionFlags
47 #include "vm/GlobalObject.h" // GlobalObject
48 #include "vm/JSContext.h" // JSContext
49 #include "vm/JSFunction.h" // JSFunction
50 #include "vm/JSScript.h" // BaseScript, ScriptSource, SourceExtent
51 #include "vm/Realm.h" // JSContext::global
52 #include "vm/Scope.h" // Scope, ModuleScope
53 #include "vm/ScopeKind.h" // ScopeKind
54 #include "vm/SharedStencil.h" // ImmutableScriptFlags, MemberInitializers, SharedImmutableScriptData, RO_IMMUTABLE_SCRIPT_FLAGS
63 class JS_PUBLIC_API ReadOnlyCompileOptions
;
74 struct CompilationInput
;
75 struct CompilationStencil
;
76 struct CompilationGCOutput
;
77 struct PreallocatedCompilationGCOutput
;
78 class ScriptStencilIterable
;
80 class ScopeBindingCache
;
82 // When delazifying modules' inner functions, the actual global scope is used.
83 // However, when doing a delazification the global scope is not available. We
84 // use this dummy type to be a placeholder to be used as part of the InputScope
85 // variants to mimic what the Global scope would be used for.
86 struct FakeStencilGlobalScope
{};
88 // Reference to a Scope within a CompilationStencil.
89 struct ScopeStencilRef
{
90 const CompilationStencil
& context_
;
91 const ScopeIndex scopeIndex_
;
93 // Lookup the ScopeStencil referenced by this ScopeStencilRef.
94 inline const ScopeStencil
& scope() const;
97 // Wraps a scope for a CompilationInput. The scope is either as a GC pointer to
98 // an instantiated scope, or as a reference to a CompilationStencil.
100 // Note: A scope reference may be nullptr/InvalidIndex if there is no such
101 // scope, such as the enclosingScope at the end of a scope chain. See `isNull`
104 using InputScopeStorage
=
105 mozilla::Variant
<Scope
*, ScopeStencilRef
, FakeStencilGlobalScope
>;
106 InputScopeStorage scope_
;
109 // Create an InputScope given an instantiated scope.
110 explicit InputScope(Scope
* ptr
) : scope_(ptr
) {}
112 // Create an InputScope for a global.
113 explicit InputScope(FakeStencilGlobalScope global
) : scope_(global
) {}
115 // Create an InputScope given a CompilationStencil and the ScopeIndex which is
116 // an offset within the same CompilationStencil given as argument.
117 InputScope(const CompilationStencil
& context
, ScopeIndex scopeIndex
)
118 : scope_(ScopeStencilRef
{context
, scopeIndex
}) {}
120 // Returns the variant used by the InputScope. This can be useful for complex
121 // cases where the following accessors are not enough.
122 const InputScopeStorage
& variant() const { return scope_
; }
123 InputScopeStorage
& variant() { return scope_
; }
125 // This match function will unwrap the variant for each type, and will
126 // specialize and call the Matcher given as argument with the type and value
127 // of the stored pointer / reference.
129 // This is useful for cases where the code is literally identical despite
130 // having different specializations. This is achiveable by relying on
131 // function overloading when the usage differ between the 2 types.
134 // inputScope.match([](auto& scope) {
135 // // scope is either a `Scope*` or a `ScopeStencilRef`.
136 // for (auto bi = InputBindingIter(scope); bi; bi++) {
137 // InputName name(scope, bi.name());
141 template <typename Matcher
>
142 decltype(auto) match(Matcher
&& matcher
) const& {
143 return scope_
.match(std::forward
<Matcher
>(matcher
));
145 template <typename Matcher
>
146 decltype(auto) match(Matcher
&& matcher
) & {
147 return scope_
.match(std::forward
<Matcher
>(matcher
));
150 bool isNull() const {
152 [](const Scope
* ptr
) { return !ptr
; },
153 [](const ScopeStencilRef
& ref
) { return !ref
.scopeIndex_
.isValid(); },
154 [](const FakeStencilGlobalScope
&) { return false; });
157 ScopeKind
kind() const {
159 [](const Scope
* ptr
) { return ptr
->kind(); },
160 [](const ScopeStencilRef
& ref
) { return ref
.scope().kind(); },
161 [](const FakeStencilGlobalScope
&) { return ScopeKind::Global
; });
163 bool hasEnvironment() const {
165 [](const Scope
* ptr
) { return ptr
->hasEnvironment(); },
166 [](const ScopeStencilRef
& ref
) { return ref
.scope().hasEnvironment(); },
167 [](const FakeStencilGlobalScope
&) {
168 // See Scope::hasEnvironment
172 inline InputScope
enclosing() const;
173 bool hasOnChain(ScopeKind kind
) const {
175 [=](const Scope
* ptr
) { return ptr
->hasOnChain(kind
); },
176 [=](const ScopeStencilRef
& ref
) {
177 ScopeStencilRef it
= ref
;
179 const ScopeStencil
& scope
= it
.scope();
180 if (scope
.kind() == kind
) {
183 if (scope
.kind() == ScopeKind::Module
&&
184 kind
== ScopeKind::Global
) {
187 if (!scope
.hasEnclosing()) {
190 new (&it
) ScopeStencilRef
{ref
.context_
, scope
.enclosing()};
194 [=](const FakeStencilGlobalScope
&) {
195 return kind
== ScopeKind::Global
;
198 uint32_t environmentChainLength() const {
200 [](const Scope
* ptr
) { return ptr
->environmentChainLength(); },
201 [](const ScopeStencilRef
& ref
) {
203 ScopeStencilRef it
= ref
;
205 const ScopeStencil
& scope
= it
.scope();
206 if (scope
.hasEnvironment() &&
207 scope
.kind() != ScopeKind::NonSyntactic
) {
210 if (scope
.kind() == ScopeKind::Module
) {
211 // Stencil do not encode the Global scope, as it used to be
212 // assumed to already exists. As moving delazification off-thread,
213 // we need to materialize a fake-stencil version of the Global
215 MOZ_ASSERT(!scope
.hasEnclosing());
216 length
+= js::ModuleScope::EnclosingEnvironmentChainLength
;
218 if (!scope
.hasEnclosing()) {
221 new (&it
) ScopeStencilRef
{ref
.context_
, scope
.enclosing()};
225 [=](const FakeStencilGlobalScope
&) {
226 // Stencil-based delazification needs to calculate
227 // environmentChainLength where the global is not available.
229 // The FakeStencilGlobalScope is used to represent what the global
230 // would be if we had access to it while delazifying.
231 return uint32_t(js::ModuleScope::EnclosingEnvironmentChainLength
);
234 void trace(JSTracer
* trc
);
235 bool isStencil() const { return !scope_
.is
<Scope
*>(); };
237 // Various accessors which are valid only when the InputScope is a
238 // FunctionScope. Some of these accessors are returning values associated with
239 // the canonical function.
241 inline FunctionFlags
functionFlags() const;
242 inline ImmutableScriptFlags
immutableFlags() const;
245 inline MemberInitializers
getMemberInitializers() const;
246 RO_IMMUTABLE_SCRIPT_FLAGS(immutableFlags())
247 bool isArrow() const { return functionFlags().isArrow(); }
248 bool allowSuperProperty() const {
249 return functionFlags().allowSuperProperty();
251 bool isClassConstructor() const {
252 return functionFlags().isClassConstructor();
256 // Reference to a Script within a CompilationStencil.
257 struct ScriptStencilRef
{
258 const CompilationStencil
& context_
;
259 const ScriptIndex scriptIndex_
;
261 inline const ScriptStencil
& scriptData() const;
262 inline const ScriptStencilExtra
& scriptExtra() const;
265 // Wraps a script for a CompilationInput. The script is either as a BaseScript
266 // pointer to an instantiated script, or as a reference to a CompilationStencil.
268 using InputScriptStorage
= mozilla::Variant
<BaseScript
*, ScriptStencilRef
>;
269 InputScriptStorage script_
;
272 // Create an InputScript given an instantiated BaseScript pointer.
273 explicit InputScript(BaseScript
* ptr
) : script_(ptr
) {}
275 // Create an InputScript given a CompilationStencil and the ScriptIndex which
276 // is an offset within the same CompilationStencil given as argument.
277 InputScript(const CompilationStencil
& context
, ScriptIndex scriptIndex
)
278 : script_(ScriptStencilRef
{context
, scriptIndex
}) {}
280 const InputScriptStorage
& raw() const { return script_
; }
281 InputScriptStorage
& raw() { return script_
; }
283 SourceExtent
extent() const {
284 return script_
.match(
285 [](const BaseScript
* ptr
) { return ptr
->extent(); },
286 [](const ScriptStencilRef
& ref
) { return ref
.scriptExtra().extent
; });
288 ImmutableScriptFlags
immutableFlags() const {
289 return script_
.match(
290 [](const BaseScript
* ptr
) { return ptr
->immutableFlags(); },
291 [](const ScriptStencilRef
& ref
) {
292 return ref
.scriptExtra().immutableFlags
;
295 RO_IMMUTABLE_SCRIPT_FLAGS(immutableFlags())
296 FunctionFlags
functionFlags() const {
297 return script_
.match(
298 [](const BaseScript
* ptr
) { return ptr
->function()->flags(); },
299 [](const ScriptStencilRef
& ref
) {
300 return ref
.scriptData().functionFlags
;
303 bool hasPrivateScriptData() const {
304 return script_
.match(
305 [](const BaseScript
* ptr
) { return ptr
->hasPrivateScriptData(); },
306 [](const ScriptStencilRef
& ref
) {
307 // See BaseScript::CreateRawLazy.
308 return ref
.scriptData().hasGCThings() ||
309 ref
.scriptExtra().useMemberInitializers();
312 InputScope
enclosingScope() const {
313 return script_
.match(
314 [](const BaseScript
* ptr
) {
315 return InputScope(ptr
->function()->enclosingScope());
317 [](const ScriptStencilRef
& ref
) {
318 // The ScriptStencilRef only reference lazy Script, otherwise we
319 // should fetch the enclosing scope using the bodyScope field of the
320 // immutable data which is a reference to the vector of gc-things.
321 MOZ_RELEASE_ASSERT(!ref
.scriptData().hasSharedData());
322 MOZ_ASSERT(ref
.scriptData().hasLazyFunctionEnclosingScopeIndex());
323 auto scopeIndex
= ref
.scriptData().lazyFunctionEnclosingScopeIndex();
324 return InputScope(ref
.context_
, scopeIndex
);
327 MemberInitializers
getMemberInitializers() const {
328 return script_
.match(
329 [](const BaseScript
* ptr
) { return ptr
->getMemberInitializers(); },
330 [](const ScriptStencilRef
& ref
) {
331 return ref
.scriptExtra().memberInitializers();
335 InputName
displayAtom() const;
336 void trace(JSTracer
* trc
);
337 bool isNull() const {
338 return script_
.match([](const BaseScript
* ptr
) { return !ptr
; },
339 [](const ScriptStencilRef
& ref
) { return false; });
341 bool isStencil() const {
342 return script_
.match([](const BaseScript
* ptr
) { return false; },
343 [](const ScriptStencilRef
&) { return true; });
347 // Iterator for walking the scope chain, this is identical to ScopeIter but
348 // accept an InputScope instead of a Scope pointer.
350 // It may be placed in GC containers; for example:
352 // for (Rooted<InputScopeIter> si(cx, InputScopeIter(scope)); si; si++) {
354 // SomeMayGCOperation();
358 class MOZ_STACK_CLASS InputScopeIter
{
362 explicit InputScopeIter(const InputScope
& scope
) : scope_(scope
) {}
364 InputScope
& scope() {
369 const InputScope
& scope() const {
374 bool done() const { return scope_
.isNull(); }
375 explicit operator bool() const { return !done(); }
376 void operator++(int) { scope_
= scope_
.enclosing(); }
377 ScopeKind
kind() const { return scope_
.kind(); }
379 // Returns whether this scope has a syntactic environment (i.e., an
380 // Environment that isn't a non-syntactic With or NonSyntacticVariables)
381 // on the environment chain.
382 bool hasSyntacticEnvironment() const {
383 return scope_
.hasEnvironment() && scope_
.kind() != ScopeKind::NonSyntactic
;
386 void trace(JSTracer
* trc
) { scope_
.trace(trc
); }
389 // Reference to a Binding Name within an existing CompilationStencil.
390 // TaggedParserAtomIndex are in some cases indexes in the parserAtomData of the
391 // CompilationStencil.
392 struct NameStencilRef
{
393 const CompilationStencil
& context_
;
394 const TaggedParserAtomIndex atomIndex_
;
397 // Wraps a name for a CompilationInput. The name is either as a GC pointer to
398 // a JSAtom, or a TaggedParserAtomIndex which might reference to a non-included.
400 // The constructor for this class are using an InputScope as argument. This
401 // InputScope is made to fetch back the CompilationStencil associated with the
402 // TaggedParserAtomIndex when using a Stencil as input.
404 using InputNameStorage
= mozilla::Variant
<JSAtom
*, NameStencilRef
>;
405 InputNameStorage variant_
;
407 InputName(Scope
*, JSAtom
* ptr
) : variant_(ptr
) {}
408 InputName(const ScopeStencilRef
& scope
, TaggedParserAtomIndex index
)
409 : variant_(NameStencilRef
{scope
.context_
, index
}) {}
410 InputName(BaseScript
*, JSAtom
* ptr
) : variant_(ptr
) {}
411 InputName(const ScriptStencilRef
& script
, TaggedParserAtomIndex index
)
412 : variant_(NameStencilRef
{script
.context_
, index
}) {}
414 // Dummy for empty global.
415 InputName(const FakeStencilGlobalScope
&, TaggedParserAtomIndex
)
416 : variant_(static_cast<JSAtom
*>(nullptr)) {}
418 // The InputName is either from an instantiated name, or from another
419 // CompilationStencil. This method interns the current name in the parser atom
420 // table of a CompilationState, which has a corresponding CompilationInput.
421 TaggedParserAtomIndex
internInto(FrontendContext
* fc
,
422 ParserAtomsTable
& parserAtoms
,
423 CompilationAtomCache
& atomCache
);
425 // Compare an InputName, which is not yet interned, with `other` is either an
426 // interned name or a well-known or static string.
428 // The `otherCached` argument should be a reference to a JSAtom*, initialized
429 // to nullptr, which is used to cache the JSAtom representation of the `other`
430 // argument if needed. If a different `other` parameter is provided, the
431 // `otherCached` argument should be reset to nullptr.
432 bool isEqualTo(FrontendContext
* fc
, ParserAtomsTable
& parserAtoms
,
433 CompilationAtomCache
& atomCache
, TaggedParserAtomIndex other
,
434 JSAtom
** otherCached
) const;
436 bool isNull() const {
437 return variant_
.match(
438 [](JSAtom
* ptr
) { return !ptr
; },
439 [](const NameStencilRef
& ref
) { return !ref
.atomIndex_
; });
443 // ScopeContext holds information derived from the scope and environment chains
444 // to try to avoid the parser needing to traverse VM structures directly.
445 struct ScopeContext
{
446 // Cache: Scope -> (JSAtom/TaggedParserAtomIndex -> NameLocation)
448 // This cache maps the scope to a hash table which can lookup a name of the
449 // scope to the equivalent NameLocation.
450 ScopeBindingCache
* scopeCache
= nullptr;
452 // Generation number of the `scopeCache` collected before filling the cache
453 // with enclosing scope information.
455 // The generation number, obtained from `scopeCache->getCurrentGeneration()`
456 // is incremented each time the GC invalidate the content of the cache. The
457 // `scopeCache` can only be used when the generation number collected before
458 // filling the cache is identical to the generation number seen when querying
459 // the cached content.
460 size_t scopeCacheGen
= 0;
462 // Class field initializer info if we are nested within a class constructor.
463 // We may be an combination of arrow and eval context within the constructor.
464 mozilla::Maybe
<MemberInitializers
> memberInitializers
= {};
466 enum class EnclosingLexicalBindingKind
{
474 using EnclosingLexicalBindingCache
=
475 mozilla::HashMap
<TaggedParserAtomIndex
, EnclosingLexicalBindingKind
,
476 TaggedParserAtomIndexHasher
>;
478 // Cache of enclosing lexical bindings.
479 // Used only for eval.
480 mozilla::Maybe
<EnclosingLexicalBindingCache
> enclosingLexicalBindingCache_
;
482 // A map of private names to NameLocations used to allow evals to
483 // provide correct private name semantics (particularly around early
484 // errors and private brand lookup).
485 using EffectiveScopePrivateFieldCache
=
486 mozilla::HashMap
<TaggedParserAtomIndex
, NameLocation
,
487 TaggedParserAtomIndexHasher
>;
489 // Cache of enclosing class's private fields.
490 // Used only for eval.
491 mozilla::Maybe
<EffectiveScopePrivateFieldCache
>
492 effectiveScopePrivateFieldCache_
;
495 bool enclosingEnvironmentIsDebugProxy_
= false;
498 // How many hops required to navigate from 'enclosingScope' to effective
500 uint32_t effectiveScopeHops
= 0;
502 uint32_t enclosingScopeEnvironmentChainLength
= 0;
504 // Eval and arrow scripts also inherit the "this" environment -- used by
505 // `super` expressions -- from their enclosing script. We count the number of
506 // environment hops needed to get from enclosing scope to the nearest
507 // appropriate environment. This value is undefined if the script we are
508 // compiling is not an eval or arrow-function.
509 uint32_t enclosingThisEnvironmentHops
= 0;
511 // The kind of enclosing scope.
512 ScopeKind enclosingScopeKind
= ScopeKind::Global
;
514 // The type of binding required for `this` of the top level context, as
515 // indicated by the enclosing scopes of this parse.
517 // NOTE: This is computed based on the effective scope (defined above).
518 ThisBinding thisBinding
= ThisBinding::Global
;
520 // Eval and arrow scripts inherit certain syntax allowances from their
521 // enclosing scripts.
522 bool allowNewTarget
= false;
523 bool allowSuperProperty
= false;
524 bool allowSuperCall
= false;
525 bool allowArguments
= true;
527 // Indicates there is a 'class' or 'with' scope on enclosing scope chain.
528 bool inClass
= false;
531 // True if the enclosing scope is for FunctionScope of arrow function.
532 bool enclosingScopeIsArrow
= false;
534 // True if the enclosing scope has environment.
535 bool enclosingScopeHasEnvironment
= false;
538 // True if the enclosing scope has non-syntactic scope on chain.
539 bool hasNonSyntacticScopeOnChain
= false;
541 // True if the enclosing scope has function scope where the function needs
543 bool hasFunctionNeedsHomeObjectOnChain
= false;
546 bool init(FrontendContext
* fc
, CompilationInput
& input
,
547 ParserAtomsTable
& parserAtoms
, ScopeBindingCache
* scopeCache
,
548 InheritThis inheritThis
, JSObject
* enclosingEnv
);
550 mozilla::Maybe
<EnclosingLexicalBindingKind
>
551 lookupLexicalBindingInEnclosingScope(TaggedParserAtomIndex name
);
553 NameLocation
searchInEnclosingScope(FrontendContext
* fc
,
554 CompilationInput
& input
,
555 ParserAtomsTable
& parserAtoms
,
556 TaggedParserAtomIndex name
);
558 bool effectiveScopePrivateFieldCacheHas(TaggedParserAtomIndex name
);
559 mozilla::Maybe
<NameLocation
> getPrivateFieldLocation(
560 TaggedParserAtomIndex name
);
563 void computeThisBinding(const InputScope
& scope
);
564 void computeThisEnvironment(const InputScope
& enclosingScope
);
565 void computeInScope(const InputScope
& enclosingScope
);
566 void cacheEnclosingScope(const InputScope
& enclosingScope
);
567 NameLocation
searchInEnclosingScopeWithCache(FrontendContext
* fc
,
568 CompilationInput
& input
,
569 ParserAtomsTable
& parserAtoms
,
570 TaggedParserAtomIndex name
);
571 NameLocation
searchInEnclosingScopeNoCache(FrontendContext
* fc
,
572 CompilationInput
& input
,
573 ParserAtomsTable
& parserAtoms
,
574 TaggedParserAtomIndex name
);
576 InputScope
determineEffectiveScope(InputScope
& scope
, JSObject
* environment
);
578 bool cachePrivateFieldsForEval(FrontendContext
* fc
, CompilationInput
& input
,
579 JSObject
* enclosingEnvironment
,
580 const InputScope
& effectiveScope
,
581 ParserAtomsTable
& parserAtoms
);
583 bool cacheEnclosingScopeBindingForEval(FrontendContext
* fc
,
584 CompilationInput
& input
,
585 ParserAtomsTable
& parserAtoms
);
587 bool addToEnclosingLexicalBindingCache(FrontendContext
* fc
,
588 ParserAtomsTable
& parserAtoms
,
589 CompilationAtomCache
& atomCache
,
591 EnclosingLexicalBindingKind kind
);
594 struct CompilationAtomCache
{
596 using AtomCacheVector
= JS::GCVector
<JSString
*, 0, js::SystemAllocPolicy
>;
599 // Atoms lowered into or converted from CompilationStencil.parserAtomData.
601 // This field is here instead of in CompilationGCOutput because atoms lowered
602 // from JSAtom is part of input (enclosing scope bindings, lazy function name,
603 // etc), and having 2 vectors in both input/output is error prone.
604 AtomCacheVector atoms_
;
607 JSString
* getExistingStringAt(ParserAtomIndex index
) const;
608 JSString
* getExistingStringAt(JSContext
* cx
,
609 TaggedParserAtomIndex taggedIndex
) const;
610 JSString
* getStringAt(ParserAtomIndex index
) const;
612 JSAtom
* getExistingAtomAt(ParserAtomIndex index
) const;
613 JSAtom
* getExistingAtomAt(JSContext
* cx
,
614 TaggedParserAtomIndex taggedIndex
) const;
615 JSAtom
* getAtomAt(ParserAtomIndex index
) const;
617 bool hasAtomAt(ParserAtomIndex index
) const;
618 bool setAtomAt(FrontendContext
* fc
, ParserAtomIndex index
, JSString
* atom
);
619 bool allocate(FrontendContext
* fc
, size_t length
);
621 bool empty() const { return atoms_
.empty(); }
622 size_t size() const { return atoms_
.length(); }
624 void stealBuffer(AtomCacheVector
& atoms
);
625 void releaseBuffer(AtomCacheVector
& atoms
);
627 void trace(JSTracer
* trc
);
629 size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf
) const {
630 return atoms_
.sizeOfExcludingThis(mallocSizeOf
);
634 // Information associated with an extra binding provided to a global script.
635 // See frontend::CompileGlobalScriptWithExtraBindings.
636 struct ExtraBindingInfo
{
637 // UTF-8 encoded name of the binding.
638 UniqueChars nameChars
;
640 TaggedParserAtomIndex nameIndex
;
642 // If the binding conflicts with global variable or global lexical variable,
643 // the binding is shadowed.
644 bool isShadowed
= false;
646 ExtraBindingInfo(UniqueChars
&& nameChars
, bool isShadowed
)
647 : nameChars(std::move(nameChars
)), isShadowed(isShadowed
) {}
650 using ExtraBindingInfoVector
=
651 js::Vector
<ExtraBindingInfo
, 0, js::SystemAllocPolicy
>;
653 // Input of the compilation, including source and enclosing context.
654 struct CompilationInput
{
655 enum class CompilationTarget
{
659 StandaloneFunctionInNonSyntacticScope
,
664 CompilationTarget target
= CompilationTarget::Global
;
666 const JS::ReadOnlyCompileOptions
& options
;
668 CompilationAtomCache atomCache
;
671 InputScript lazy_
= InputScript(nullptr);
673 // Extra bindings for the global script.
674 ExtraBindingInfoVector
* maybeExtraBindings_
= nullptr;
677 RefPtr
<ScriptSource
> source
;
679 // * If the target is Global, null.
680 // * If the target is SelfHosting, null. Instantiation code for self-hosting
681 // will ignore this and use the appropriate empty global scope instead.
682 // * If the target is StandaloneFunction, an empty global scope.
683 // * If the target is StandaloneFunctionInNonSyntacticScope, the non-null
684 // enclosing scope of the function
685 // * If the target is Eval, the non-null enclosing scope of the `eval`.
686 // * If the target is Module, null that means empty global scope
687 // (See EmitterScope::checkEnvironmentChainLength)
688 // * If the target is Delazification, the non-null enclosing scope of
690 InputScope enclosingScope
= InputScope(nullptr);
692 explicit CompilationInput(const JS::ReadOnlyCompileOptions
& options
)
693 : options(options
) {}
696 bool initScriptSource(FrontendContext
* fc
);
699 bool initForGlobal(FrontendContext
* fc
) {
700 target
= CompilationTarget::Global
;
701 return initScriptSource(fc
);
704 bool initForGlobalWithExtraBindings(
705 FrontendContext
* fc
, ExtraBindingInfoVector
* maybeExtraBindings
) {
706 MOZ_ASSERT(maybeExtraBindings
);
707 target
= CompilationTarget::Global
;
708 maybeExtraBindings_
= maybeExtraBindings
;
709 return initScriptSource(fc
);
712 bool initForSelfHostingGlobal(FrontendContext
* fc
) {
713 target
= CompilationTarget::SelfHosting
;
714 return initScriptSource(fc
);
717 bool initForStandaloneFunction(JSContext
* cx
, FrontendContext
* fc
) {
718 target
= CompilationTarget::StandaloneFunction
;
719 if (!initScriptSource(fc
)) {
722 enclosingScope
= InputScope(&cx
->global()->emptyGlobalScope());
726 bool initForStandaloneFunctionInNonSyntacticScope(
727 FrontendContext
* fc
, JS::Handle
<Scope
*> functionEnclosingScope
);
729 bool initForEval(FrontendContext
* fc
, JS::Handle
<Scope
*> evalEnclosingScope
) {
730 target
= CompilationTarget::Eval
;
731 if (!initScriptSource(fc
)) {
734 enclosingScope
= InputScope(evalEnclosingScope
);
738 bool initForModule(FrontendContext
* fc
) {
739 target
= CompilationTarget::Module
;
740 if (!initScriptSource(fc
)) {
743 // The `enclosingScope` is the emptyGlobalScope.
747 void initFromLazy(JSContext
* cx
, BaseScript
* lazyScript
, ScriptSource
* ss
) {
748 MOZ_ASSERT(cx
->compartment() == lazyScript
->compartment());
750 // We can only compile functions whose parents have previously been
751 // compiled, because compilation requires full information about the
752 // function's immediately enclosing scope.
753 MOZ_ASSERT(lazyScript
->isReadyForDelazification());
754 target
= CompilationTarget::Delazification
;
755 lazy_
= InputScript(lazyScript
);
757 enclosingScope
= lazy_
.enclosingScope();
760 void initFromStencil(CompilationStencil
& context
, ScriptIndex scriptIndex
,
762 target
= CompilationTarget::Delazification
;
763 lazy_
= InputScript(context
, scriptIndex
);
765 enclosingScope
= lazy_
.enclosingScope();
768 // Returns true if enclosingScope field is provided to init* function,
769 // instead of setting to empty global internally.
770 bool hasNonDefaultEnclosingScope() const {
771 return target
== CompilationTarget::StandaloneFunctionInNonSyntacticScope
||
772 target
== CompilationTarget::Eval
||
773 target
== CompilationTarget::Delazification
;
776 // Returns the enclosing scope provided to init* function.
777 // nullptr otherwise.
778 InputScope
maybeNonDefaultEnclosingScope() const {
779 if (hasNonDefaultEnclosingScope()) {
780 return enclosingScope
;
782 return InputScope(nullptr);
785 // The BaseScript* is needed when instantiating a lazy function.
786 // See InstantiateTopLevel and FunctionsFromExistingLazy.
787 InputScript
lazyOuterScript() { return lazy_
; }
788 BaseScript
* lazyOuterBaseScript() { return lazy_
.raw().as
<BaseScript
*>(); }
790 // The JSFunction* is needed when instantiating a lazy function.
791 // See FunctionsFromExistingLazy.
792 JSFunction
* function() const {
793 return lazy_
.raw().as
<BaseScript
*>()->function();
796 // When compiling an inner function, we want to know the unique identifier
797 // which identify a function. This is computed from the source extend.
798 SourceExtent
extent() const { return lazy_
.extent(); }
800 // See `BaseScript::immutableFlags_`.
801 ImmutableScriptFlags
immutableFlags() const { return lazy_
.immutableFlags(); }
803 RO_IMMUTABLE_SCRIPT_FLAGS(immutableFlags())
805 FunctionFlags
functionFlags() const { return lazy_
.functionFlags(); }
807 // When delazifying, return the kind of function which is defined.
808 FunctionSyntaxKind
functionSyntaxKind() const;
810 bool hasPrivateScriptData() const {
811 // This is equivalent to: ngcthings != 0 || useMemberInitializers()
812 // See BaseScript::CreateRawLazy.
813 return lazy_
.hasPrivateScriptData();
816 // Whether this CompilationInput is parsing the top-level of a script, or
817 // false if we are parsing an inner function.
818 bool isInitialStencil() { return lazy_
.isNull(); }
820 // Whether this CompilationInput is parsing a specific function with already
821 // pre-parsed contextual information.
822 bool isDelazifying() { return target
== CompilationTarget::Delazification
; }
824 bool hasExtraBindings() const { return !!maybeExtraBindings_
; }
825 ExtraBindingInfoVector
& extraBindings() { return *maybeExtraBindings_
; }
826 const ExtraBindingInfoVector
& extraBindings() const {
827 return *maybeExtraBindings_
;
829 bool internExtraBindings(FrontendContext
* fc
, ParserAtomsTable
& parserAtoms
);
831 void trace(JSTracer
* trc
);
833 // Size of dynamic data. Note that GC data is counted by GC and not here. We
834 // also ignore ScriptSource which is a shared RefPtr.
835 size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf
) const {
836 return atomCache
.sizeOfExcludingThis(mallocSizeOf
);
838 size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf
) const {
839 return mallocSizeOf(this) + sizeOfExcludingThis(mallocSizeOf
);
842 #if defined(DEBUG) || defined(JS_JITSPEW)
844 void dump(js::JSONPrinter
& json
) const;
845 void dumpFields(js::JSONPrinter
& json
) const;
849 // When compiling a function which was previously Syntaxly Parsed, we generated
850 // some information which made it possible to skip over some parsing phases,
851 // such as computing closed over bindings as well as parsing inner functions.
852 // This class contains all information which is generated by the SyntaxParse and
853 // reused in the FullParse.
854 class CompilationSyntaxParseCache
{
855 // When delazifying, we should prepare an array which contains all
856 // stencil-like gc-things such that it can be used by the parser.
858 // When compiling from a Stencil, this will alias the existing Stencil.
859 mozilla::Span
<TaggedScriptThingIndex
> cachedGCThings_
;
861 // When delazifying, we should perpare an array which contains all
862 // stencil-like information about scripts, such that it can be used by the
865 // When compiling from a Stencil, these will alias the existing Stencil.
866 mozilla::Span
<ScriptStencil
> cachedScriptData_
;
867 mozilla::Span
<ScriptStencilExtra
> cachedScriptExtra_
;
869 // When delazifying, we copy the atom, either from JSAtom, or from another
870 // Stencil into TaggedParserAtomIndex which are valid in this current
872 mozilla::Span
<TaggedParserAtomIndex
> closedOverBindings_
;
874 // Atom of the function being compiled. This atom index is valid in the
875 // current CompilationState.
876 TaggedParserAtomIndex displayAtom_
;
878 // Stencil-like data about the function which is being compiled.
879 ScriptStencilExtra funExtra_
;
882 // Whether any of these data should be considered or not.
883 bool isInitialized
= false;
887 // When doing a full-parse of an incomplete BaseScript*, we have to iterate
888 // over functions and closed-over bindings, to avoid costly recursive decent
889 // in inner functions. This function will clone the BaseScript* information to
890 // make it available as a stencil-like data to the full-parser.
891 mozilla::Span
<TaggedParserAtomIndex
> closedOverBindings() const {
892 MOZ_ASSERT(isInitialized
);
893 return closedOverBindings_
;
895 const ScriptStencil
& scriptData(size_t functionIndex
) const {
896 return cachedScriptData_
[scriptIndex(functionIndex
)];
898 const ScriptStencilExtra
& scriptExtra(size_t functionIndex
) const {
899 return cachedScriptExtra_
[scriptIndex(functionIndex
)];
902 // Return the name of the function being delazified, if any.
903 TaggedParserAtomIndex
displayAtom() const {
904 MOZ_ASSERT(isInitialized
);
908 // Return the extra information about the function being delazified, if any.
909 const ScriptStencilExtra
& funExtra() const {
910 MOZ_ASSERT(isInitialized
);
914 // Initialize the SynaxParse cache given a LifoAlloc. The JSContext is only
915 // used for reporting allocation errors.
916 [[nodiscard
]] bool init(FrontendContext
* fc
, LifoAlloc
& alloc
,
917 ParserAtomsTable
& parseAtoms
,
918 CompilationAtomCache
& atomCache
,
919 const InputScript
& lazy
);
922 // Return the script index of a given inner function.
924 // WARNING: The ScriptIndex returned by this function corresponds to the index
925 // in the cachedScriptExtra_ and cachedScriptData_ spans. With the
926 // cachedGCThings_ span, these might be reference to an actual Stencil from
927 // another compilation. Thus, the ScriptIndex returned by this function should
928 // not be confused with any ScriptIndex from the CompilationState.
929 ScriptIndex
scriptIndex(size_t functionIndex
) const {
930 MOZ_ASSERT(isInitialized
);
931 auto taggedScriptIndex
= cachedGCThings_
[functionIndex
];
932 MOZ_ASSERT(taggedScriptIndex
.isFunction());
933 return taggedScriptIndex
.toFunction();
936 [[nodiscard
]] bool copyFunctionInfo(FrontendContext
* fc
,
937 ParserAtomsTable
& parseAtoms
,
938 CompilationAtomCache
& atomCache
,
939 const InputScript
& lazy
);
940 [[nodiscard
]] bool copyScriptInfo(FrontendContext
* fc
, LifoAlloc
& alloc
,
941 ParserAtomsTable
& parseAtoms
,
942 CompilationAtomCache
& atomCache
,
944 [[nodiscard
]] bool copyScriptInfo(FrontendContext
* fc
, LifoAlloc
& alloc
,
945 ParserAtomsTable
& parseAtoms
,
946 CompilationAtomCache
& atomCache
,
947 const ScriptStencilRef
& lazy
);
948 [[nodiscard
]] bool copyClosedOverBindings(FrontendContext
* fc
,
950 ParserAtomsTable
& parseAtoms
,
951 CompilationAtomCache
& atomCache
,
953 [[nodiscard
]] bool copyClosedOverBindings(FrontendContext
* fc
,
955 ParserAtomsTable
& parseAtoms
,
956 CompilationAtomCache
& atomCache
,
957 const ScriptStencilRef
& lazy
);
960 // AsmJS scripts are very rare on-average, so we use a HashMap to associate
961 // data with a ScriptStencil. The ScriptStencil has a flag to indicate if we
962 // need to even do this lookup.
963 using StencilAsmJSMap
=
964 mozilla::HashMap
<ScriptIndex
, RefPtr
<const JS::WasmModule
>,
965 mozilla::DefaultHasher
<ScriptIndex
>,
966 js::SystemAllocPolicy
>;
968 struct StencilAsmJSContainer
969 : public js::AtomicRefCounted
<StencilAsmJSContainer
> {
970 StencilAsmJSMap moduleMap
;
972 StencilAsmJSContainer() = default;
974 size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf
) const {
975 return moduleMap
.shallowSizeOfExcludingThis(mallocSizeOf
);
977 size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf
) const {
978 return mallocSizeOf(this) + sizeOfExcludingThis(mallocSizeOf
);
982 // Store shared data for non-lazy script.
983 struct SharedDataContainer
{
984 // NOTE: While stored, we must hold a ref-count and care must be taken when
985 // updating or clearing the pointer.
986 using SingleSharedDataPtr
= SharedImmutableScriptData
*;
988 using SharedDataVector
=
989 Vector
<RefPtr
<js::SharedImmutableScriptData
>, 0, js::SystemAllocPolicy
>;
990 using SharedDataVectorPtr
= SharedDataVector
*;
992 using SharedDataMap
=
993 mozilla::HashMap
<ScriptIndex
, RefPtr
<js::SharedImmutableScriptData
>,
994 mozilla::DefaultHasher
<ScriptIndex
>,
995 js::SystemAllocPolicy
>;
996 using SharedDataMapPtr
= SharedDataMap
*;
1008 uintptr_t data_
= 0;
1011 // Defaults to SingleSharedData.
1012 SharedDataContainer() = default;
1014 SharedDataContainer(const SharedDataContainer
&) = delete;
1015 SharedDataContainer(SharedDataContainer
&& other
) noexcept
{
1016 std::swap(data_
, other
.data_
);
1017 MOZ_ASSERT(other
.isEmpty());
1020 SharedDataContainer
& operator=(const SharedDataContainer
&) = delete;
1021 SharedDataContainer
& operator=(SharedDataContainer
&& other
) noexcept
{
1022 std::swap(data_
, other
.data_
);
1023 MOZ_ASSERT(other
.isEmpty());
1027 ~SharedDataContainer();
1029 [[nodiscard
]] bool initVector(FrontendContext
* fc
);
1030 [[nodiscard
]] bool initMap(FrontendContext
* fc
);
1033 [[nodiscard
]] bool convertFromSingleToMap(FrontendContext
* fc
);
1036 bool isEmpty() const { return (data_
) == SingleTag
; }
1037 bool isSingle() const { return (data_
& TagMask
) == SingleTag
; }
1038 bool isVector() const { return (data_
& TagMask
) == VectorTag
; }
1039 bool isMap() const { return (data_
& TagMask
) == MapTag
; }
1040 bool isBorrow() const { return (data_
& TagMask
) == BorrowTag
; }
1042 void setSingle(already_AddRefed
<SharedImmutableScriptData
>&& data
) {
1043 MOZ_ASSERT(isEmpty());
1044 data_
= reinterpret_cast<uintptr_t>(data
.take());
1045 MOZ_ASSERT(isSingle());
1046 MOZ_ASSERT(!isEmpty());
1049 void setBorrow(SharedDataContainer
* sharedData
) {
1050 MOZ_ASSERT(isEmpty());
1051 data_
= reinterpret_cast<uintptr_t>(sharedData
) | BorrowTag
;
1052 MOZ_ASSERT(isBorrow());
1055 SingleSharedDataPtr
asSingle() const {
1056 MOZ_ASSERT(isSingle());
1057 MOZ_ASSERT(!isEmpty());
1058 static_assert(SingleTag
== 0);
1059 return reinterpret_cast<SingleSharedDataPtr
>(data_
);
1061 SharedDataVectorPtr
asVector() const {
1062 MOZ_ASSERT(isVector());
1063 return reinterpret_cast<SharedDataVectorPtr
>(data_
& ~TagMask
);
1065 SharedDataMapPtr
asMap() const {
1066 MOZ_ASSERT(isMap());
1067 return reinterpret_cast<SharedDataMapPtr
>(data_
& ~TagMask
);
1069 SharedDataContainer
* asBorrow() const {
1070 MOZ_ASSERT(isBorrow());
1071 return reinterpret_cast<SharedDataContainer
*>(data_
& ~TagMask
);
1074 [[nodiscard
]] bool prepareStorageFor(FrontendContext
* fc
,
1075 size_t nonLazyScriptCount
,
1076 size_t allScriptCount
);
1077 [[nodiscard
]] bool cloneFrom(FrontendContext
* fc
,
1078 const SharedDataContainer
& other
);
1080 // Returns index-th script's shared data, or nullptr if it doesn't have.
1081 js::SharedImmutableScriptData
* get(ScriptIndex index
) const;
1083 // Add data for index-th script and share it with VM.
1084 [[nodiscard
]] bool addAndShare(FrontendContext
* fc
, ScriptIndex index
,
1085 js::SharedImmutableScriptData
* data
);
1087 // Add data for index-th script without sharing it with VM.
1088 // The data should already be shared with VM.
1090 // The data is supposed to be added from delazification.
1091 [[nodiscard
]] bool addExtraWithoutShare(FrontendContext
* fc
,
1093 js::SharedImmutableScriptData
* data
);
1095 // Dynamic memory associated with this container. Does not include the
1096 // SharedImmutableScriptData since we are not the unique owner of it.
1097 size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf
) const {
1099 return asVector()->sizeOfIncludingThis(mallocSizeOf
);
1102 return asMap()->shallowSizeOfIncludingThis(mallocSizeOf
);
1104 MOZ_ASSERT(isSingle() || isBorrow());
1108 #if defined(DEBUG) || defined(JS_JITSPEW)
1110 void dump(js::JSONPrinter
& json
) const;
1111 void dumpFields(js::JSONPrinter
& json
) const;
1115 struct ExtensibleCompilationStencil
;
1117 // The top level struct of stencil specialized for non-extensible case.
1118 // Used as the compilation output, and also XDR decode output.
1120 // In XDR decode output case, the span and not-owning pointer fields point
1121 // the internal LifoAlloc and the external XDR buffer.
1123 // In BorrowingCompilationStencil usage, span and not-owning pointer fields
1124 // point the ExtensibleCompilationStencil and its LifoAlloc.
1126 // The dependent XDR buffer or ExtensibleCompilationStencil must be kept
1129 // See SMDOC in Stencil.h for more info.
1130 struct CompilationStencil
{
1131 friend struct ExtensibleCompilationStencil
;
1133 static constexpr ScriptIndex TopLevelIndex
= ScriptIndex(0);
1135 static constexpr size_t LifoAllocChunkSize
= 512;
1137 // The lifetime of this CompilationStencil may be managed by stack allocation,
1138 // UniquePtr<T>, or RefPtr<T>. If a RefPtr is used, this ref-count will track
1139 // the lifetime, otherwise it is ignored.
1141 // NOTE: Internal code and public APIs use a mix of these different allocation
1144 // See: JS::StencilAddRef/Release
1145 mutable mozilla::Atomic
<uintptr_t> refCount
{0};
1148 // On-heap ExtensibleCompilationStencil that this CompilationStencil owns,
1149 // and this CompilationStencil borrows each data from.
1150 UniquePtr
<ExtensibleCompilationStencil
> ownedBorrowStencil
;
1153 enum class StorageType
{
1154 // Pointers and spans point LifoAlloc or owned buffer.
1157 // Pointers and spans point external data, such as XDR buffer, or not-owned
1158 // ExtensibleCompilationStencil (see BorrowingCompilationStencil).
1161 // Pointers and spans point data owned by ownedBorrowStencil.
1164 StorageType storageType
= StorageType::Owned
;
1166 // Value of CanLazilyParse(CompilationInput) on compilation.
1167 // Used during instantiation.
1168 bool canLazilyParse
= false;
1170 // If this stencil is a delazification, this identifies location of the
1171 // function in the source text.
1172 using FunctionKey
= SourceExtent::FunctionKey
;
1173 FunctionKey functionKey
= SourceExtent::NullFunctionKey
;
1175 // This holds allocations that do not require destructors to be run but are
1176 // live until the stencil is released.
1179 // The source text holder for the script. This may be an empty placeholder if
1180 // the code will fully parsed and options indicate the source will never be
1182 RefPtr
<ScriptSource
> source
;
1184 // Stencil for all function and non-function scripts. The TopLevelIndex is
1185 // reserved for the top-level script. This top-level may or may not be a
1187 mozilla::Span
<ScriptStencil
> scriptData
;
1189 // Immutable data computed during initial compilation and never updated during
1191 mozilla::Span
<ScriptStencilExtra
> scriptExtra
;
1193 mozilla::Span
<TaggedScriptThingIndex
> gcThingData
;
1195 // scopeData and scopeNames have the same size, and i-th scopeNames contains
1196 // the names for the bindings contained in the slot defined by i-th scopeData.
1197 mozilla::Span
<ScopeStencil
> scopeData
;
1198 mozilla::Span
<BaseParserScopeData
*> scopeNames
;
1200 // Hold onto the RegExpStencil, BigIntStencil, and ObjLiteralStencil that are
1201 // allocated during parse to ensure correct destruction.
1202 mozilla::Span
<RegExpStencil
> regExpData
;
1203 mozilla::Span
<BigIntStencil
> bigIntData
;
1204 mozilla::Span
<ObjLiteralStencil
> objLiteralData
;
1206 // List of parser atoms for this compilation. This may contain nullptr entries
1207 // when round-tripping with XDR if the atom was generated in original parse
1208 // but not used by stencil.
1209 ParserAtomSpan parserAtomData
;
1211 // Variable sized container for bytecode and other immutable data. A valid
1212 // stencil always contains at least an entry for `TopLevelIndex` script.
1213 SharedDataContainer sharedData
;
1215 // Module metadata if this is a module compile.
1216 RefPtr
<StencilModuleMetadata
> moduleMetadata
;
1218 // AsmJS modules generated by parsing. These scripts are never lazy and
1219 // therefore only generated during initial parse.
1220 RefPtr
<StencilAsmJSContainer
> asmJS
;
1224 // Construct a CompilationStencil
1225 explicit CompilationStencil(ScriptSource
* source
)
1226 : alloc(LifoAllocChunkSize
), source(source
) {}
1228 // Take the ownership of on-heap ExtensibleCompilationStencil and
1230 explicit CompilationStencil(
1231 UniquePtr
<ExtensibleCompilationStencil
>&& extensibleStencil
);
1234 void borrowFromExtensibleCompilationStencil(
1235 ExtensibleCompilationStencil
& extensibleStencil
);
1238 void assertBorrowingFromExtensibleCompilationStencil(
1239 const ExtensibleCompilationStencil
& extensibleStencil
) const;
1243 bool isInitialStencil() const {
1244 return functionKey
== SourceExtent::NullFunctionKey
;
1247 [[nodiscard
]] static bool instantiateStencilAfterPreparation(
1248 JSContext
* cx
, CompilationInput
& input
, const CompilationStencil
& stencil
,
1249 CompilationGCOutput
& gcOutput
);
1251 [[nodiscard
]] static bool prepareForInstantiate(
1252 FrontendContext
* fc
, CompilationAtomCache
& atomCache
,
1253 const CompilationStencil
& stencil
, CompilationGCOutput
& gcOutput
);
1254 [[nodiscard
]] static bool prepareForInstantiate(
1255 FrontendContext
* fc
, const CompilationStencil
& stencil
,
1256 PreallocatedCompilationGCOutput
& gcOutput
);
1258 [[nodiscard
]] static bool instantiateStencils(
1259 JSContext
* cx
, CompilationInput
& input
, const CompilationStencil
& stencil
,
1260 CompilationGCOutput
& gcOutput
);
1262 // Decode the special self-hosted stencil
1263 [[nodiscard
]] bool instantiateSelfHostedAtoms(
1264 JSContext
* cx
, AtomSet
& atomSet
, CompilationAtomCache
& atomCache
) const;
1265 [[nodiscard
]] JSScript
* instantiateSelfHostedTopLevelForRealm(
1266 JSContext
* cx
, CompilationInput
& input
);
1267 [[nodiscard
]] JSFunction
* instantiateSelfHostedLazyFunction(
1268 JSContext
* cx
, CompilationAtomCache
& atomCache
, ScriptIndex index
,
1269 JS::Handle
<JSAtom
*> name
);
1270 [[nodiscard
]] bool delazifySelfHostedFunction(JSContext
* cx
,
1271 CompilationAtomCache
& atomCache
,
1272 ScriptIndexRange range
,
1273 JS::Handle
<JSFunction
*> fun
);
1275 [[nodiscard
]] bool serializeStencils(JSContext
* cx
, CompilationInput
& input
,
1276 JS::TranscodeBuffer
& buf
,
1277 bool* succeededOut
= nullptr) const;
1278 [[nodiscard
]] bool deserializeStencils(
1279 FrontendContext
* fc
, const JS::ReadOnlyCompileOptions
& options
,
1280 const JS::TranscodeRange
& range
, bool* succeededOut
= nullptr);
1282 // To avoid any misuses, make sure this is neither copyable or assignable.
1283 CompilationStencil(const CompilationStencil
&) = delete;
1284 CompilationStencil(CompilationStencil
&&) = delete;
1285 CompilationStencil
& operator=(const CompilationStencil
&) = delete;
1286 CompilationStencil
& operator=(CompilationStencil
&&) = delete;
1288 ~CompilationStencil() {
1289 // We can mix UniquePtr<..> and RefPtr<..>. This asserts that a UniquePtr
1290 // does not delete a reference-counted stencil.
1291 MOZ_ASSERT(!refCount
);
1295 static inline ScriptStencilIterable
functionScriptStencils(
1296 const CompilationStencil
& stencil
, CompilationGCOutput
& gcOutput
);
1298 void setFunctionKey(BaseScript
* lazy
) {
1299 functionKey
= lazy
->extent().toFunctionKey();
1302 inline size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf
) const;
1303 size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf
) const {
1304 return mallocSizeOf(this) + sizeOfExcludingThis(mallocSizeOf
);
1307 const ParserAtomSpan
& parserAtomsSpan() const { return parserAtomData
; }
1309 bool isModule() const;
1311 bool hasMultipleReference() const { return refCount
> 1; }
1313 bool hasOwnedBorrow() const {
1314 return storageType
== StorageType::OwnedExtensible
;
1317 ExtensibleCompilationStencil
* takeOwnedBorrow() {
1318 MOZ_ASSERT(!hasMultipleReference());
1319 MOZ_ASSERT(hasOwnedBorrow());
1320 return ownedBorrowStencil
.release();
1324 void assertNoExternalDependency() const;
1327 #if defined(DEBUG) || defined(JS_JITSPEW)
1329 void dump(js::JSONPrinter
& json
) const;
1330 void dumpFields(js::JSONPrinter
& json
) const;
1332 void dumpAtom(TaggedParserAtomIndex index
) const;
1336 // The top level struct of stencil specialized for extensible case.
1337 // Used as the temporary storage during compilation, an the compilation output.
1339 // All not-owning pointer fields point the internal LifoAlloc.
1341 // See CompilationStencil for each field's description.
1343 // Also see SMDOC in Stencil.h for more info.
1344 struct ExtensibleCompilationStencil
{
1345 bool canLazilyParse
= false;
1347 using FunctionKey
= SourceExtent::FunctionKey
;
1349 FunctionKey functionKey
= SourceExtent::NullFunctionKey
;
1351 // Data pointed by other fields are allocated in this LifoAlloc,
1352 // and moved to `CompilationStencil.alloc`.
1355 RefPtr
<ScriptSource
> source
;
1357 // NOTE: We reserve a modest amount of inline storage in order to reduce
1358 // allocations in the most common delazification cases. These common
1359 // cases have one script and scope, as well as a handful of gcthings.
1360 // For complex pages this covers about 75% of delazifications.
1362 Vector
<ScriptStencil
, 1, js::SystemAllocPolicy
> scriptData
;
1363 Vector
<ScriptStencilExtra
, 0, js::SystemAllocPolicy
> scriptExtra
;
1365 Vector
<TaggedScriptThingIndex
, 8, js::SystemAllocPolicy
> gcThingData
;
1367 Vector
<ScopeStencil
, 1, js::SystemAllocPolicy
> scopeData
;
1368 Vector
<BaseParserScopeData
*, 1, js::SystemAllocPolicy
> scopeNames
;
1370 Vector
<RegExpStencil
, 0, js::SystemAllocPolicy
> regExpData
;
1371 Vector
<BigIntStencil
, 0, js::SystemAllocPolicy
> bigIntData
;
1372 Vector
<ObjLiteralStencil
, 0, js::SystemAllocPolicy
> objLiteralData
;
1374 // Table of parser atoms for this compilation.
1375 ParserAtomsTable parserAtoms
;
1377 SharedDataContainer sharedData
;
1379 RefPtr
<StencilModuleMetadata
> moduleMetadata
;
1381 RefPtr
<StencilAsmJSContainer
> asmJS
;
1383 explicit ExtensibleCompilationStencil(ScriptSource
* source
);
1385 explicit ExtensibleCompilationStencil(CompilationInput
& input
);
1386 ExtensibleCompilationStencil(const JS::ReadOnlyCompileOptions
& options
,
1387 RefPtr
<ScriptSource
> source
);
1389 ExtensibleCompilationStencil(ExtensibleCompilationStencil
&& other
) noexcept
1390 : canLazilyParse(other
.canLazilyParse
),
1391 functionKey(other
.functionKey
),
1392 alloc(CompilationStencil::LifoAllocChunkSize
),
1393 source(std::move(other
.source
)),
1394 scriptData(std::move(other
.scriptData
)),
1395 scriptExtra(std::move(other
.scriptExtra
)),
1396 gcThingData(std::move(other
.gcThingData
)),
1397 scopeData(std::move(other
.scopeData
)),
1398 scopeNames(std::move(other
.scopeNames
)),
1399 regExpData(std::move(other
.regExpData
)),
1400 bigIntData(std::move(other
.bigIntData
)),
1401 objLiteralData(std::move(other
.objLiteralData
)),
1402 parserAtoms(std::move(other
.parserAtoms
)),
1403 sharedData(std::move(other
.sharedData
)),
1404 moduleMetadata(std::move(other
.moduleMetadata
)),
1405 asmJS(std::move(other
.asmJS
)) {
1406 alloc
.steal(&other
.alloc
);
1407 parserAtoms
.fixupAlloc(alloc
);
1410 ExtensibleCompilationStencil
& operator=(
1411 ExtensibleCompilationStencil
&& other
) noexcept
{
1412 MOZ_ASSERT(alloc
.isEmpty());
1414 canLazilyParse
= other
.canLazilyParse
;
1415 functionKey
= other
.functionKey
;
1416 source
= std::move(other
.source
);
1417 scriptData
= std::move(other
.scriptData
);
1418 scriptExtra
= std::move(other
.scriptExtra
);
1419 gcThingData
= std::move(other
.gcThingData
);
1420 scopeData
= std::move(other
.scopeData
);
1421 scopeNames
= std::move(other
.scopeNames
);
1422 regExpData
= std::move(other
.regExpData
);
1423 bigIntData
= std::move(other
.bigIntData
);
1424 objLiteralData
= std::move(other
.objLiteralData
);
1425 parserAtoms
= std::move(other
.parserAtoms
);
1426 sharedData
= std::move(other
.sharedData
);
1427 moduleMetadata
= std::move(other
.moduleMetadata
);
1428 asmJS
= std::move(other
.asmJS
);
1430 alloc
.steal(&other
.alloc
);
1431 parserAtoms
.fixupAlloc(alloc
);
1436 void setFunctionKey(const SourceExtent
& extent
) {
1437 functionKey
= extent
.toFunctionKey();
1440 bool isInitialStencil() const {
1441 return functionKey
== SourceExtent::NullFunctionKey
;
1444 // Steal CompilationStencil content.
1445 [[nodiscard
]] bool steal(FrontendContext
* fc
,
1446 RefPtr
<CompilationStencil
>&& other
);
1448 // Clone ExtensibleCompilationStencil content.
1449 [[nodiscard
]] bool cloneFrom(FrontendContext
* fc
,
1450 const CompilationStencil
& other
);
1451 [[nodiscard
]] bool cloneFrom(FrontendContext
* fc
,
1452 const ExtensibleCompilationStencil
& other
);
1455 template <typename Stencil
>
1456 [[nodiscard
]] bool cloneFromImpl(FrontendContext
* fc
, const Stencil
& other
);
1459 const ParserAtomVector
& parserAtomsSpan() const {
1460 return parserAtoms
.entries();
1463 bool isModule() const;
1465 inline size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf
) const;
1466 size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf
) const {
1467 return mallocSizeOf(this) + sizeOfExcludingThis(mallocSizeOf
);
1471 void assertNoExternalDependency() const;
1474 #if defined(DEBUG) || defined(JS_JITSPEW)
1476 void dump(js::JSONPrinter
& json
);
1477 void dumpFields(js::JSONPrinter
& json
);
1479 void dumpAtom(TaggedParserAtomIndex index
);
1483 // The internal state of the compilation.
1484 struct MOZ_RAII CompilationState
: public ExtensibleCompilationStencil
{
1485 Directives directives
;
1487 ScopeContext scopeContext
;
1489 UsedNameTracker usedNames
;
1491 // LifoAlloc scope used by Parser for allocating AST etc.
1493 // NOTE: This is not used for ExtensibleCompilationStencil.alloc.
1494 LifoAllocScope
& parserAllocScope
;
1496 CompilationInput
& input
;
1497 CompilationSyntaxParseCache previousParseCache
;
1499 // The number of functions that *will* have bytecode.
1500 // This doesn't count top-level non-function script.
1502 // This should be counted while parsing, and should be passed to
1503 // SharedDataContainer.prepareStorageFor *before* start emitting bytecode.
1504 size_t nonLazyFunctionCount
= 0;
1508 CompilationState(FrontendContext
* fc
, LifoAllocScope
& parserAllocScope
,
1509 CompilationInput
& input
);
1511 bool init(FrontendContext
* fc
, ScopeBindingCache
* scopeCache
,
1512 InheritThis inheritThis
= InheritThis::No
,
1513 JSObject
* enclosingEnv
= nullptr) {
1514 if (!scopeContext
.init(fc
, input
, parserAtoms
, scopeCache
, inheritThis
,
1519 // gcThings is later used by the full parser initialization.
1520 if (input
.isDelazifying()) {
1521 InputScript lazy
= input
.lazyOuterScript();
1522 auto& atomCache
= input
.atomCache
;
1523 if (!previousParseCache
.init(fc
, alloc
, parserAtoms
, atomCache
, lazy
)) {
1531 // Track the state of key allocations and roll them back as parts of parsing
1532 // get retried. This ensures iteration during stencil instantiation does not
1533 // encounter discarded frontend state.
1534 struct CompilationStatePosition
{
1535 // Temporarily share this token struct with CompilationState.
1536 size_t scriptDataLength
= 0;
1538 size_t asmJSCount
= 0;
1541 bool prepareSharedDataStorage(FrontendContext
* fc
);
1543 CompilationStatePosition
getPosition();
1544 void rewind(const CompilationStatePosition
& pos
);
1546 // When parsing arrow function, parameter is parsed twice, and if there are
1547 // functions inside parameter expression, stencils will be created for them.
1549 // Those functions exist only for lazy parsing.
1550 // Mark them "ghost", so that they don't affect other parts.
1552 // See GHOST_FUNCTION in FunctionFlags.h for more details.
1553 void markGhost(const CompilationStatePosition
& pos
);
1555 // Allocate space for `length` gcthings, and return the address of the
1556 // first element to `cursor` to initialize on the caller.
1557 bool allocateGCThingsUninitialized(FrontendContext
* fc
,
1558 ScriptIndex scriptIndex
, size_t length
,
1559 TaggedScriptThingIndex
** cursor
);
1561 bool appendScriptStencilAndData(FrontendContext
* fc
);
1563 bool appendGCThings(FrontendContext
* fc
, ScriptIndex scriptIndex
,
1564 mozilla::Span
<const TaggedScriptThingIndex
> things
);
1567 // A temporary CompilationStencil instance that borrows
1568 // ExtensibleCompilationStencil data.
1569 // Ensure that this instance does not outlive the ExtensibleCompilationStencil.
1570 class MOZ_STACK_CLASS BorrowingCompilationStencil
: public CompilationStencil
{
1572 explicit BorrowingCompilationStencil(
1573 ExtensibleCompilationStencil
& extensibleStencil
);
1576 // Size of dynamic data. Ignores Spans (unless their contents are in the
1577 // LifoAlloc) and RefPtrs since we are not the unique owner.
1578 inline size_t CompilationStencil::sizeOfExcludingThis(
1579 mozilla::MallocSizeOf mallocSizeOf
) const {
1580 if (ownedBorrowStencil
) {
1581 return ownedBorrowStencil
->sizeOfIncludingThis(mallocSizeOf
);
1584 size_t moduleMetadataSize
=
1585 moduleMetadata
? moduleMetadata
->sizeOfIncludingThis(mallocSizeOf
) : 0;
1586 size_t asmJSSize
= asmJS
? asmJS
->sizeOfIncludingThis(mallocSizeOf
) : 0;
1588 return alloc
.sizeOfExcludingThis(mallocSizeOf
) +
1589 sharedData
.sizeOfExcludingThis(mallocSizeOf
) + moduleMetadataSize
+
1593 inline size_t ExtensibleCompilationStencil::sizeOfExcludingThis(
1594 mozilla::MallocSizeOf mallocSizeOf
) const {
1595 size_t moduleMetadataSize
=
1596 moduleMetadata
? moduleMetadata
->sizeOfIncludingThis(mallocSizeOf
) : 0;
1597 size_t asmJSSize
= asmJS
? asmJS
->sizeOfIncludingThis(mallocSizeOf
) : 0;
1599 return alloc
.sizeOfExcludingThis(mallocSizeOf
) +
1600 scriptData
.sizeOfExcludingThis(mallocSizeOf
) +
1601 scriptExtra
.sizeOfExcludingThis(mallocSizeOf
) +
1602 gcThingData
.sizeOfExcludingThis(mallocSizeOf
) +
1603 scopeData
.sizeOfExcludingThis(mallocSizeOf
) +
1604 scopeNames
.sizeOfExcludingThis(mallocSizeOf
) +
1605 regExpData
.sizeOfExcludingThis(mallocSizeOf
) +
1606 bigIntData
.sizeOfExcludingThis(mallocSizeOf
) +
1607 objLiteralData
.sizeOfExcludingThis(mallocSizeOf
) +
1608 parserAtoms
.sizeOfExcludingThis(mallocSizeOf
) +
1609 sharedData
.sizeOfExcludingThis(mallocSizeOf
) + moduleMetadataSize
+
1613 // A PreAllocateableGCArray is an array of GC thing pointers.
1615 // The array's internal buffer can be allocated ahead of time, possibly off
1617 template <typename T
>
1618 struct PreAllocateableGCArray
{
1622 // Inline element for the case when length_ == 1.
1625 // Heap-allocated elements for the case when length_ > 1;
1626 T
* elems_
= nullptr;
1629 struct Preallocated
{
1632 uintptr_t* elems_
= nullptr;
1634 friend struct PreAllocateableGCArray
<T
>;
1637 Preallocated() = default;
1640 bool empty() const { return length_
== 0; }
1642 size_t length() const { return length_
; }
1645 bool isInline() const { return length_
== 1; }
1648 bool allocate(size_t length
);
1650 size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf
) const {
1651 return sizeof(uintptr_t) * length_
;
1655 PreAllocateableGCArray() {
1656 static_assert(std::is_pointer_v
<T
>,
1657 "PreAllocateableGCArray element must be a pointer");
1659 ~PreAllocateableGCArray();
1661 bool empty() const { return length_
== 0; }
1663 size_t length() const { return length_
; }
1666 bool isInline() const { return length_
== 1; }
1669 bool allocate(size_t length
);
1670 bool allocateWith(T init
, size_t length
);
1672 // Steal pre-allocated buffer.
1673 void steal(Preallocated
&& buffer
);
1675 T
& operator[](size_t index
) {
1676 MOZ_ASSERT(index
< length_
);
1682 return elems_
[index
];
1684 const T
& operator[](size_t index
) const {
1685 MOZ_ASSERT(index
< length_
);
1691 return elems_
[index
];
1694 size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf
) const {
1699 return sizeof(T
) * length_
;
1702 void trace(JSTracer
* trc
);
1705 struct CompilationGCOutput
;
1707 // Pre-allocated storage for CompilationGCOutput.
1708 struct PreallocatedCompilationGCOutput
{
1710 PreAllocateableGCArray
<JSFunction
*>::Preallocated functions
;
1711 PreAllocateableGCArray
<js::Scope
*>::Preallocated scopes
;
1713 friend struct CompilationGCOutput
;
1716 PreallocatedCompilationGCOutput() = default;
1718 [[nodiscard
]] bool allocate(FrontendContext
* fc
, size_t scriptDataLength
,
1719 size_t scopeDataLength
) {
1720 if (!functions
.allocate(scriptDataLength
)) {
1721 ReportOutOfMemory(fc
);
1724 if (!scopes
.allocate(scopeDataLength
)) {
1725 ReportOutOfMemory(fc
);
1731 size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf
) const {
1732 return functions
.sizeOfExcludingThis(mallocSizeOf
) +
1733 scopes
.sizeOfExcludingThis(mallocSizeOf
);
1737 // The output of GC allocation from stencil.
1738 struct CompilationGCOutput
{
1739 // The resulting outermost script for the compilation powered
1740 // by this CompilationStencil.
1741 JSScript
* script
= nullptr;
1743 // The resulting module object if there is one.
1744 ModuleObject
* module
= nullptr;
1746 // An array to handle tracing of JSFunction* and Atoms within.
1748 // If the top level script isn't a function, the item at TopLevelIndex is
1750 PreAllocateableGCArray
<JSFunction
*> functions
;
1752 // References to scopes are controlled via AbstractScopePtr, which holds onto
1753 // an index (and CompilationStencil reference).
1754 PreAllocateableGCArray
<js::Scope
*> scopes
;
1756 // The result ScriptSourceObject. This is unused in delazifying parses.
1757 ScriptSourceObject
* sourceObject
= nullptr;
1760 // If we are only instantiating part of a stencil, we can reduce allocations
1761 // by setting a base index and allocating only the array elements we need.
1762 // This applies to both the `functions` and `scopes` arrays. These fields are
1763 // initialized by `ensureAllocatedWithBaseIndex` which also allocates the
1764 // array appropriately.
1766 // Note: These are only used for self-hosted delazification currently.
1767 ScriptIndex functionsBaseIndex
{};
1768 ScopeIndex scopesBaseIndex
{};
1773 CompilationGCOutput() = default;
1775 // Helper to access the `functions` array. The NoBaseIndex version is used if
1776 // the caller never uses a base index.
1777 JSFunction
*& getFunction(ScriptIndex index
) {
1778 return functions
[index
- functionsBaseIndex
];
1780 JSFunction
*& getFunctionNoBaseIndex(ScriptIndex index
) {
1781 MOZ_ASSERT(!functionsBaseIndex
);
1782 return functions
[index
];
1785 // Helper accessors for the `scopes` array.
1786 js::Scope
*& getScope(ScopeIndex index
) {
1787 return scopes
[index
- scopesBaseIndex
];
1789 js::Scope
*& getScopeNoBaseIndex(ScopeIndex index
) {
1790 MOZ_ASSERT(!scopesBaseIndex
);
1791 return scopes
[index
];
1793 js::Scope
* getScopeNoBaseIndex(ScopeIndex index
) const {
1794 MOZ_ASSERT(!scopesBaseIndex
);
1795 return scopes
[index
];
1798 // Allocate output arrays.
1799 [[nodiscard
]] bool ensureAllocated(FrontendContext
* fc
,
1800 size_t scriptDataLength
,
1801 size_t scopeDataLength
) {
1802 if (functions
.empty()) {
1803 if (!functions
.allocate(scriptDataLength
)) {
1804 ReportOutOfMemory(fc
);
1808 if (scopes
.empty()) {
1809 if (!scopes
.allocate(scopeDataLength
)) {
1810 ReportOutOfMemory(fc
);
1817 // Steal output arrays' buffer.
1818 void steal(PreallocatedCompilationGCOutput
&& pre
) {
1819 functions
.steal(std::move(pre
.functions
));
1820 scopes
.steal(std::move(pre
.scopes
));
1823 // A variant of `ensureAllocated` that sets a base index for the function and
1824 // scope arrays. This is used when instantiating only a subset of the stencil.
1825 // Currently this only applies to self-hosted delazification. The ranges
1826 // include the start index and exclude the limit index.
1827 [[nodiscard
]] bool ensureAllocatedWithBaseIndex(FrontendContext
* fc
,
1828 ScriptIndex scriptStart
,
1829 ScriptIndex scriptLimit
,
1830 ScopeIndex scopeStart
,
1831 ScopeIndex scopeLimit
) {
1832 this->functionsBaseIndex
= scriptStart
;
1833 this->scopesBaseIndex
= scopeStart
;
1835 return ensureAllocated(fc
, scriptLimit
- scriptStart
,
1836 scopeLimit
- scopeStart
);
1839 // Size of dynamic data. Note that GC data is counted by GC and not here.
1840 size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf
) const {
1841 return functions
.sizeOfExcludingThis(mallocSizeOf
) +
1842 scopes
.sizeOfExcludingThis(mallocSizeOf
);
1845 void trace(JSTracer
* trc
);
1848 // Iterator over functions that make up a CompilationStencil. This abstracts
1849 // over the parallel arrays in stencil and gc-output that use the same index
1851 class ScriptStencilIterable
{
1853 class ScriptAndFunction
{
1855 const ScriptStencil
& script
;
1856 const ScriptStencilExtra
* scriptExtra
;
1857 JSFunction
* function
;
1860 ScriptAndFunction() = delete;
1861 ScriptAndFunction(const ScriptStencil
& script
,
1862 const ScriptStencilExtra
* scriptExtra
,
1863 JSFunction
* function
, ScriptIndex index
)
1865 scriptExtra(scriptExtra
),
1872 const CompilationStencil
& stencil_
;
1873 CompilationGCOutput
& gcOutput_
;
1875 Iterator(const CompilationStencil
& stencil
, CompilationGCOutput
& gcOutput
,
1877 : index_(index
), stencil_(stencil
), gcOutput_(gcOutput
) {
1878 MOZ_ASSERT(index
== stencil
.scriptData
.size());
1882 explicit Iterator(const CompilationStencil
& stencil
,
1883 CompilationGCOutput
& gcOutput
)
1884 : stencil_(stencil
), gcOutput_(gcOutput
) {
1885 skipTopLevelNonFunction();
1888 Iterator
operator++() {
1895 MOZ_ASSERT(index_
< stencil_
.scriptData
.size());
1899 void assertFunction() {
1900 if (index_
< stencil_
.scriptData
.size()) {
1901 MOZ_ASSERT(stencil_
.scriptData
[index_
].isFunction());
1905 void skipTopLevelNonFunction() {
1906 MOZ_ASSERT(index_
== 0);
1907 if (stencil_
.scriptData
.size()) {
1908 if (!stencil_
.scriptData
[0].isFunction()) {
1915 bool operator!=(const Iterator
& other
) const {
1916 return index_
!= other
.index_
;
1919 ScriptAndFunction
operator*() {
1920 ScriptIndex index
= ScriptIndex(index_
);
1921 const ScriptStencil
& script
= stencil_
.scriptData
[index
];
1922 const ScriptStencilExtra
* scriptExtra
= nullptr;
1923 if (stencil_
.isInitialStencil()) {
1924 scriptExtra
= &stencil_
.scriptExtra
[index
];
1926 return ScriptAndFunction(script
, scriptExtra
,
1927 gcOutput_
.getFunctionNoBaseIndex(index
), index
);
1930 static Iterator
end(const CompilationStencil
& stencil
,
1931 CompilationGCOutput
& gcOutput
) {
1932 return Iterator(stencil
, gcOutput
, stencil
.scriptData
.size());
1936 const CompilationStencil
& stencil_
;
1937 CompilationGCOutput
& gcOutput_
;
1939 explicit ScriptStencilIterable(const CompilationStencil
& stencil
,
1940 CompilationGCOutput
& gcOutput
)
1941 : stencil_(stencil
), gcOutput_(gcOutput
) {}
1943 Iterator
begin() const { return Iterator(stencil_
, gcOutput_
); }
1945 Iterator
end() const { return Iterator::end(stencil_
, gcOutput_
); }
1948 inline ScriptStencilIterable
CompilationStencil::functionScriptStencils(
1949 const CompilationStencil
& stencil
, CompilationGCOutput
& gcOutput
) {
1950 return ScriptStencilIterable(stencil
, gcOutput
);
1953 // Merge CompilationStencil for delazification into initial
1954 // ExtensibleCompilationStencil.
1955 struct CompilationStencilMerger
{
1957 using FunctionKey
= SourceExtent::FunctionKey
;
1959 // The stencil for the initial compilation.
1960 // Delazifications are merged into this.
1962 // If any failure happens during merge operation, this field is reset to
1964 UniquePtr
<ExtensibleCompilationStencil
> initial_
;
1966 // A Map from function key to the ScriptIndex in the initial stencil.
1967 using FunctionKeyToScriptIndexMap
=
1968 mozilla::HashMap
<FunctionKey
, ScriptIndex
,
1969 mozilla::DefaultHasher
<FunctionKey
>,
1970 js::SystemAllocPolicy
>;
1971 FunctionKeyToScriptIndexMap functionKeyToInitialScriptIndex_
;
1973 [[nodiscard
]] bool buildFunctionKeyToIndex(FrontendContext
* fc
);
1975 ScriptIndex
getInitialScriptIndexFor(
1976 const CompilationStencil
& delazification
) const;
1978 // A map from delazification's ParserAtomIndex to
1979 // initial's TaggedParserAtomIndex
1980 using AtomIndexMap
= Vector
<TaggedParserAtomIndex
, 0, js::SystemAllocPolicy
>;
1982 [[nodiscard
]] bool buildAtomIndexMap(FrontendContext
* fc
,
1983 const CompilationStencil
& delazification
,
1984 AtomIndexMap
& atomIndexMap
);
1987 CompilationStencilMerger() = default;
1989 // Set the initial stencil and prepare for merging.
1990 [[nodiscard
]] bool setInitial(
1991 FrontendContext
* fc
, UniquePtr
<ExtensibleCompilationStencil
>&& initial
);
1993 // Merge the delazification stencil into the initial stencil.
1994 [[nodiscard
]] bool addDelazification(
1995 FrontendContext
* fc
, const CompilationStencil
& delazification
);
1997 ExtensibleCompilationStencil
& getResult() const { return *initial_
; }
1998 UniquePtr
<ExtensibleCompilationStencil
> takeResult() {
1999 return std::move(initial_
);
2003 const ScopeStencil
& ScopeStencilRef::scope() const {
2004 return context_
.scopeData
[scopeIndex_
];
2007 InputScope
InputScope::enclosing() const {
2008 return scope_
.match(
2009 [](const Scope
* ptr
) {
2010 // This may return a nullptr Scope pointer.
2011 return InputScope(ptr
->enclosing());
2013 [](const ScopeStencilRef
& ref
) {
2014 if (ref
.scope().hasEnclosing()) {
2015 return InputScope(ref
.context_
, ref
.scope().enclosing());
2017 // The global scope is not known by the Stencil, while parsing inner
2018 // functions from Stencils where they are known at the execution using
2020 if (ref
.scope().kind() == ScopeKind::Module
) {
2021 return InputScope(FakeStencilGlobalScope
{});
2023 return InputScope(nullptr);
2025 [](const FakeStencilGlobalScope
&) { return InputScope(nullptr); });
2028 FunctionFlags
InputScope::functionFlags() const {
2029 return scope_
.match(
2030 [](const Scope
* ptr
) {
2031 JSFunction
* fun
= ptr
->as
<FunctionScope
>().canonicalFunction();
2032 return fun
->flags();
2034 [](const ScopeStencilRef
& ref
) {
2035 MOZ_ASSERT(ref
.scope().isFunction());
2036 ScriptIndex scriptIndex
= ref
.scope().functionIndex();
2037 ScriptStencil
& data
= ref
.context_
.scriptData
[scriptIndex
];
2038 return data
.functionFlags
;
2040 [](const FakeStencilGlobalScope
&) -> FunctionFlags
{
2041 MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("No functionFlags on global.");
2045 ImmutableScriptFlags
InputScope::immutableFlags() const {
2046 return scope_
.match(
2047 [](const Scope
* ptr
) {
2048 JSFunction
* fun
= ptr
->as
<FunctionScope
>().canonicalFunction();
2049 return fun
->baseScript()->immutableFlags();
2051 [](const ScopeStencilRef
& ref
) {
2052 MOZ_ASSERT(ref
.scope().isFunction());
2053 ScriptIndex scriptIndex
= ref
.scope().functionIndex();
2054 ScriptStencilExtra
& extra
= ref
.context_
.scriptExtra
[scriptIndex
];
2055 return extra
.immutableFlags
;
2057 [](const FakeStencilGlobalScope
&) -> ImmutableScriptFlags
{
2058 MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("No immutableFlags on global.");
2062 MemberInitializers
InputScope::getMemberInitializers() const {
2063 return scope_
.match(
2064 [](const Scope
* ptr
) {
2065 JSFunction
* fun
= ptr
->as
<FunctionScope
>().canonicalFunction();
2066 return fun
->baseScript()->getMemberInitializers();
2068 [](const ScopeStencilRef
& ref
) {
2069 MOZ_ASSERT(ref
.scope().isFunction());
2070 ScriptIndex scriptIndex
= ref
.scope().functionIndex();
2071 ScriptStencilExtra
& extra
= ref
.context_
.scriptExtra
[scriptIndex
];
2072 return extra
.memberInitializers();
2074 [](const FakeStencilGlobalScope
&) -> MemberInitializers
{
2075 MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE(
2076 "No getMemberInitializers on global.");
2080 const ScriptStencil
& ScriptStencilRef::scriptData() const {
2081 return context_
.scriptData
[scriptIndex_
];
2084 const ScriptStencilExtra
& ScriptStencilRef::scriptExtra() const {
2085 return context_
.scriptExtra
[scriptIndex_
];
2088 } // namespace frontend
2091 #endif // frontend_CompilationStencil_h