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_Stencil_h
8 #define frontend_Stencil_h
10 #include "mozilla/Assertions.h" // MOZ_ASSERT
11 #include "mozilla/Maybe.h" // mozilla::{Maybe, Nothing}
12 #include "mozilla/MemoryReporting.h" // mozilla::MallocSizeOf
13 #include "mozilla/Span.h" // mozilla::Span
15 #include <stddef.h> // size_t
16 #include <stdint.h> // char16_t, uint8_t, uint16_t, uint32_t
18 #include "frontend/AbstractScopePtr.h" // AbstractScopePtr, ScopeIndex
19 #include "frontend/ObjLiteral.h" // ObjLiteralStencil
20 #include "frontend/ParserAtom.h" // TaggedParserAtomIndex
21 #include "frontend/ScriptIndex.h" // ScriptIndex
22 #include "frontend/TypedIndex.h" // TypedIndex
23 #include "js/AllocPolicy.h" // SystemAllocPolicy
24 #include "js/ColumnNumber.h" // JS::ColumnNumberOneOrigin
25 #include "js/RefCounted.h" // AtomicRefCounted
26 #include "js/RegExpFlags.h" // JS::RegExpFlags
27 #include "js/RootingAPI.h" // Handle
28 #include "js/TypeDecls.h" // JSContext
29 #include "js/UniquePtr.h" // js::UniquePtr
30 #include "js/Utility.h" // UniqueTwoByteChars
31 #include "js/Vector.h" // js::Vector
32 #include "vm/FunctionFlags.h" // FunctionFlags
33 #include "vm/Scope.h" // Scope, BaseScopeData, FunctionScope, LexicalScope, VarScope, GlobalScope, EvalScope, ModuleScope
34 #include "vm/ScopeKind.h" // ScopeKind
35 #include "vm/SharedStencil.h" // ImmutableScriptFlags, GCThingIndex, js::SharedImmutableScriptData, MemberInitializers, SourceExtent
45 struct CompilationInput
;
46 struct CompilationStencil
;
47 struct CompilationAtomCache
;
48 struct CompilationGCOutput
;
49 struct CompilationStencilMerger
;
54 using BaseParserScopeData
= AbstractBaseScopeData
<TaggedParserAtomIndex
>;
55 using ParserBindingName
= AbstractBindingName
<TaggedParserAtomIndex
>;
57 template <typename Scope
>
58 using ParserScopeSlotInfo
= typename
Scope::SlotInfo
;
59 using ParserGlobalScopeSlotInfo
= ParserScopeSlotInfo
<GlobalScope
>;
60 using ParserEvalScopeSlotInfo
= ParserScopeSlotInfo
<EvalScope
>;
61 using ParserLexicalScopeSlotInfo
= ParserScopeSlotInfo
<LexicalScope
>;
62 using ParserClassBodyScopeSlotInfo
= ParserScopeSlotInfo
<ClassBodyScope
>;
63 using ParserFunctionScopeSlotInfo
= ParserScopeSlotInfo
<FunctionScope
>;
64 using ParserModuleScopeSlotInfo
= ParserScopeSlotInfo
<ModuleScope
>;
65 using ParserVarScopeSlotInfo
= ParserScopeSlotInfo
<VarScope
>;
67 using ParserBindingIter
= AbstractBindingIter
<TaggedParserAtomIndex
>;
68 using ParserPositionalFormalParameterIter
=
69 AbstractPositionalFormalParameterIter
<TaggedParserAtomIndex
>;
71 // [SMDOC] Script Stencil (Frontend Representation)
73 // Stencils are the set of data structures capturing the result of parsing and
74 // bytecode emission. The Stencil format is a precursor format that is then used
75 // to allocate the corresponding scripts on the GC heap that will be used for
76 // execution. By decoupling from the GC and other runtime systems, robust
77 // caching and speculation systems can be built that are more thread-agnostic
80 // See: https://bugzil.la/stencil
82 // There are numerous data structures that make up the Stencil format. The
83 // structures are designed for fast serialization to and from disk by preferring
84 // indices over pointers and vectors instead of graphs to allow bulk operations.
89 // Our parser relies on atomized strings as part of its normal operations and so
90 // a `ParserAtom` type exists that mirrors the `JSAtom` type but does not
91 // involve the garbage collector. This is possible because the lifetime of these
92 // ParserAtoms is the lifetime of the Stencil that makes use of them and we do
93 // not need finer grained collection.
98 // The key structures generated by parsing are instances of `ScriptStencil`.
99 // There is a `ScriptStencil` for the top-level script and for each inner
100 // function. It contains information needed to create the `JSFunction` (if it is
101 // a function) and the `BaseScript` (if not asm.js) and may or may not have
102 // bytecode. Each `ScriptStencil` may also reference the following Stencil types
103 // (similar to the `BaseScript::gcthings()` list):
109 // * ObjLiteralStencil
110 // * StencilModuleMetadata
113 // CompilationStencil / ExtensibleCompilationStencil
114 // -------------------------------------------------
115 // Parsing a single JavaScript file may generate a tree of `ScriptStencil` that
116 // we then package up into the `ExtensibleCompilationStencil` type or
117 // `CompilationStencil`. They contain a series of vectors/spans segregated by
118 // data type for fast processing (a.k.a Data Oriented Design).
120 // `ExtensibleCompilationStencil` is mutable type used during parsing, and
121 // can be allocated either on stack or heap.
122 // `ExtensibleCompilationStencil` holds vectors of stencils.
124 // `CompilationStencil` is immutable type used for caching the compilation
125 // result, and is allocated on heap with refcount.
126 // `CompilationStencil` holds spans of stencils, and it can point either
127 // owned data or borrowed data.
128 // The borrowed data can be from other `ExtensibleCompilationStencil` or
129 // from serialized stencil (XDR) on memory or mmap.
131 // Delazifying a function will generate its bytecode but some fields remain
132 // unchanged from the initial lazy parse.
133 // When we delazify a function that was lazily parsed, we generate a new
134 // Stencil at the point too. These delazifications can be merged into the
135 // Stencil of the initial parse by using `CompilationStencilMerger`.
137 // Conversion from ExtensibleCompilationStencil to CompilationStencil
138 // ------------------------------------------------------------------
139 // There are multiple ways to convert from `ExtensibleCompilationStencil` to
140 // `CompilationStencil`:
142 // 1. Temporarily borrow `ExtensibleCompilationStencil` content and call
143 // function that takes `CompilationStencil` reference, and keep using the
144 // `ExtensibleCompilationStencil` after that:
146 // ExtensibleCompilationStencil extensible = ...;
148 // BorrowingCompilationStencil stencil(extensible);
149 // // Use `stencil reference.
152 // 2. Take the ownership of an on-heap ExtensibleCompilationStencil. This makes
153 // the `CompilationStencil` self-contained and it's useful for caching:
155 // UniquePtr<ExtensibleCompilationStencil> extensible = ...;
156 // CompilationStencil stencil(std::move(extensible));
158 // Conversion from CompilationStencil to ExtensibleCompilationStencil
159 // ------------------------------------------------------------------
160 // In the same way, there are multiple ways to convert from
161 // `CompilationStencil` to `ExtensibleCompilationStencil`:
163 // 1. Take the ownership of `CompilationStencil`'s underlying data, Only when
164 // stencil owns the data and the refcount is 1:
166 // RefPtr<CompilationStencil> stencil = ...;
167 // ExtensibleCompilationStencil extensible(...);
168 // // NOTE: This is equivalent to cloneFrom below if `stencil` has refcount
169 // // more than 2, or it doesn't own the data.
170 // extensible.steal(fc, std::move(stencil));
172 // 2. Clone the underlying data. This is slow but safe operation:
174 // CompilationStencil stencil = ...;
175 // ExtensibleCompilationStencil extensible(...);
176 // extensible.cloneFrom(fc, stencil);
178 // 3. Take the ownership back from the `CompilationStencil` which is created by
179 // taking the ownership of an on-heap `ExtensibleCompilationStencil`:
181 // CompilationStencil stencil = ...;
182 // ExtensibleCompilationStencil* extensible = stencil.takeOwnedBorrow();
184 // CompilationGCOutput
185 // -------------------
186 // When a Stencil is instantiated the equivalent script objects are allocated on
187 // the GC heap and their pointers are collected into the `CompilationGCOutput`
188 // structure. This is only used temporarily during instantiation.
193 // This is another temporary structure used by the parser while the Stencil is
194 // being generated. Once the `CompilationStencil` is complete, this can be
197 // Typed indices for the different stencil elements in the compilation result.
198 using RegExpIndex
= TypedIndex
<RegExpStencil
>;
199 using BigIntIndex
= TypedIndex
<BigIntStencil
>;
200 using ObjLiteralIndex
= TypedIndex
<ObjLiteralStencil
>;
202 // Index into {ExtensibleCompilationStencil,CompilationStencil}.gcThingData.
203 class CompilationGCThingType
{};
204 using CompilationGCThingIndex
= TypedIndex
<CompilationGCThingType
>;
206 // A syntax-checked regular expression string.
207 class RegExpStencil
{
208 friend class StencilXDR
;
210 TaggedParserAtomIndex atom_
;
211 // Use uint32_t to make this struct fully-packed.
214 friend struct CompilationStencilMerger
;
217 RegExpStencil() = default;
219 RegExpStencil(TaggedParserAtomIndex atom
, JS::RegExpFlags flags
)
220 : atom_(atom
), flags_(flags
.value()) {}
222 JS::RegExpFlags
flags() const { return JS::RegExpFlags(flags_
); }
224 RegExpObject
* createRegExp(JSContext
* cx
,
225 const CompilationAtomCache
& atomCache
) const;
227 // This is used by `Reflect.parse` when we need the RegExpObject but are not
228 // doing a complete instantiation of the CompilationStencil.
229 RegExpObject
* createRegExpAndEnsureAtom(
230 JSContext
* cx
, FrontendContext
* fc
, ParserAtomsTable
& parserAtoms
,
231 CompilationAtomCache
& atomCache
) const;
233 #if defined(DEBUG) || defined(JS_JITSPEW)
235 void dump(JSONPrinter
& json
, const CompilationStencil
* stencil
) const;
236 void dumpFields(JSONPrinter
& json
, const CompilationStencil
* stencil
) const;
240 // This owns a set of characters guaranteed to parse into a BigInt via
241 // ParseBigIntLiteral. Used to avoid allocating the BigInt on the
242 // GC heap during parsing.
243 class BigIntStencil
{
244 friend class StencilXDR
;
246 // Source of the BigInt literal.
247 // It's not null-terminated, and also trailing 'n' suffix is not included.
248 mozilla::Span
<char16_t
> source_
;
251 BigIntStencil() = default;
253 [[nodiscard
]] bool init(FrontendContext
* fc
, LifoAlloc
& alloc
,
254 const mozilla::Span
<const char16_t
> buf
);
256 BigInt
* createBigInt(JSContext
* cx
) const;
260 mozilla::Span
<const char16_t
> source() const { return source_
; }
263 bool isContainedIn(const LifoAlloc
& alloc
) const;
266 #if defined(DEBUG) || defined(JS_JITSPEW)
268 void dump(JSONPrinter
& json
) const;
269 void dumpCharsNoQuote(GenericPrinter
& out
) const;
274 friend class StencilXDR
;
275 friend class InputScope
;
276 friend class AbstractBindingIter
<frontend::TaggedParserAtomIndex
>;
277 friend struct CompilationStencil
;
278 friend struct CompilationStencilMerger
;
280 // The enclosing scope. Valid only if HasEnclosing flag is set.
281 // compilation applies.
282 ScopeIndex enclosing_
;
284 // First frame slot to use, or LOCALNO_LIMIT if none are allowed.
285 uint32_t firstFrameSlot_
= UINT32_MAX
;
287 // The number of environment shape's slots. Valid only if
288 // HasEnvironmentShape flag is set.
289 uint32_t numEnvironmentSlots_
;
291 // Canonical function if this is a FunctionScope. Valid only if
292 // kind_ is ScopeKind::Function.
293 ScriptIndex functionIndex_
;
295 // The kind determines the corresponding BaseParserScopeData.
296 ScopeKind kind_
{UINT8_MAX
};
298 // True if this scope has enclosing scope stencil. Otherwise, the enclosing
299 // scope will be read from CompilationInput while instantiating. Self-hosting
300 // is a special case and will use `emptyGlobalScope` when there is no
301 // enclosing scope stencil.
302 static constexpr uint8_t HasEnclosing
= 1 << 0;
304 // If true, an environment Shape must be created. The shape itself may
305 // have no slots if the environment may be extensible later.
306 static constexpr uint8_t HasEnvironmentShape
= 1 << 1;
308 // True if this is a FunctionScope for an arrow function.
309 static constexpr uint8_t IsArrow
= 1 << 2;
313 // To make this struct packed, add explicit field for padding.
314 uint16_t padding_
= 0;
318 ScopeStencil() = default;
320 ScopeStencil(ScopeKind kind
, mozilla::Maybe
<ScopeIndex
> enclosing
,
321 uint32_t firstFrameSlot
,
322 mozilla::Maybe
<uint32_t> numEnvironmentSlots
,
323 mozilla::Maybe
<ScriptIndex
> functionIndex
= mozilla::Nothing(),
324 bool isArrow
= false)
325 : enclosing_(enclosing
.valueOr(ScopeIndex(0))),
326 firstFrameSlot_(firstFrameSlot
),
327 numEnvironmentSlots_(numEnvironmentSlots
.valueOr(0)),
328 functionIndex_(functionIndex
.valueOr(ScriptIndex(0))),
330 flags_((enclosing
.isSome() ? HasEnclosing
: 0) |
331 (numEnvironmentSlots
.isSome() ? HasEnvironmentShape
: 0) |
332 (isArrow
? IsArrow
: 0)) {
333 MOZ_ASSERT((kind
== ScopeKind::Function
) == functionIndex
.isSome());
334 // Silence -Wunused-private-field warnings.
339 // Create ScopeStencil with `args`, and append ScopeStencil and `data` to
340 // `compilationState`, and return the index of them as `indexOut`.
341 template <typename
... Args
>
342 static bool appendScopeStencilAndData(FrontendContext
* fc
,
343 CompilationState
& compilationState
,
344 BaseParserScopeData
* data
,
345 ScopeIndex
* indexOut
, Args
&&... args
);
348 static bool createForFunctionScope(
349 FrontendContext
* fc
, CompilationState
& compilationState
,
350 FunctionScope::ParserData
* dataArg
, bool hasParameterExprs
,
351 bool needsEnvironment
, ScriptIndex functionIndex
, bool isArrow
,
352 mozilla::Maybe
<ScopeIndex
> enclosing
, ScopeIndex
* index
);
354 static bool createForLexicalScope(
355 FrontendContext
* fc
, CompilationState
& compilationState
, ScopeKind kind
,
356 LexicalScope::ParserData
* dataArg
, uint32_t firstFrameSlot
,
357 mozilla::Maybe
<ScopeIndex
> enclosing
, ScopeIndex
* index
);
359 static bool createForClassBodyScope(
360 FrontendContext
* fc
, CompilationState
& compilationState
, ScopeKind kind
,
361 ClassBodyScope::ParserData
* dataArg
, uint32_t firstFrameSlot
,
362 mozilla::Maybe
<ScopeIndex
> enclosing
, ScopeIndex
* index
);
364 static bool createForVarScope(FrontendContext
* fc
,
365 CompilationState
& compilationState
,
366 ScopeKind kind
, VarScope::ParserData
* dataArg
,
367 uint32_t firstFrameSlot
, bool needsEnvironment
,
368 mozilla::Maybe
<ScopeIndex
> enclosing
,
371 static bool createForGlobalScope(FrontendContext
* fc
,
372 CompilationState
& compilationState
,
374 GlobalScope::ParserData
* dataArg
,
377 static bool createForEvalScope(FrontendContext
* fc
,
378 CompilationState
& compilationState
,
379 ScopeKind kind
, EvalScope::ParserData
* dataArg
,
380 mozilla::Maybe
<ScopeIndex
> enclosing
,
383 static bool createForModuleScope(FrontendContext
* fc
,
384 CompilationState
& compilationState
,
385 ModuleScope::ParserData
* dataArg
,
386 mozilla::Maybe
<ScopeIndex
> enclosing
,
389 static bool createForWithScope(FrontendContext
* fc
,
390 CompilationState
& compilationState
,
391 mozilla::Maybe
<ScopeIndex
> enclosing
,
394 AbstractScopePtr
enclosing(CompilationState
& compilationState
) const;
395 js::Scope
* enclosingExistingScope(const CompilationInput
& input
,
396 const CompilationGCOutput
& gcOutput
) const;
399 bool hasEnclosing() const { return flags_
& HasEnclosing
; }
401 ScopeIndex
enclosing() const {
402 MOZ_ASSERT(hasEnclosing());
406 uint32_t firstFrameSlot() const { return firstFrameSlot_
; }
408 bool hasEnvironmentShape() const { return flags_
& HasEnvironmentShape
; }
410 uint32_t numEnvironmentSlots() const {
411 MOZ_ASSERT(hasEnvironmentShape());
412 return numEnvironmentSlots_
;
415 bool isFunction() const { return kind_
== ScopeKind::Function
; }
417 ScriptIndex
functionIndex() const { return functionIndex_
; }
420 ScopeKind
kind() const { return kind_
; }
422 bool hasEnvironment() const {
423 // Check if scope kind alone means we have an env shape, and
424 // otherwise check if we have one created.
425 return Scope::hasEnvironment(kind(), hasEnvironmentShape());
428 bool isArrow() const { return flags_
& IsArrow
; }
430 Scope
* createScope(JSContext
* cx
, CompilationInput
& input
,
431 CompilationGCOutput
& gcOutput
,
432 BaseParserScopeData
* baseScopeData
) const;
433 Scope
* createScope(JSContext
* cx
, CompilationAtomCache
& atomCache
,
434 Handle
<Scope
*> enclosingScope
,
435 BaseParserScopeData
* baseScopeData
) const;
437 #if defined(DEBUG) || defined(JS_JITSPEW)
439 void dump(JSONPrinter
& json
, const BaseParserScopeData
* baseScopeData
,
440 const CompilationStencil
* stencil
) const;
441 void dumpFields(JSONPrinter
& json
, const BaseParserScopeData
* baseScopeData
,
442 const CompilationStencil
* stencil
) const;
446 // Transfer ownership into a new UniquePtr.
447 template <typename SpecificScopeType
>
448 UniquePtr
<typename
SpecificScopeType::RuntimeData
> createSpecificScopeData(
449 JSContext
* cx
, CompilationAtomCache
& atomCache
,
450 BaseParserScopeData
* baseData
) const;
452 template <typename SpecificEnvironmentType
>
453 [[nodiscard
]] bool createSpecificShape(
454 JSContext
* cx
, ScopeKind kind
, BaseScopeData
* scopeData
,
455 MutableHandle
<SharedShape
*> shape
) const;
457 template <typename SpecificScopeType
, typename SpecificEnvironmentType
>
458 Scope
* createSpecificScope(JSContext
* cx
, CompilationAtomCache
& atomCache
,
459 Handle
<Scope
*> enclosingScope
,
460 BaseParserScopeData
* baseData
) const;
462 template <typename ScopeT
>
463 static constexpr bool matchScopeKind(ScopeKind kind
) {
465 case ScopeKind::Function
: {
466 return std::is_same_v
<ScopeT
, FunctionScope
>;
468 case ScopeKind::Lexical
:
469 case ScopeKind::SimpleCatch
:
470 case ScopeKind::Catch
:
471 case ScopeKind::NamedLambda
:
472 case ScopeKind::StrictNamedLambda
:
473 case ScopeKind::FunctionLexical
: {
474 return std::is_same_v
<ScopeT
, LexicalScope
>;
476 case ScopeKind::ClassBody
: {
477 return std::is_same_v
<ScopeT
, ClassBodyScope
>;
479 case ScopeKind::FunctionBodyVar
: {
480 return std::is_same_v
<ScopeT
, VarScope
>;
482 case ScopeKind::Global
:
483 case ScopeKind::NonSyntactic
: {
484 return std::is_same_v
<ScopeT
, GlobalScope
>;
486 case ScopeKind::Eval
:
487 case ScopeKind::StrictEval
: {
488 return std::is_same_v
<ScopeT
, EvalScope
>;
490 case ScopeKind::Module
: {
491 return std::is_same_v
<ScopeT
, ModuleScope
>;
493 case ScopeKind::With
: {
494 return std::is_same_v
<ScopeT
, WithScope
>;
496 case ScopeKind::WasmFunction
:
497 case ScopeKind::WasmInstance
: {
505 class StencilModuleAssertion
{
507 TaggedParserAtomIndex key
;
508 TaggedParserAtomIndex value
;
510 StencilModuleAssertion() = default;
511 StencilModuleAssertion(TaggedParserAtomIndex key
, TaggedParserAtomIndex value
)
512 : key(key
), value(value
) {}
515 class StencilModuleRequest
{
517 TaggedParserAtomIndex specifier
;
519 using AssertionVector
=
520 Vector
<StencilModuleAssertion
, 0, js::SystemAllocPolicy
>;
521 AssertionVector assertions
;
524 StencilModuleRequest() = default;
526 explicit StencilModuleRequest(TaggedParserAtomIndex specifier
)
527 : specifier(specifier
) {
528 MOZ_ASSERT(specifier
);
531 StencilModuleRequest(const StencilModuleRequest
& other
)
532 : specifier(other
.specifier
) {
533 AutoEnterOOMUnsafeRegion oomUnsafe
;
534 if (!assertions
.appendAll(other
.assertions
)) {
535 oomUnsafe
.crash("StencilModuleRequest::StencilModuleRequest");
539 StencilModuleRequest(StencilModuleRequest
&& other
) noexcept
540 : specifier(other
.specifier
), assertions(std::move(other
.assertions
)) {}
542 StencilModuleRequest
& operator=(StencilModuleRequest
& other
) {
543 specifier
= other
.specifier
;
544 assertions
= std::move(other
.assertions
);
548 StencilModuleRequest
& operator=(StencilModuleRequest
&& other
) noexcept
{
549 specifier
= other
.specifier
;
550 assertions
= std::move(other
.assertions
);
555 class MaybeModuleRequestIndex
{
556 static constexpr uint32_t NOTHING
= UINT32_MAX
;
558 uint32_t bits
= NOTHING
;
561 MaybeModuleRequestIndex() = default;
562 explicit MaybeModuleRequestIndex(uint32_t index
) : bits(index
) {
563 MOZ_ASSERT(isSome());
566 MaybeModuleRequestIndex(const MaybeModuleRequestIndex
& other
) = default;
567 MaybeModuleRequestIndex
& operator=(const MaybeModuleRequestIndex
& other
) =
570 bool isNothing() const { return bits
== NOTHING
; }
571 bool isSome() const { return !isNothing(); }
572 explicit operator bool() const { return isSome(); }
574 uint32_t value() const {
575 MOZ_ASSERT(isSome());
579 uint32_t* operator&() { return &bits
; }
582 // Common type for ImportEntry / ExportEntry / ModuleRequest within frontend. We
583 // use a shared stencil class type to simplify serialization.
585 // https://tc39.es/ecma262/#importentry-record
586 // https://tc39.es/ecma262/#exportentry-record
588 // Note: We subdivide the spec's ExportEntry into ExportAs / ExportFrom forms
590 class StencilModuleEntry
{
594 // | RequestedModule | ImportEntry | ImportNamespaceEntry | ExportAs | ExportFrom | ExportNamespaceFrom | ExportBatchFrom |
595 // |----------------------------------------------------------------------------------------------------------------------|
596 // moduleRequest | required | required | required | null | required | required | required |
597 // localName | null | required | required | required | null | null | null |
598 // importName | null | required | null | null | required | null | null |
599 // exportName | null | null | null | required | required | required | null |
602 MaybeModuleRequestIndex moduleRequest
;
603 TaggedParserAtomIndex localName
;
604 TaggedParserAtomIndex importName
;
605 TaggedParserAtomIndex exportName
;
607 // Location used for error messages. If this is for a module request entry
608 // then it is the module specifier string, otherwise the import/export spec
609 // that failed. Exports may not fill these fields if an error cannot be
610 // generated such as `export let x;`.
612 // Line number (1-origin).
615 // Column number in UTF-16 code units.
616 JS::ColumnNumberOneOrigin column
;
619 StencilModuleEntry(uint32_t lineno
, JS::ColumnNumberOneOrigin column
)
620 : lineno(lineno
), column(column
) {}
624 StencilModuleEntry() = default;
626 StencilModuleEntry(const StencilModuleEntry
& other
)
627 : moduleRequest(other
.moduleRequest
),
628 localName(other
.localName
),
629 importName(other
.importName
),
630 exportName(other
.exportName
),
631 lineno(other
.lineno
),
632 column(other
.column
) {}
634 StencilModuleEntry(StencilModuleEntry
&& other
) noexcept
635 : moduleRequest(other
.moduleRequest
),
636 localName(other
.localName
),
637 importName(other
.importName
),
638 exportName(other
.exportName
),
639 lineno(other
.lineno
),
640 column(other
.column
) {}
642 StencilModuleEntry
& operator=(StencilModuleEntry
& other
) {
643 moduleRequest
= other
.moduleRequest
;
644 localName
= other
.localName
;
645 importName
= other
.importName
;
646 exportName
= other
.exportName
;
647 lineno
= other
.lineno
;
648 column
= other
.column
;
652 StencilModuleEntry
& operator=(StencilModuleEntry
&& other
) noexcept
{
653 moduleRequest
= other
.moduleRequest
;
654 localName
= other
.localName
;
655 importName
= other
.importName
;
656 exportName
= other
.exportName
;
657 lineno
= other
.lineno
;
658 column
= other
.column
;
662 static StencilModuleEntry
requestedModule(
663 MaybeModuleRequestIndex moduleRequest
, uint32_t lineno
,
664 JS::ColumnNumberOneOrigin column
) {
665 MOZ_ASSERT(moduleRequest
.isSome());
666 StencilModuleEntry
entry(lineno
, column
);
667 entry
.moduleRequest
= moduleRequest
;
671 static StencilModuleEntry
importEntry(MaybeModuleRequestIndex moduleRequest
,
672 TaggedParserAtomIndex localName
,
673 TaggedParserAtomIndex importName
,
675 JS::ColumnNumberOneOrigin column
) {
676 MOZ_ASSERT(moduleRequest
.isSome());
677 MOZ_ASSERT(localName
&& importName
);
678 StencilModuleEntry
entry(lineno
, column
);
679 entry
.moduleRequest
= moduleRequest
;
680 entry
.localName
= localName
;
681 entry
.importName
= importName
;
685 static StencilModuleEntry
importNamespaceEntry(
686 MaybeModuleRequestIndex moduleRequest
, TaggedParserAtomIndex localName
,
687 uint32_t lineno
, JS::ColumnNumberOneOrigin column
) {
688 MOZ_ASSERT(moduleRequest
.isSome());
689 MOZ_ASSERT(localName
);
690 StencilModuleEntry
entry(lineno
, column
);
691 entry
.moduleRequest
= moduleRequest
;
692 entry
.localName
= localName
;
696 static StencilModuleEntry
exportAsEntry(TaggedParserAtomIndex localName
,
697 TaggedParserAtomIndex exportName
,
699 JS::ColumnNumberOneOrigin column
) {
700 MOZ_ASSERT(localName
&& exportName
);
701 StencilModuleEntry
entry(lineno
, column
);
702 entry
.localName
= localName
;
703 entry
.exportName
= exportName
;
707 static StencilModuleEntry
exportFromEntry(
708 MaybeModuleRequestIndex moduleRequest
, TaggedParserAtomIndex importName
,
709 TaggedParserAtomIndex exportName
, uint32_t lineno
,
710 JS::ColumnNumberOneOrigin column
) {
711 MOZ_ASSERT(moduleRequest
.isSome());
712 MOZ_ASSERT(importName
&& exportName
);
713 StencilModuleEntry
entry(lineno
, column
);
714 entry
.moduleRequest
= moduleRequest
;
715 entry
.importName
= importName
;
716 entry
.exportName
= exportName
;
720 static StencilModuleEntry
exportNamespaceFromEntry(
721 MaybeModuleRequestIndex moduleRequest
, TaggedParserAtomIndex exportName
,
722 uint32_t lineno
, JS::ColumnNumberOneOrigin column
) {
723 MOZ_ASSERT(moduleRequest
.isSome());
724 MOZ_ASSERT(exportName
);
725 StencilModuleEntry
entry(lineno
, column
);
726 entry
.moduleRequest
= MaybeModuleRequestIndex(moduleRequest
);
727 entry
.exportName
= exportName
;
731 static StencilModuleEntry
exportBatchFromEntry(
732 MaybeModuleRequestIndex moduleRequest
, uint32_t lineno
,
733 JS::ColumnNumberOneOrigin column
) {
734 MOZ_ASSERT(moduleRequest
.isSome());
735 StencilModuleEntry
entry(lineno
, column
);
736 entry
.moduleRequest
= MaybeModuleRequestIndex(moduleRequest
);
741 // Metadata generated by parsing module scripts, including import/export tables.
742 class StencilModuleMetadata
743 : public js::AtomicRefCounted
<StencilModuleMetadata
> {
745 using RequestVector
= Vector
<StencilModuleRequest
, 0, js::SystemAllocPolicy
>;
746 using EntryVector
= Vector
<StencilModuleEntry
, 0, js::SystemAllocPolicy
>;
748 RequestVector moduleRequests
;
749 EntryVector requestedModules
;
750 EntryVector importEntries
;
751 EntryVector localExportEntries
;
752 EntryVector indirectExportEntries
;
753 EntryVector starExportEntries
;
754 FunctionDeclarationVector functionDecls
;
755 // Set to true if the module has a top-level await keyword.
756 bool isAsync
= false;
758 StencilModuleMetadata() = default;
760 bool initModule(JSContext
* cx
, FrontendContext
* fc
,
761 CompilationAtomCache
& atomCache
,
762 JS::Handle
<ModuleObject
*> module
) const;
764 size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf
) const {
765 return mallocSizeOf(this) +
766 requestedModules
.sizeOfExcludingThis(mallocSizeOf
) +
767 importEntries
.sizeOfExcludingThis(mallocSizeOf
) +
768 localExportEntries
.sizeOfExcludingThis(mallocSizeOf
) +
769 indirectExportEntries
.sizeOfExcludingThis(mallocSizeOf
) +
770 starExportEntries
.sizeOfExcludingThis(mallocSizeOf
) +
771 functionDecls
.sizeOfExcludingThis(mallocSizeOf
);
774 #if defined(DEBUG) || defined(JS_JITSPEW)
776 void dump(JSONPrinter
& json
, const CompilationStencil
* stencil
) const;
777 void dumpFields(JSONPrinter
& json
, const CompilationStencil
* stencil
) const;
781 bool createModuleRequestObjects(
782 JSContext
* cx
, CompilationAtomCache
& atomCache
,
783 MutableHandle
<ModuleRequestVector
> output
) const;
784 bool createRequestedModules(
785 JSContext
* cx
, CompilationAtomCache
& atomCache
,
786 Handle
<ModuleRequestVector
> moduleRequests
,
787 MutableHandle
<RequestedModuleVector
> output
) const;
788 bool createImportEntries(JSContext
* cx
, CompilationAtomCache
& atomCache
,
789 Handle
<ModuleRequestVector
> moduleRequests
,
790 MutableHandle
<ImportEntryVector
> output
) const;
791 bool createExportEntries(JSContext
* cx
, CompilationAtomCache
& atomCache
,
792 Handle
<ModuleRequestVector
> moduleRequests
,
793 const EntryVector
& input
,
794 MutableHandle
<ExportEntryVector
> output
) const;
795 ModuleRequestObject
* createModuleRequestObject(
796 JSContext
* cx
, CompilationAtomCache
& atomCache
,
797 const StencilModuleRequest
& request
) const;
800 // As an alternative to a ScopeIndex (which references a ScopeStencil), we may
801 // instead refer to an existing scope from GlobalObject::emptyGlobalScope().
803 // NOTE: This is only used for the self-hosting global.
804 class EmptyGlobalScopeType
{};
806 // Things pointed by this index all end up being baked into GC things as part
807 // of stencil instantiation.
810 // 0x1YYY_YYYY 28-bit ParserAtom
811 // 0x2YYY_YYYY Well-known/static atom (See TaggedParserAtomIndex)
812 // 0x3YYY_YYYY 28-bit BigInt
813 // 0x4YYY_YYYY 28-bit ObjLiteral
814 // 0x5YYY_YYYY 28-bit RegExp
815 // 0x6YYY_YYYY 28-bit Scope
816 // 0x7YYY_YYYY 28-bit Function
817 // 0x8000_0000 EmptyGlobalScope
818 class TaggedScriptThingIndex
{
821 static constexpr size_t IndexBit
= TaggedParserAtomIndex::IndexBit
;
822 static constexpr size_t IndexMask
= TaggedParserAtomIndex::IndexMask
;
824 static constexpr size_t TagShift
= TaggedParserAtomIndex::TagShift
;
825 static constexpr size_t TagBit
= TaggedParserAtomIndex::TagBit
;
826 static constexpr size_t TagMask
= TaggedParserAtomIndex::TagMask
;
829 enum class Kind
: uint32_t {
830 Null
= uint32_t(TaggedParserAtomIndex::Kind::Null
),
831 ParserAtomIndex
= uint32_t(TaggedParserAtomIndex::Kind::ParserAtomIndex
),
832 WellKnown
= uint32_t(TaggedParserAtomIndex::Kind::WellKnown
),
842 static constexpr uint32_t NullTag
= uint32_t(Kind::Null
) << TagShift
;
843 static_assert(NullTag
== TaggedParserAtomIndex::NullTag
);
844 static constexpr uint32_t ParserAtomIndexTag
= uint32_t(Kind::ParserAtomIndex
)
846 static_assert(ParserAtomIndexTag
==
847 TaggedParserAtomIndex::ParserAtomIndexTag
);
848 static constexpr uint32_t WellKnownTag
= uint32_t(Kind::WellKnown
)
850 static_assert(WellKnownTag
== TaggedParserAtomIndex::WellKnownTag
);
852 static constexpr uint32_t BigIntTag
= uint32_t(Kind::BigInt
) << TagShift
;
853 static constexpr uint32_t ObjLiteralTag
= uint32_t(Kind::ObjLiteral
)
855 static constexpr uint32_t RegExpTag
= uint32_t(Kind::RegExp
) << TagShift
;
856 static constexpr uint32_t ScopeTag
= uint32_t(Kind::Scope
) << TagShift
;
857 static constexpr uint32_t FunctionTag
= uint32_t(Kind::Function
) << TagShift
;
858 static constexpr uint32_t EmptyGlobalScopeTag
=
859 uint32_t(Kind::EmptyGlobalScope
) << TagShift
;
862 static constexpr uint32_t IndexLimit
= Bit(IndexBit
);
864 TaggedScriptThingIndex() : data_(NullTag
) {}
866 explicit TaggedScriptThingIndex(TaggedParserAtomIndex index
)
867 : data_(index
.rawData()) {}
868 explicit TaggedScriptThingIndex(BigIntIndex index
)
869 : data_(uint32_t(index
) | BigIntTag
) {
870 MOZ_ASSERT(uint32_t(index
) < IndexLimit
);
872 explicit TaggedScriptThingIndex(ObjLiteralIndex index
)
873 : data_(uint32_t(index
) | ObjLiteralTag
) {
874 MOZ_ASSERT(uint32_t(index
) < IndexLimit
);
876 explicit TaggedScriptThingIndex(RegExpIndex index
)
877 : data_(uint32_t(index
) | RegExpTag
) {
878 MOZ_ASSERT(uint32_t(index
) < IndexLimit
);
880 explicit TaggedScriptThingIndex(ScopeIndex index
)
881 : data_(uint32_t(index
) | ScopeTag
) {
882 MOZ_ASSERT(uint32_t(index
) < IndexLimit
);
884 explicit TaggedScriptThingIndex(ScriptIndex index
)
885 : data_(uint32_t(index
) | FunctionTag
) {
886 MOZ_ASSERT(uint32_t(index
) < IndexLimit
);
888 explicit TaggedScriptThingIndex(EmptyGlobalScopeType t
)
889 : data_(EmptyGlobalScopeTag
) {}
891 bool isAtom() const {
892 return (data_
& TagMask
) == ParserAtomIndexTag
||
893 (data_
& TagMask
) == WellKnownTag
;
895 bool isNull() const {
896 bool result
= !data_
;
897 MOZ_ASSERT_IF(result
, (data_
& TagMask
) == NullTag
);
900 bool isBigInt() const { return (data_
& TagMask
) == BigIntTag
; }
901 bool isObjLiteral() const { return (data_
& TagMask
) == ObjLiteralTag
; }
902 bool isRegExp() const { return (data_
& TagMask
) == RegExpTag
; }
903 bool isScope() const { return (data_
& TagMask
) == ScopeTag
; }
904 bool isFunction() const { return (data_
& TagMask
) == FunctionTag
; }
905 bool isEmptyGlobalScope() const {
906 return (data_
& TagMask
) == EmptyGlobalScopeTag
;
909 TaggedParserAtomIndex
toAtom() const {
910 MOZ_ASSERT(isAtom());
911 return TaggedParserAtomIndex::fromRaw(data_
);
913 BigIntIndex
toBigInt() const { return BigIntIndex(data_
& IndexMask
); }
914 ObjLiteralIndex
toObjLiteral() const {
915 return ObjLiteralIndex(data_
& IndexMask
);
917 RegExpIndex
toRegExp() const { return RegExpIndex(data_
& IndexMask
); }
918 ScopeIndex
toScope() const { return ScopeIndex(data_
& IndexMask
); }
919 ScriptIndex
toFunction() const { return ScriptIndex(data_
& IndexMask
); }
921 TaggedParserAtomIndex
toAtomOrNull() const {
922 MOZ_ASSERT(isAtom() || isNull());
923 return TaggedParserAtomIndex::fromRaw(data_
);
926 uint32_t* rawDataRef() { return &data_
; }
927 uint32_t rawData() const { return data_
; }
929 Kind
tag() const { return Kind((data_
& TagMask
) >> TagShift
); }
931 bool operator==(const TaggedScriptThingIndex
& rhs
) const {
932 return data_
== rhs
.data_
;
936 // Data generated by frontend that will be used to create a js::BaseScript.
937 class ScriptStencil
{
938 friend struct CompilationStencilMerger
;
941 // Fields for BaseScript.
946 // * non-lazy Function (except asm.js module)
947 // * lazy Function (cannot be asm.js module)
949 // GCThings are stored into
950 // {ExtensibleCompilationStencil,CompilationStencil}.gcThingData,
951 // in [gcThingsOffset, gcThingsOffset + gcThingsLength) range.
952 CompilationGCThingIndex gcThingsOffset
;
953 uint32_t gcThingsLength
= 0;
955 // Fields for JSFunction.
957 // * non-lazy Function
961 // The explicit or implicit name of the function. The FunctionFlags indicate
963 TaggedParserAtomIndex functionAtom
;
965 // If this ScriptStencil refers to a lazy child of the function being
966 // compiled, this field holds the child's immediately enclosing scope's index.
967 // Once compilation succeeds, we will store the scope pointed by this in the
968 // child's BaseScript. (Debugger may become confused if lazy scripts refer to
969 // partially initialized enclosing scopes, so we must avoid storing the
970 // scope in the BaseScript until compilation has completed
975 // This may be used for self-hosting canonical name (TaggedParserAtomIndex).
976 TaggedScriptThingIndex enclosingScopeOrCanonicalName
;
978 // See: `FunctionFlags`.
979 FunctionFlags functionFlags
= {};
981 // This is set by the BytecodeEmitter of the enclosing script when a reference
982 // to this function is generated.
983 static constexpr uint16_t WasEmittedByEnclosingScriptFlag
= 1 << 0;
985 // If this is for the root of delazification, this represents
986 // MutableScriptFlagsEnum::AllowRelazify value of the script *after*
989 static constexpr uint16_t AllowRelazifyFlag
= 1 << 1;
991 // Set if this is non-lazy script and shared data is created.
992 // The shared data is stored into CompilationStencil.sharedData.
993 static constexpr uint16_t HasSharedDataFlag
= 1 << 2;
995 // True if this script is lazy function and has enclosing scope. In that
996 // case, `enclosingScopeOrCanonicalName` will hold the ScopeIndex.
997 static constexpr uint16_t HasLazyFunctionEnclosingScopeIndexFlag
= 1 << 3;
999 // True if this script is a self-hosted function with a canonical name
1000 // explicitly set. In that case, `enclosingScopeOrCanonicalName` will hold the
1001 // TaggedParserAtomIndex.
1002 static constexpr uint16_t HasSelfHostedCanonicalName
= 1 << 4;
1004 uint16_t flags_
= 0;
1008 ScriptStencil() = default;
1010 bool isFunction() const {
1011 bool result
= functionFlags
.toRaw() != 0x0000;
1013 result
, functionFlags
.isAsmJSNative() || functionFlags
.hasBaseScript());
1017 bool hasGCThings() const { return gcThingsLength
; }
1019 mozilla::Span
<TaggedScriptThingIndex
> gcthings(
1020 const CompilationStencil
& stencil
) const;
1022 bool wasEmittedByEnclosingScript() const {
1023 return flags_
& WasEmittedByEnclosingScriptFlag
;
1026 void setWasEmittedByEnclosingScript() {
1027 flags_
|= WasEmittedByEnclosingScriptFlag
;
1030 bool allowRelazify() const { return flags_
& AllowRelazifyFlag
; }
1032 void setAllowRelazify() { flags_
|= AllowRelazifyFlag
; }
1034 bool isGhost() const { return functionFlags
.isGhost(); }
1035 void setIsGhost() { functionFlags
.setIsGhost(); }
1037 bool hasSharedData() const { return flags_
& HasSharedDataFlag
; }
1039 void setHasSharedData() { flags_
|= HasSharedDataFlag
; }
1041 bool hasLazyFunctionEnclosingScopeIndex() const {
1042 return flags_
& HasLazyFunctionEnclosingScopeIndexFlag
;
1045 bool hasSelfHostedCanonicalName() const {
1046 return flags_
& HasSelfHostedCanonicalName
;
1050 void setHasLazyFunctionEnclosingScopeIndex() {
1051 flags_
|= HasLazyFunctionEnclosingScopeIndexFlag
;
1054 void setHasSelfHostedCanonicalName() { flags_
|= HasSelfHostedCanonicalName
; }
1057 void setLazyFunctionEnclosingScopeIndex(ScopeIndex index
) {
1058 MOZ_ASSERT(enclosingScopeOrCanonicalName
.isNull());
1059 enclosingScopeOrCanonicalName
= TaggedScriptThingIndex(index
);
1060 setHasLazyFunctionEnclosingScopeIndex();
1063 void resetHasLazyFunctionEnclosingScopeIndexAfterStencilMerge() {
1064 flags_
&= ~HasLazyFunctionEnclosingScopeIndexFlag
;
1065 enclosingScopeOrCanonicalName
= TaggedScriptThingIndex();
1068 ScopeIndex
lazyFunctionEnclosingScopeIndex() const {
1069 MOZ_ASSERT(hasLazyFunctionEnclosingScopeIndex());
1070 return enclosingScopeOrCanonicalName
.toScope();
1073 void setSelfHostedCanonicalName(TaggedParserAtomIndex name
) {
1074 MOZ_ASSERT(enclosingScopeOrCanonicalName
.isNull());
1075 enclosingScopeOrCanonicalName
= TaggedScriptThingIndex(name
);
1076 setHasSelfHostedCanonicalName();
1079 TaggedParserAtomIndex
selfHostedCanonicalName() const {
1080 MOZ_ASSERT(hasSelfHostedCanonicalName());
1081 return enclosingScopeOrCanonicalName
.toAtom();
1084 #if defined(DEBUG) || defined(JS_JITSPEW)
1086 void dump(JSONPrinter
& json
, const CompilationStencil
* stencil
) const;
1087 void dumpFields(JSONPrinter
& json
, const CompilationStencil
* stencil
) const;
1091 // In addition to ScriptStencil, data generated only while initial-parsing.
1092 class ScriptStencilExtra
{
1094 // See `BaseScript::immutableFlags_`.
1095 ImmutableScriptFlags immutableFlags
;
1097 // The location of this script in the source.
1098 SourceExtent extent
;
1100 // See `PrivateScriptData::memberInitializers_`.
1101 // This data only valid when `UseMemberInitializers` script flag is true.
1102 uint32_t memberInitializers_
= 0;
1104 // See `JSFunction::nargs_`.
1107 // To make this struct packed, add explicit field for padding.
1108 uint16_t padding_
= 0;
1110 ScriptStencilExtra() = default;
1112 RO_IMMUTABLE_SCRIPT_FLAGS(immutableFlags
)
1114 void setMemberInitializers(MemberInitializers member
) {
1115 MOZ_ASSERT(useMemberInitializers());
1116 memberInitializers_
= member
.serialize();
1119 MemberInitializers
memberInitializers() const {
1120 MOZ_ASSERT(useMemberInitializers());
1121 return MemberInitializers::deserialize(memberInitializers_
);
1124 #if defined(DEBUG) || defined(JS_JITSPEW)
1126 void dump(JSONPrinter
& json
) const;
1127 void dumpFields(JSONPrinter
& json
) const;
1131 #if defined(DEBUG) || defined(JS_JITSPEW)
1132 void DumpTaggedParserAtomIndex(js::JSONPrinter
& json
,
1133 TaggedParserAtomIndex taggedIndex
,
1134 const CompilationStencil
* stencil
);
1136 void DumpTaggedParserAtomIndexNoQuote(GenericPrinter
& out
,
1137 TaggedParserAtomIndex taggedIndex
,
1138 const CompilationStencil
* stencil
);
1141 } /* namespace frontend */
1143 #if defined(DEBUG) || defined(JS_JITSPEW)
1144 void DumpImmutableScriptFlags(js::JSONPrinter
& json
,
1145 ImmutableScriptFlags immutableFlags
);
1146 void DumpFunctionFlagsItems(js::JSONPrinter
& json
, FunctionFlags functionFlags
);
1149 } /* namespace js */
1151 #endif /* frontend_Stencil_h */