Bug 1874684 - Part 31: Correctly reject invalid durations in some RoundDuration calls...
[gecko.git] / js / src / frontend / Stencil.h
blob91308ffcc920fde9df41aa67b5377e3a161f4d2d
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
37 namespace js {
39 class LifoAlloc;
40 class JSONPrinter;
41 class RegExpObject;
43 namespace frontend {
45 struct CompilationInput;
46 struct CompilationStencil;
47 struct CompilationAtomCache;
48 struct CompilationGCOutput;
49 struct CompilationStencilMerger;
50 class RegExpStencil;
51 class BigIntStencil;
52 class StencilXDR;
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
78 // and flexible.
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.
87 // ParserAtom
88 // ----------
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.
96 // ScriptStencil
97 // -------------
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):
105 // * ParserAtom
106 // * ScopeStencil
107 // * RegExpStencil
108 // * BigIntStencil
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 = ...;
147 // {
148 // BorrowingCompilationStencil stencil(extensible);
149 // // Use `stencil reference.
150 // }
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.
191 // CompilationState
192 // ----------------
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
195 // released.
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.
212 uint32_t flags_;
214 friend struct CompilationStencilMerger;
216 public:
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)
234 void dump() const;
235 void dump(JSONPrinter& json, const CompilationStencil* stencil) const;
236 void dumpFields(JSONPrinter& json, const CompilationStencil* stencil) const;
237 #endif
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_;
250 public:
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;
258 bool isZero() const;
260 mozilla::Span<const char16_t> source() const { return source_; }
262 #ifdef DEBUG
263 bool isContainedIn(const LifoAlloc& alloc) const;
264 #endif
266 #if defined(DEBUG) || defined(JS_JITSPEW)
267 void dump() const;
268 void dump(JSONPrinter& json) const;
269 void dumpCharsNoQuote(GenericPrinter& out) const;
270 #endif
273 class ScopeStencil {
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;
311 uint8_t flags_ = 0;
313 // To make this struct packed, add explicit field for padding.
314 uint16_t padding_ = 0;
316 public:
317 // For XDR only.
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))),
329 kind_(kind),
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.
335 (void)padding_;
338 private:
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);
347 public:
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,
369 ScopeIndex* index);
371 static bool createForGlobalScope(FrontendContext* fc,
372 CompilationState& compilationState,
373 ScopeKind kind,
374 GlobalScope::ParserData* dataArg,
375 ScopeIndex* index);
377 static bool createForEvalScope(FrontendContext* fc,
378 CompilationState& compilationState,
379 ScopeKind kind, EvalScope::ParserData* dataArg,
380 mozilla::Maybe<ScopeIndex> enclosing,
381 ScopeIndex* index);
383 static bool createForModuleScope(FrontendContext* fc,
384 CompilationState& compilationState,
385 ModuleScope::ParserData* dataArg,
386 mozilla::Maybe<ScopeIndex> enclosing,
387 ScopeIndex* index);
389 static bool createForWithScope(FrontendContext* fc,
390 CompilationState& compilationState,
391 mozilla::Maybe<ScopeIndex> enclosing,
392 ScopeIndex* index);
394 AbstractScopePtr enclosing(CompilationState& compilationState) const;
395 js::Scope* enclosingExistingScope(const CompilationInput& input,
396 const CompilationGCOutput& gcOutput) const;
398 private:
399 bool hasEnclosing() const { return flags_ & HasEnclosing; }
401 ScopeIndex enclosing() const {
402 MOZ_ASSERT(hasEnclosing());
403 return enclosing_;
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_; }
419 public:
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)
438 void dump() const;
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;
443 #endif
445 private:
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) {
464 switch (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: {
498 return false;
501 return false;
505 class StencilModuleAssertion {
506 public:
507 TaggedParserAtomIndex key;
508 TaggedParserAtomIndex value;
510 StencilModuleAssertion() = default;
511 StencilModuleAssertion(TaggedParserAtomIndex key, TaggedParserAtomIndex value)
512 : key(key), value(value) {}
515 class StencilModuleRequest {
516 public:
517 TaggedParserAtomIndex specifier;
519 using AssertionVector =
520 Vector<StencilModuleAssertion, 0, js::SystemAllocPolicy>;
521 AssertionVector assertions;
523 // For XDR only.
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);
545 return *this;
548 StencilModuleRequest& operator=(StencilModuleRequest&& other) noexcept {
549 specifier = other.specifier;
550 assertions = std::move(other.assertions);
551 return *this;
555 class MaybeModuleRequestIndex {
556 static constexpr uint32_t NOTHING = UINT32_MAX;
558 uint32_t bits = NOTHING;
560 public:
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) =
568 default;
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());
576 return bits;
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
589 // for readability.
590 class StencilModuleEntry {
591 public:
592 // clang-format off
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 |
601 // clang-format on
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).
613 uint32_t lineno = 0;
615 // Column number in UTF-16 code units.
616 JS::ColumnNumberOneOrigin column;
618 private:
619 StencilModuleEntry(uint32_t lineno, JS::ColumnNumberOneOrigin column)
620 : lineno(lineno), column(column) {}
622 public:
623 // For XDR only.
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;
649 return *this;
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;
659 return *this;
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;
668 return entry;
671 static StencilModuleEntry importEntry(MaybeModuleRequestIndex moduleRequest,
672 TaggedParserAtomIndex localName,
673 TaggedParserAtomIndex importName,
674 uint32_t lineno,
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;
682 return entry;
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;
693 return entry;
696 static StencilModuleEntry exportAsEntry(TaggedParserAtomIndex localName,
697 TaggedParserAtomIndex exportName,
698 uint32_t lineno,
699 JS::ColumnNumberOneOrigin column) {
700 MOZ_ASSERT(localName && exportName);
701 StencilModuleEntry entry(lineno, column);
702 entry.localName = localName;
703 entry.exportName = exportName;
704 return entry;
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;
717 return entry;
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;
728 return entry;
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);
737 return entry;
741 // Metadata generated by parsing module scripts, including import/export tables.
742 class StencilModuleMetadata
743 : public js::AtomicRefCounted<StencilModuleMetadata> {
744 public:
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)
775 void dump() const;
776 void dump(JSONPrinter& json, const CompilationStencil* stencil) const;
777 void dumpFields(JSONPrinter& json, const CompilationStencil* stencil) const;
778 #endif
780 private:
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.
809 // 0x0000_0000 Null
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 {
819 uint32_t data_;
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;
828 public:
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),
833 BigInt,
834 ObjLiteral,
835 RegExp,
836 Scope,
837 Function,
838 EmptyGlobalScope,
841 private:
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)
845 << TagShift;
846 static_assert(ParserAtomIndexTag ==
847 TaggedParserAtomIndex::ParserAtomIndexTag);
848 static constexpr uint32_t WellKnownTag = uint32_t(Kind::WellKnown)
849 << TagShift;
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)
854 << TagShift;
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;
861 public:
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);
898 return result;
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;
940 public:
941 // Fields for BaseScript.
942 // Used by:
943 // * Global script
944 // * Eval
945 // * Module
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.
956 // Used by:
957 // * non-lazy Function
958 // * lazy Function
959 // * asm.js module
961 // The explicit or implicit name of the function. The FunctionFlags indicate
962 // the kind of name.
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
971 // successfully.)
973 // OR
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*
987 // delazification.
988 // False otherwise.
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;
1006 // End of fields.
1008 ScriptStencil() = default;
1010 bool isFunction() const {
1011 bool result = functionFlags.toRaw() != 0x0000;
1012 MOZ_ASSERT_IF(
1013 result, functionFlags.isAsmJSNative() || functionFlags.hasBaseScript());
1014 return result;
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;
1049 private:
1050 void setHasLazyFunctionEnclosingScopeIndex() {
1051 flags_ |= HasLazyFunctionEnclosingScopeIndexFlag;
1054 void setHasSelfHostedCanonicalName() { flags_ |= HasSelfHostedCanonicalName; }
1056 public:
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)
1085 void dump() const;
1086 void dump(JSONPrinter& json, const CompilationStencil* stencil) const;
1087 void dumpFields(JSONPrinter& json, const CompilationStencil* stencil) const;
1088 #endif
1091 // In addition to ScriptStencil, data generated only while initial-parsing.
1092 class ScriptStencilExtra {
1093 public:
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_`.
1105 uint16_t nargs = 0;
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)
1125 void dump() const;
1126 void dump(JSONPrinter& json) const;
1127 void dumpFields(JSONPrinter& json) const;
1128 #endif
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);
1139 #endif
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);
1147 #endif
1149 } /* namespace js */
1151 #endif /* frontend_Stencil_h */