diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
commit | 2aa4a82499d4becd2284cdb482213d541b8804dd (patch) | |
tree | b80bf8bf13c3766139fbacc530efd0dd9d54394c /js/src/frontend/CompilationInfo.h | |
parent | Initial commit. (diff) | |
download | firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.tar.xz firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.zip |
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | js/src/frontend/CompilationInfo.h | 706 |
1 files changed, 706 insertions, 0 deletions
diff --git a/js/src/frontend/CompilationInfo.h b/js/src/frontend/CompilationInfo.h new file mode 100644 index 0000000000..88bb6612b5 --- /dev/null +++ b/js/src/frontend/CompilationInfo.h @@ -0,0 +1,706 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: set ts=8 sts=2 et sw=2 tw=80: + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef frontend_CompilationInfo_h +#define frontend_CompilationInfo_h + +#include "mozilla/AlreadyAddRefed.h" // already_AddRefed +#include "mozilla/Assertions.h" // MOZ_ASSERT +#include "mozilla/Attributes.h" +#include "mozilla/RefPtr.h" // RefPtr +#include "mozilla/Span.h" + +#include "builtin/ModuleObject.h" +#include "ds/LifoAlloc.h" +#include "frontend/ParserAtom.h" +#include "frontend/ScriptIndex.h" // ScriptIndex +#include "frontend/SharedContext.h" +#include "frontend/Stencil.h" +#include "frontend/UsedNameTracker.h" +#include "js/GCVector.h" +#include "js/HashTable.h" +#include "js/RealmOptions.h" +#include "js/SourceText.h" +#include "js/Transcoding.h" +#include "js/Vector.h" +#include "js/WasmModule.h" +#include "vm/GlobalObject.h" // GlobalObject +#include "vm/JSContext.h" +#include "vm/JSFunction.h" // JSFunction +#include "vm/JSScript.h" // SourceExtent +#include "vm/Realm.h" +#include "vm/SharedStencil.h" // SharedImmutableScriptData + +namespace js { + +class JSONPrinter; + +namespace frontend { + +// ScopeContext hold information derivied from the scope and environment chains +// to try to avoid the parser needing to traverse VM structures directly. +struct ScopeContext { + // If this eval is in response to Debugger.Frame.eval, we may have an + // incomplete scope chain. In order to provide a better debugging experience, + // we inspect the (optional) environment chain to determine it's enclosing + // FunctionScope if there is one. If there is no such scope, we use the + // orignal scope provided. + // + // NOTE: This is used to compute the ThisBinding kind and to allow access to + // private fields, while other contextual information only uses the + // actual scope passed to the compile. + JS::Rooted<Scope*> effectiveScope; + + // The type of binding required for `this` of the top level context, as + // indicated by the enclosing scopes of this parse. + // + // NOTE: This is computed based on the effective scope (defined above). + ThisBinding thisBinding = ThisBinding::Global; + + // Eval and arrow scripts inherit certain syntax allowances from their + // enclosing scripts. + bool allowNewTarget = false; + bool allowSuperProperty = false; + bool allowSuperCall = false; + bool allowArguments = true; + + // Eval and arrow scripts also inherit the "this" environment -- used by + // `super` expressions -- from their enclosing script. We count the number of + // environment hops needed to get from enclosing scope to the nearest + // appropriate environment. This value is undefined if the script we are + // compiling is not an eval or arrow-function. + uint32_t enclosingThisEnvironmentHops = 0; + + // Class field initializer info if we are nested within a class constructor. + // We may be an combination of arrow and eval context within the constructor. + mozilla::Maybe<MemberInitializers> memberInitializers = {}; + + // Indicates there is a 'class' or 'with' scope on enclosing scope chain. + bool inClass = false; + bool inWith = false; + + explicit ScopeContext(JSContext* cx, InheritThis inheritThis, Scope* scope, + JSObject* enclosingEnv = nullptr) + : effectiveScope(cx, determineEffectiveScope(scope, enclosingEnv)) { + if (inheritThis == InheritThis::Yes) { + computeThisBinding(effectiveScope); + computeThisEnvironment(scope); + } + computeInScope(scope); + } + + private: + void computeThisBinding(Scope* scope); + void computeThisEnvironment(Scope* scope); + void computeInScope(Scope* scope); + + static Scope* determineEffectiveScope(Scope* scope, JSObject* environment); +}; + +struct CompilationAtomCache { + public: + using AtomCacheVector = JS::GCVector<JSAtom*, 0, js::SystemAllocPolicy>; + + private: + // Atoms lowered into or converted from BaseCompilationStencil.parserAtomData. + // + // This field is here instead of in CompilationGCOutput because atoms lowered + // from JSAtom is part of input (enclosing scope bindings, lazy function name, + // etc), and having 2 vectors in both input/output is error prone. + AtomCacheVector atoms_; + + public: + JSAtom* getExistingAtomAt(ParserAtomIndex index) const; + JSAtom* getExistingAtomAt(JSContext* cx, + TaggedParserAtomIndex taggedIndex) const; + JSAtom* getAtomAt(ParserAtomIndex index) const; + bool hasAtomAt(ParserAtomIndex index) const; + bool setAtomAt(JSContext* cx, ParserAtomIndex index, JSAtom* atom); + bool allocate(JSContext* cx, size_t length); + bool extendIfNecessary(JSContext* cx, size_t length); + + void stealBuffer(AtomCacheVector& atoms); + void releaseBuffer(AtomCacheVector& atoms); + + void trace(JSTracer* trc); +} JS_HAZ_GC_POINTER; + +// Input of the compilation, including source and enclosing context. +struct CompilationInput { + const JS::ReadOnlyCompileOptions& options; + + CompilationAtomCache atomCache; + + BaseScript* lazy = nullptr; + + ScriptSourceHolder source_; + + // * If we're compiling standalone function, the non-null enclosing scope of + // the function + // * If we're compiling eval, the non-null enclosing scope of the `eval`. + // * If we're compiling module, null that means empty global scope + // (See EmitterScope::checkEnvironmentChainLength) + // * If we're compiling self-hosted JS, an empty global scope. + // This scope is also used for EmptyGlobalScopeType in + // BaseCompilationStencil.gcThings. + // See the comment in initForSelfHostingGlobal. + // * Null otherwise + Scope* enclosingScope = nullptr; + + explicit CompilationInput(const JS::ReadOnlyCompileOptions& options) + : options(options) {} + + private: + bool initScriptSource(JSContext* cx); + + public: + bool initForGlobal(JSContext* cx) { return initScriptSource(cx); } + + bool initForSelfHostingGlobal(JSContext* cx) { + if (!initScriptSource(cx)) { + return false; + } + + // This enclosing scope is also recorded as EmptyGlobalScopeType in + // BaseCompilationStencil.gcThings even though corresponding ScopeStencil + // isn't generated. + // + // Store the enclosing scope here in order to access it from + // inner scopes' ScopeStencil::enclosing. + enclosingScope = &cx->global()->emptyGlobalScope(); + return true; + } + + bool initForStandaloneFunction(JSContext* cx, + HandleScope functionEnclosingScope) { + if (!initScriptSource(cx)) { + return false; + } + enclosingScope = functionEnclosingScope; + return true; + } + + bool initForEval(JSContext* cx, HandleScope evalEnclosingScope) { + if (!initScriptSource(cx)) { + return false; + } + enclosingScope = evalEnclosingScope; + return true; + } + + bool initForModule(JSContext* cx) { + if (!initScriptSource(cx)) { + return false; + } + // The `enclosingScope` is the emptyGlobalScope. + return true; + } + + void initFromLazy(BaseScript* lazyScript) { + lazy = lazyScript; + enclosingScope = lazy->function()->enclosingScope(); + } + + ScriptSource* source() { return source_.get(); } + + void setSource(ScriptSource* ss) { return source_.reset(ss); } + + template <typename Unit> + MOZ_MUST_USE bool assignSource(JSContext* cx, + JS::SourceText<Unit>& sourceBuffer) { + return source()->assignSource(cx, options, sourceBuffer); + } + + void trace(JSTracer* trc); +} JS_HAZ_GC_POINTER; + +struct CompilationStencil; + +struct MOZ_RAII CompilationState { + // Until we have dealt with Atoms in the front end, we need to hold + // onto them. + Directives directives; + + ScopeContext scopeContext; + + UsedNameTracker usedNames; + LifoAllocScope& allocScope; + + CompilationInput& input; + + // Temporary space to accumulate stencil data. + // Copied to BaseCompilationStencil by `finish` method. + // + // See corresponding BaseCompilationStencil fields for desription. + Vector<RegExpStencil, 0, js::SystemAllocPolicy> regExpData; + Vector<ScriptStencil, 0, js::SystemAllocPolicy> scriptData; + Vector<ScriptStencilExtra, 0, js::SystemAllocPolicy> scriptExtra; + Vector<ScopeStencil, 0, js::SystemAllocPolicy> scopeData; + Vector<BaseParserScopeData*, 0, js::SystemAllocPolicy> scopeNames; + Vector<TaggedScriptThingIndex, 0, js::SystemAllocPolicy> gcThingData; + + // Table of parser atoms for this compilation. + ParserAtomsTable parserAtoms; + + // The number of functions that *will* have bytecode. + // This doesn't count top-level non-function script. + // + // This should be counted while parsing, and should be passed to + // BaseCompilationStencil.prepareStorageFor *before* start emitting bytecode. + size_t nonLazyFunctionCount = 0; + + CompilationState(JSContext* cx, LifoAllocScope& frontendAllocScope, + const JS::ReadOnlyCompileOptions& options, + CompilationStencil& stencil, + InheritThis inheritThis = InheritThis::No, + Scope* enclosingScope = nullptr, + JSObject* enclosingEnv = nullptr); + + bool finish(JSContext* cx, CompilationStencil& stencil); + + const ParserAtom* getParserAtomAt(JSContext* cx, + TaggedParserAtomIndex taggedIndex) const; + + // Allocate space for `length` gcthings, and return the address of the + // first element to `cursor` to initialize on the caller. + bool allocateGCThingsUninitialized(JSContext* cx, ScriptIndex scriptIndex, + size_t length, + TaggedScriptThingIndex** cursor); + + bool appendGCThings(JSContext* cx, ScriptIndex scriptIndex, + mozilla::Span<const TaggedScriptThingIndex> things); +}; + +// Store shared data for non-lazy script. +struct SharedDataContainer { + // NOTE: While stored, we must hold a ref-count and care must be taken when + // updating or clearing the pointer. + using SingleSharedDataPtr = SharedImmutableScriptData*; + + using SharedDataVector = + Vector<RefPtr<js::SharedImmutableScriptData>, 0, js::SystemAllocPolicy>; + using SharedDataVectorPtr = SharedDataVector*; + + using SharedDataMap = + HashMap<ScriptIndex, RefPtr<js::SharedImmutableScriptData>, + mozilla::DefaultHasher<ScriptIndex>, js::SystemAllocPolicy>; + using SharedDataMapPtr = SharedDataMap*; + + private: + enum { + SingleTag = 0, + VectorTag = 1, + MapTag = 2, + + TagMask = 3, + }; + + uintptr_t data_ = 0; + + public: + // Defaults to SingleSharedData for delazification vector. + SharedDataContainer() = default; + + ~SharedDataContainer(); + + bool initVector(JSContext* cx); + bool initMap(JSContext* cx); + + bool isEmpty() const { return (data_) == SingleTag; } + bool isSingle() const { return (data_ & TagMask) == SingleTag; } + bool isVector() const { return (data_ & TagMask) == VectorTag; } + bool isMap() const { return (data_ & TagMask) == MapTag; } + + void setSingle(already_AddRefed<SharedImmutableScriptData>&& data) { + MOZ_ASSERT(isEmpty()); + data_ = reinterpret_cast<uintptr_t>(data.take()); + MOZ_ASSERT(isSingle()); + } + + SingleSharedDataPtr asSingle() { + MOZ_ASSERT(isSingle()); + MOZ_ASSERT(!isEmpty()); + static_assert(SingleTag == 0); + return reinterpret_cast<SingleSharedDataPtr>(data_); + } + SharedDataVectorPtr asVector() { + MOZ_ASSERT(isVector()); + return reinterpret_cast<SharedDataVectorPtr>(data_ & ~TagMask); + } + SharedDataMapPtr asMap() { + MOZ_ASSERT(isMap()); + return reinterpret_cast<SharedDataMapPtr>(data_ & ~TagMask); + } + + bool prepareStorageFor(JSContext* cx, size_t nonLazyScriptCount, + size_t allScriptCount); + + // Returns index-th script's shared data, or nullptr if it doesn't have. + js::SharedImmutableScriptData* get(ScriptIndex index); + + // Add data for index-th script and share it with VM. + bool addAndShare(JSContext* cx, ScriptIndex index, + js::SharedImmutableScriptData* data); + +#if defined(DEBUG) || defined(JS_JITSPEW) + void dump(); + void dump(js::JSONPrinter& json); + void dumpFields(js::JSONPrinter& json); +#endif +}; + +// The top level struct of stencil. +struct BaseCompilationStencil { + // Hold onto the RegExpStencil, BigIntStencil, and ObjLiteralStencil that are + // allocated during parse to ensure correct destruction. + mozilla::Span<RegExpStencil> regExpData; + Vector<BigIntStencil, 0, js::SystemAllocPolicy> bigIntData; + Vector<ObjLiteralStencil, 0, js::SystemAllocPolicy> objLiteralData; + + // Stencil for all function and non-function scripts. The TopLevelIndex is + // reserved for the top-level script. This top-level may or may not be a + // function. + mozilla::Span<ScriptStencil> scriptData; + SharedDataContainer sharedData; + mozilla::Span<TaggedScriptThingIndex> gcThingData; + + // scopeData and scopeNames have the same size, and i-th scopeNames contains + // the names for the bindings contained in the slot defined by i-th scopeData. + mozilla::Span<ScopeStencil> scopeData; + mozilla::Span<BaseParserScopeData*> scopeNames; + + // List of parser atoms for this compilation. + // This may contain nullptr entries when round-tripping with XDR if the atom + // was generated in original parse but not used by stencil. + ParserAtomSpan parserAtomData; + + // FunctionKey is an identifier that identifies a function within the source + // next in a reproducible way. It allows us to match delazification data with + // initial parse data, even across different runs. This is only used for + // delazification stencils. + using FunctionKey = uint32_t; + + static constexpr FunctionKey NullFunctionKey = 0; + + FunctionKey functionKey = NullFunctionKey; + + BaseCompilationStencil() = default; + + // We need a move-constructor to work with Rooted. + BaseCompilationStencil(BaseCompilationStencil&& other) = default; + + const ParserAtom* getParserAtomAt(JSContext* cx, + TaggedParserAtomIndex taggedIndex) const; + + bool prepareStorageFor(JSContext* cx, CompilationState& compilationState) { + // NOTE: At this point CompilationState shouldn't be finished, and + // BaseCompilationStencil.scriptData field should be empty. + // Use CompilationState.scriptData as data source. + MOZ_ASSERT(scriptData.empty()); + size_t allScriptCount = compilationState.scriptData.length(); + size_t nonLazyScriptCount = compilationState.nonLazyFunctionCount; + if (!compilationState.scriptData[0].isFunction()) { + nonLazyScriptCount++; + } + return sharedData.prepareStorageFor(cx, nonLazyScriptCount, allScriptCount); + } + + static FunctionKey toFunctionKey(const SourceExtent& extent) { + // In eval("x=>1"), the arrow function will have a sourceStart of 0 which + // conflicts with the NullFunctionKey, so shift all keys by 1 instead. + auto result = extent.sourceStart + 1; + MOZ_ASSERT(result != NullFunctionKey); + return result; + } + + bool isInitialStencil() const { return functionKey == NullFunctionKey; } + + bool isCompilationStencil() const { return isInitialStencil(); } + inline CompilationStencil& asCompilationStencil(); + inline const CompilationStencil& asCompilationStencil() const; + +#if defined(DEBUG) || defined(JS_JITSPEW) + void dump(); + void dump(js::JSONPrinter& json); + void dumpFields(js::JSONPrinter& json); +#endif +}; + +// The output of GC allocation from stencil. +struct CompilationGCOutput { + // The resulting outermost script for the compilation powered + // by this CompilationStencil. + JSScript* script = nullptr; + + // The resulting module object if there is one. + ModuleObject* module = nullptr; + + // A Rooted vector to handle tracing of JSFunction* and Atoms within. + // + // If the top level script isn't a function, the item at TopLevelIndex is + // nullptr. + JS::GCVector<JSFunction*, 0, js::SystemAllocPolicy> functions; + + // References to scopes are controlled via AbstractScopePtr, which holds onto + // an index (and CompilationStencil reference). + JS::GCVector<js::Scope*, 0, js::SystemAllocPolicy> scopes; + + // The result ScriptSourceObject. This is unused in delazifying parses. + ScriptSourceObject* sourceObject = nullptr; + + CompilationGCOutput() = default; + + void trace(JSTracer* trc); +} JS_HAZ_GC_POINTER; + +class ScriptStencilIterable { + public: + class ScriptAndFunction { + public: + const ScriptStencil& script; + const ScriptStencilExtra* scriptExtra; + JSFunction* function; + ScriptIndex index; + + ScriptAndFunction() = delete; + ScriptAndFunction(const ScriptStencil& script, + const ScriptStencilExtra* scriptExtra, + JSFunction* function, ScriptIndex index) + : script(script), + scriptExtra(scriptExtra), + function(function), + index(index) {} + }; + + class Iterator { + size_t index_ = 0; + const BaseCompilationStencil& stencil_; + CompilationGCOutput& gcOutput_; + + Iterator(const BaseCompilationStencil& stencil, + CompilationGCOutput& gcOutput, size_t index) + : index_(index), stencil_(stencil), gcOutput_(gcOutput) { + MOZ_ASSERT(index == stencil.scriptData.size()); + } + + public: + explicit Iterator(const BaseCompilationStencil& stencil, + CompilationGCOutput& gcOutput) + : stencil_(stencil), gcOutput_(gcOutput) { + skipTopLevelNonFunction(); + } + + Iterator operator++() { + next(); + assertFunction(); + return *this; + } + + void next() { + MOZ_ASSERT(index_ < stencil_.scriptData.size()); + index_++; + } + + void assertFunction() { + if (index_ < stencil_.scriptData.size()) { + MOZ_ASSERT(stencil_.scriptData[index_].isFunction()); + } + } + + void skipTopLevelNonFunction() { + MOZ_ASSERT(index_ == 0); + if (stencil_.scriptData.size()) { + if (!stencil_.scriptData[0].isFunction()) { + next(); + assertFunction(); + } + } + } + + bool operator!=(const Iterator& other) const { + return index_ != other.index_; + } + + inline ScriptAndFunction operator*(); + + static Iterator end(const BaseCompilationStencil& stencil, + CompilationGCOutput& gcOutput) { + return Iterator(stencil, gcOutput, stencil.scriptData.size()); + } + }; + + const BaseCompilationStencil& stencil_; + CompilationGCOutput& gcOutput_; + + explicit ScriptStencilIterable(const BaseCompilationStencil& stencil, + CompilationGCOutput& gcOutput) + : stencil_(stencil), gcOutput_(gcOutput) {} + + Iterator begin() const { return Iterator(stencil_, gcOutput_); } + + Iterator end() const { return Iterator::end(stencil_, gcOutput_); } +}; + +// Input and output of compilation to stencil. +struct CompilationStencil : public BaseCompilationStencil { + static constexpr ScriptIndex TopLevelIndex = ScriptIndex(0); + + // This holds allocations that do not require destructors to be run but are + // live until the stencil is released. + LifoAlloc alloc; + + // Parameterized chunk size to use for LifoAlloc. + static constexpr size_t LifoAllocChunkSize = 512; + + CompilationInput input; + + // Initial-compilation-specific data for each script. + mozilla::Span<ScriptStencilExtra> scriptExtra; + + // Module metadata if this is a module compile. + mozilla::Maybe<StencilModuleMetadata> moduleMetadata; + + // AsmJS modules generated by parsing. + HashMap<ScriptIndex, RefPtr<const JS::WasmModule>, + mozilla::DefaultHasher<ScriptIndex>, js::SystemAllocPolicy> + asmJS; + + // Set to true once prepareForInstantiate is called. + // NOTE: This field isn't XDR-encoded. + bool preparationIsPerformed = false; + + // Track the state of key allocations and roll them back as parts of parsing + // get retried. This ensures iteration during stencil instantiation does not + // encounter discarded frontend state. + struct RewindToken { + // Temporarily share this token struct with CompilationState. + size_t scriptDataLength = 0; + + size_t asmJSCount = 0; + }; + + RewindToken getRewindToken(CompilationState& state); + void rewind(CompilationState& state, const RewindToken& pos); + + // Construct a CompilationStencil + CompilationStencil(JSContext* cx, const JS::ReadOnlyCompileOptions& options) + : alloc(LifoAllocChunkSize), input(options) {} + + static MOZ_MUST_USE bool prepareInputAndStencilForInstantiate( + JSContext* cx, CompilationInput& input, BaseCompilationStencil& stencil); + static MOZ_MUST_USE bool prepareGCOutputForInstantiate( + JSContext* cx, BaseCompilationStencil& stencil, + CompilationGCOutput& gcOutput); + + static MOZ_MUST_USE bool prepareForInstantiate(JSContext* cx, + CompilationStencil& stencil, + CompilationGCOutput& gcOutput); + static MOZ_MUST_USE bool instantiateStencils(JSContext* cx, + CompilationStencil& stencil, + CompilationGCOutput& gcOutput); + static MOZ_MUST_USE bool instantiateStencilsAfterPreparation( + JSContext* cx, CompilationInput& input, BaseCompilationStencil& stencil, + CompilationGCOutput& gcOutput); + + MOZ_MUST_USE bool serializeStencils(JSContext* cx, JS::TranscodeBuffer& buf, + bool* succeededOut = nullptr); + + // Move constructor is necessary to use Rooted, but must be explicit in + // order to steal the LifoAlloc data + CompilationStencil(CompilationStencil&& other) noexcept + : BaseCompilationStencil(std::move(other)), + alloc(LifoAllocChunkSize), + input(std::move(other.input)) { + // Steal the data from the LifoAlloc. + alloc.steal(&other.alloc); + } + + // To avoid any misuses, make sure this is neither copyable or assignable. + CompilationStencil(const CompilationStencil&) = delete; + CompilationStencil& operator=(const CompilationStencil&) = delete; + CompilationStencil& operator=(CompilationStencil&&) = delete; + + static ScriptStencilIterable functionScriptStencils( + BaseCompilationStencil& stencil, CompilationGCOutput& gcOutput) { + return ScriptStencilIterable(stencil, gcOutput); + } + + void trace(JSTracer* trc); + +#if defined(DEBUG) || defined(JS_JITSPEW) + void dump(); + void dump(js::JSONPrinter& json); + void dumpFields(js::JSONPrinter& json); +#endif +}; + +inline CompilationStencil& BaseCompilationStencil::asCompilationStencil() { + MOZ_ASSERT(isCompilationStencil()); + return *static_cast<CompilationStencil*>(this); +} + +inline const CompilationStencil& BaseCompilationStencil::asCompilationStencil() + const { + MOZ_ASSERT(isCompilationStencil()); + return *reinterpret_cast<const CompilationStencil*>(this); +} + +inline ScriptStencilIterable::ScriptAndFunction +ScriptStencilIterable::Iterator::operator*() { + ScriptIndex index = ScriptIndex(index_); + const ScriptStencil& script = stencil_.scriptData[index]; + const ScriptStencilExtra* scriptExtra = nullptr; + if (stencil_.isInitialStencil()) { + scriptExtra = &stencil_.asCompilationStencil().scriptExtra[index]; + } + return ScriptAndFunction(script, scriptExtra, gcOutput_.functions[index], + index); +} + +// A set of stencils, for XDR purpose. +// This contains the initial compilation, and a vector of delazification. +struct CompilationStencilSet : public CompilationStencil { + private: + using ScriptIndexVector = Vector<ScriptIndex, 0, js::SystemAllocPolicy>; + + MOZ_MUST_USE bool buildDelazificationIndices(JSContext* cx); + + public: + Vector<BaseCompilationStencil, 0, js::SystemAllocPolicy> delazifications; + ScriptIndexVector delazificationIndices; + CompilationAtomCache::AtomCacheVector delazificationAtomCache; + + CompilationStencilSet(JSContext* cx, + const JS::ReadOnlyCompileOptions& options) + : CompilationStencil(cx, options) {} + + // Move constructor is necessary to use Rooted. + CompilationStencilSet(CompilationStencilSet&& other) = default; + + // To avoid any misuses, make sure this is neither copyable or assignable. + CompilationStencilSet(const CompilationStencilSet&) = delete; + CompilationStencilSet& operator=(const CompilationStencilSet&) = delete; + CompilationStencilSet& operator=(CompilationStencilSet&&) = delete; + + MOZ_MUST_USE bool prepareForInstantiate( + JSContext* cx, CompilationGCOutput& gcOutput, + CompilationGCOutput& gcOutputForDelazification); + MOZ_MUST_USE bool instantiateStencils( + JSContext* cx, CompilationGCOutput& gcOutput, + CompilationGCOutput& gcOutputForDelazification); + MOZ_MUST_USE bool instantiateStencilsAfterPreparation( + JSContext* cx, CompilationGCOutput& gcOutput, + CompilationGCOutput& gcOutputForDelazification); + + MOZ_MUST_USE bool deserializeStencils(JSContext* cx, + const JS::TranscodeRange& range, + bool* succeededOut); +}; + +} // namespace frontend +} // namespace js + +#endif // frontend_CompilationInfo_h |