зеркало из https://github.com/mozilla/gecko-dev.git
Backed out 8 changesets (bug 1687095, bug 1696205) for causing Spidermonkey failures. CLOSED TREE
Backed out changeset 9ea9e1c55a78 (bug 1696205) Backed out changeset 9419ba69b445 (bug 1687095) Backed out changeset d7815415080c (bug 1687095) Backed out changeset 075c72b787a2 (bug 1687095) Backed out changeset 4f27f5ca8656 (bug 1687095) Backed out changeset 1f89cffbd3d5 (bug 1687095) Backed out changeset 34a37bdb73ac (bug 1687095) Backed out changeset aef34d5f65e6 (bug 1687095)
This commit is contained in:
Родитель
06e88e30db
Коммит
7b7716c928
|
@ -5190,8 +5190,10 @@ static bool EvalStencilXDR(JSContext* cx, uint32_t argc, Value* vp) {
|
|||
|
||||
/* Instantiate the stencil. */
|
||||
Rooted<frontend::CompilationGCOutput> output(cx);
|
||||
Rooted<frontend::CompilationGCOutput> outputForDelazification(cx);
|
||||
if (!frontend::CompilationStencil::instantiateStencils(
|
||||
cx, input.get(), stencil, output.get())) {
|
||||
cx, input.get(), stencil, output.get(),
|
||||
outputForDelazification.address())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -71,14 +71,15 @@ CompileGlobalScriptToExtensibleStencil(
|
|||
// Part of InstantiateStencils can be done by calling PrepareForInstantiate.
|
||||
// PrepareForInstantiate is GC-free operation that can be performed
|
||||
// off-main-thread without parse global.
|
||||
[[nodiscard]] extern bool PrepareForInstantiate(
|
||||
extern bool PrepareForInstantiate(
|
||||
JSContext* cx, CompilationInput& input, const CompilationStencil& stencil,
|
||||
CompilationGCOutput& gcOutput);
|
||||
CompilationGCOutput& gcOutput,
|
||||
CompilationGCOutput* gcOutputForDelazification = nullptr);
|
||||
|
||||
[[nodiscard]] extern bool InstantiateStencils(JSContext* cx,
|
||||
CompilationInput& input,
|
||||
const CompilationStencil& stencil,
|
||||
CompilationGCOutput& gcOutput);
|
||||
extern bool InstantiateStencils(
|
||||
JSContext* cx, CompilationInput& input, const CompilationStencil& stencil,
|
||||
CompilationGCOutput& gcOutput,
|
||||
CompilationGCOutput* gcOutputForDelazification = nullptr);
|
||||
|
||||
extern JSScript* CompileGlobalScript(JSContext* cx,
|
||||
const JS::ReadOnlyCompileOptions& options,
|
||||
|
|
|
@ -242,7 +242,7 @@ template <typename Unit>
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!stencil->steal(cx, std::move(*extensibleStencil))) {
|
||||
if (!extensibleStencil->finish(cx, *stencil)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -303,7 +303,7 @@ template <typename Unit>
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!stencil->steal(cx, std::move(compiler.stencil()))) {
|
||||
if (!compiler.stencil().finish(cx, *stencil)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -376,15 +376,16 @@ frontend::CompileGlobalScriptToExtensibleStencil(
|
|||
scopeKind);
|
||||
}
|
||||
|
||||
bool frontend::InstantiateStencils(JSContext* cx, CompilationInput& input,
|
||||
const CompilationStencil& stencil,
|
||||
CompilationGCOutput& gcOutput) {
|
||||
bool frontend::InstantiateStencils(
|
||||
JSContext* cx, CompilationInput& input, const CompilationStencil& stencil,
|
||||
CompilationGCOutput& gcOutput,
|
||||
CompilationGCOutput* gcOutputForDelazification /* = nullptr */) {
|
||||
{
|
||||
AutoGeckoProfilerEntry pseudoFrame(cx, "stencil instantiate",
|
||||
JS::ProfilingCategoryPair::JS_Parsing);
|
||||
|
||||
if (!CompilationStencil::instantiateStencils(cx, input, stencil,
|
||||
gcOutput)) {
|
||||
if (!CompilationStencil::instantiateStencils(cx, input, stencil, gcOutput,
|
||||
gcOutputForDelazification)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -403,15 +404,15 @@ bool frontend::InstantiateStencils(JSContext* cx, CompilationInput& input,
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool frontend::PrepareForInstantiate(JSContext* cx, CompilationInput& input,
|
||||
const CompilationStencil& stencil,
|
||||
CompilationGCOutput& gcOutput) {
|
||||
bool frontend::PrepareForInstantiate(
|
||||
JSContext* cx, CompilationInput& input, const CompilationStencil& stencil,
|
||||
CompilationGCOutput& gcOutput,
|
||||
CompilationGCOutput* gcOutputForDelazification) {
|
||||
AutoGeckoProfilerEntry pseudoFrame(cx, "stencil instantiate",
|
||||
JS::ProfilingCategoryPair::JS_Parsing);
|
||||
|
||||
return CompilationStencil::prepareForInstantiate(cx, input, stencil,
|
||||
gcOutput);
|
||||
return CompilationStencil::prepareForInstantiate(cx, input, stencil, gcOutput,
|
||||
gcOutputForDelazification);
|
||||
}
|
||||
|
||||
template <typename Unit>
|
||||
|
@ -913,7 +914,7 @@ template <typename Unit>
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!stencil->steal(cx, std::move(compiler.stencil()))) {
|
||||
if (!compiler.stencil().finish(cx, *stencil)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1088,26 +1089,23 @@ static bool CompileLazyFunctionImpl(JSContext* cx, CompilationInput& input,
|
|||
static_cast<uint32_t>(input.lazy->immutableFlags());
|
||||
|
||||
Rooted<CompilationGCOutput> gcOutput(cx);
|
||||
{
|
||||
BorrowingCompilationStencil borrowingStencil(compilationState);
|
||||
if (!CompilationStencil::instantiateStencils(cx, input, borrowingStencil,
|
||||
gcOutput.get())) {
|
||||
BorrowingCompilationStencil borrowingStencil(compilationState);
|
||||
if (!CompilationStencil::instantiateStencils(cx, input, borrowingStencil,
|
||||
gcOutput.get())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(lazyFlags == gcOutput.get().script->immutableFlags());
|
||||
MOZ_ASSERT(gcOutput.get().script->outermostScope()->hasOnChain(
|
||||
ScopeKind::NonSyntactic) ==
|
||||
gcOutput.get().script->immutableFlags().hasFlag(
|
||||
JSScript::ImmutableFlags::HasNonSyntacticScope));
|
||||
|
||||
if (input.source->hasEncoder()) {
|
||||
MOZ_ASSERT(!js::UseOffThreadParseGlobal());
|
||||
if (!input.source->xdrEncodeFunctionStencil(cx, borrowingStencil)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(lazyFlags == gcOutput.get().script->immutableFlags());
|
||||
MOZ_ASSERT(gcOutput.get().script->outermostScope()->hasOnChain(
|
||||
ScopeKind::NonSyntactic) ==
|
||||
gcOutput.get().script->immutableFlags().hasFlag(
|
||||
JSScript::ImmutableFlags::HasNonSyntacticScope));
|
||||
|
||||
if (input.source->hasEncoder()) {
|
||||
MOZ_ASSERT(!js::UseOffThreadParseGlobal());
|
||||
if (!input.source->addDelazificationToIncrementalEncoding(
|
||||
cx, borrowingStencil)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assertException.reset();
|
||||
|
|
|
@ -9,10 +9,10 @@
|
|||
#include "mozilla/Assertions.h" // MOZ_ASSERT
|
||||
#include "mozilla/ReverseIterator.h" // mozilla::Reversed
|
||||
|
||||
#include "frontend/AbstractScopePtr.h" // ScopeIndex
|
||||
#include "frontend/CompilationStencil.h" // CompilationStencil
|
||||
#include "frontend/SharedContext.h" // FunctionBox
|
||||
#include "vm/BytecodeUtil.h" // INDEX_LIMIT, StackUses, StackDefs
|
||||
#include "frontend/AbstractScopePtr.h" // ScopeIndex
|
||||
#include "frontend/CompilationStencil.h"
|
||||
#include "frontend/SharedContext.h" // FunctionBox
|
||||
#include "vm/BytecodeUtil.h" // INDEX_LIMIT, StackUses, StackDefs
|
||||
#include "vm/GlobalObject.h"
|
||||
#include "vm/JSContext.h" // JSContext
|
||||
#include "vm/RegExpObject.h" // RegexpObject
|
||||
|
@ -51,7 +51,7 @@ mozilla::Maybe<ScopeIndex> GCThingList::getScopeIndex(size_t index) const {
|
|||
|
||||
bool js::frontend::EmitScriptThingsVector(
|
||||
JSContext* cx, const CompilationInput& input,
|
||||
const CompilationStencil& stencil, CompilationGCOutput& gcOutput,
|
||||
const BaseCompilationStencil& stencil, CompilationGCOutput& gcOutput,
|
||||
mozilla::Span<const TaggedScriptThingIndex> things,
|
||||
mozilla::Span<JS::GCCellPtr> output) {
|
||||
MOZ_ASSERT(things.size() <= INDEX_LIMIT);
|
||||
|
|
|
@ -130,7 +130,7 @@ struct MOZ_STACK_CLASS GCThingList {
|
|||
|
||||
[[nodiscard]] bool EmitScriptThingsVector(
|
||||
JSContext* cx, const CompilationInput& input,
|
||||
const CompilationStencil& stencil, CompilationGCOutput& gcOutput,
|
||||
const BaseCompilationStencil& stencil, CompilationGCOutput& gcOutput,
|
||||
mozilla::Span<const TaggedScriptThingIndex> things,
|
||||
mozilla::Span<JS::GCCellPtr> output);
|
||||
|
||||
|
|
|
@ -51,6 +51,7 @@ namespace frontend {
|
|||
struct CompilationInput;
|
||||
struct CompilationStencil;
|
||||
struct CompilationGCOutput;
|
||||
struct StencilDelazificationSet;
|
||||
class ScriptStencilIterable;
|
||||
|
||||
// ScopeContext hold information derivied from the scope and environment chains
|
||||
|
@ -165,7 +166,7 @@ struct CompilationAtomCache {
|
|||
using AtomCacheVector = JS::GCVector<JSAtom*, 0, js::SystemAllocPolicy>;
|
||||
|
||||
private:
|
||||
// Atoms lowered into or converted from CompilationStencil.parserAtomData.
|
||||
// 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,
|
||||
|
@ -215,7 +216,7 @@ struct CompilationInput {
|
|||
// * If the target is Global, null.
|
||||
// * If the target is SelfHosting, an empty global scope.
|
||||
// This scope is also used for EmptyGlobalScopeType in
|
||||
// CompilationStencil.gcThings.
|
||||
// BaseCompilationStencil.gcThings.
|
||||
// See the comment in initForSelfHostingGlobal.
|
||||
// * If the target is StandaloneFunction, an empty global scope.
|
||||
// * If the target is StandaloneFunctionInNonSyntacticScope, the non-null
|
||||
|
@ -246,7 +247,7 @@ struct CompilationInput {
|
|||
}
|
||||
|
||||
// This enclosing scope is also recorded as EmptyGlobalScopeType in
|
||||
// CompilationStencil.gcThings even though corresponding ScopeStencil
|
||||
// BaseCompilationStencil.gcThings even though corresponding ScopeStencil
|
||||
// isn't generated.
|
||||
//
|
||||
// Store the enclosing scope here in order to access it from
|
||||
|
@ -370,7 +371,7 @@ struct SharedDataContainer {
|
|||
uintptr_t data_ = 0;
|
||||
|
||||
public:
|
||||
// Defaults to SingleSharedData.
|
||||
// Defaults to SingleSharedData for delazification vector.
|
||||
SharedDataContainer() = default;
|
||||
|
||||
SharedDataContainer(const SharedDataContainer&) = delete;
|
||||
|
@ -388,13 +389,9 @@ struct SharedDataContainer {
|
|||
|
||||
~SharedDataContainer();
|
||||
|
||||
[[nodiscard]] bool initVector(JSContext* cx);
|
||||
[[nodiscard]] bool initMap(JSContext* cx);
|
||||
bool initVector(JSContext* cx);
|
||||
bool initMap(JSContext* cx);
|
||||
|
||||
private:
|
||||
[[nodiscard]] bool convertFromSingleToMap(JSContext* cx);
|
||||
|
||||
public:
|
||||
bool isEmpty() const { return (data_) == SingleTag; }
|
||||
bool isSingle() const { return (data_ & TagMask) == SingleTag; }
|
||||
bool isVector() const { return (data_ & TagMask) == VectorTag; }
|
||||
|
@ -433,22 +430,15 @@ struct SharedDataContainer {
|
|||
return reinterpret_cast<SharedDataContainer*>(data_ & ~TagMask);
|
||||
}
|
||||
|
||||
[[nodiscard]] bool prepareStorageFor(JSContext* cx, size_t nonLazyScriptCount,
|
||||
size_t allScriptCount);
|
||||
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) const;
|
||||
|
||||
// Add data for index-th script and share it with VM.
|
||||
[[nodiscard]] bool addAndShare(JSContext* cx, ScriptIndex index,
|
||||
js::SharedImmutableScriptData* data);
|
||||
|
||||
// Add data for index-th script without sharing it with VM.
|
||||
// The data should already be shared with VM.
|
||||
//
|
||||
// The data is supposed to be added from delazification.
|
||||
[[nodiscard]] bool addExtraWithoutShare(JSContext* cx, ScriptIndex index,
|
||||
js::SharedImmutableScriptData* data);
|
||||
bool addAndShare(JSContext* cx, ScriptIndex index,
|
||||
js::SharedImmutableScriptData* data);
|
||||
|
||||
// Dynamic memory associated with this container. Does not include the
|
||||
// SharedImmutableScriptData since we are not the unique owner of it.
|
||||
|
@ -470,28 +460,8 @@ struct SharedDataContainer {
|
|||
#endif
|
||||
};
|
||||
|
||||
struct ExtensibleCompilationStencil;
|
||||
|
||||
// The top level struct of stencil specialized for non-extensible case.
|
||||
// Used as the compilation output, and also XDR decode output.
|
||||
//
|
||||
// In XDR decode output case, the span and not-owning pointer fields point
|
||||
// the internal LifoAlloc and the external XDR buffer.
|
||||
//
|
||||
// In BorrowingCompilationStencil usage, span and not-owning pointer fields
|
||||
// point the ExtensibleCompilationStencil and its LifoAlloc.
|
||||
//
|
||||
// The dependent XDR buffer or ExtensibleCompilationStencil must be kept
|
||||
// alive manually.
|
||||
struct CompilationStencil {
|
||||
static constexpr ScriptIndex TopLevelIndex = ScriptIndex(0);
|
||||
|
||||
static constexpr size_t LifoAllocChunkSize = 512;
|
||||
|
||||
// Set to true if any pointer/span contains external data instead of
|
||||
// LifoAlloc or owned memory.
|
||||
bool hasExternalDependency = false;
|
||||
|
||||
// The top level struct of stencil.
|
||||
struct BaseCompilationStencil {
|
||||
// FunctionKey is an encoded position of a function within the source text
|
||||
// that is reproducible.
|
||||
using FunctionKey = uint32_t;
|
||||
|
@ -501,11 +471,6 @@ struct CompilationStencil {
|
|||
// reserved for the top-level script. This top-level may or may not be a
|
||||
// function.
|
||||
mozilla::Span<ScriptStencil> scriptData;
|
||||
|
||||
// Immutable data computed during initial compilation and never updated during
|
||||
// delazification.
|
||||
mozilla::Span<ScriptStencilExtra> scriptExtra;
|
||||
|
||||
mozilla::Span<TaggedScriptThingIndex> gcThingData;
|
||||
|
||||
// scopeData and scopeNames have the same size, and i-th scopeNames contains
|
||||
|
@ -532,6 +497,59 @@ struct CompilationStencil {
|
|||
// function in the source text.
|
||||
FunctionKey functionKey = NullFunctionKey;
|
||||
|
||||
// End of fields.
|
||||
|
||||
BaseCompilationStencil() = default;
|
||||
|
||||
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; }
|
||||
|
||||
inline CompilationStencil& asCompilationStencil();
|
||||
inline const CompilationStencil& asCompilationStencil() const;
|
||||
|
||||
// Size of dynamic allocations. Note that data in Spans are not owned by us
|
||||
// and instead accounted for in by their backing storage (eg LifoAlloc or XDR
|
||||
// buffer).
|
||||
size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
|
||||
return sharedData.sizeOfExcludingThis(mallocSizeOf);
|
||||
}
|
||||
|
||||
#if defined(DEBUG) || defined(JS_JITSPEW)
|
||||
void dump() const;
|
||||
void dump(js::JSONPrinter& json) const;
|
||||
void dumpFields(js::JSONPrinter& json) const;
|
||||
|
||||
void dumpAtom(TaggedParserAtomIndex index) const;
|
||||
#endif
|
||||
};
|
||||
|
||||
// The top level struct of stencil specialized for non-extensible case.
|
||||
// Used as the compilation output, and also XDR decode output.
|
||||
//
|
||||
// In XDR decode output case, the span and not-owning pointer fields point
|
||||
// the internal LifoAlloc and the external XDR buffer.
|
||||
//
|
||||
// In BorrowingCompilationStencil usage, span and not-owning pointer fields
|
||||
// point the ExtensibleCompilationStencil and its LifoAlloc.
|
||||
//
|
||||
// The dependent XDR buffer or ExtensibleCompilationStencil must be kept
|
||||
// alive manually.
|
||||
struct CompilationStencil : public BaseCompilationStencil {
|
||||
static constexpr ScriptIndex TopLevelIndex = ScriptIndex(0);
|
||||
|
||||
static constexpr size_t LifoAllocChunkSize = 512;
|
||||
|
||||
// Set to true if any pointer/span contains external data instead of
|
||||
// LifoAlloc or owned memory.
|
||||
bool hasExternalDependency = false;
|
||||
|
||||
// The lifetime of this CompilationStencil may be managed by stack allocation,
|
||||
// UniquePtr<T>, or RefPtr<T>. If a RefPtr is used, this ref-count will track
|
||||
// the lifetime, otherwise it is ignored.
|
||||
|
@ -554,37 +572,37 @@ struct CompilationStencil {
|
|||
// Module metadata if this is a module compile.
|
||||
RefPtr<StencilModuleMetadata> moduleMetadata;
|
||||
|
||||
// Immutable data computed during initial compilation and never updated during
|
||||
// delazification.
|
||||
mozilla::Span<ScriptStencilExtra> scriptExtra;
|
||||
|
||||
// AsmJS modules generated by parsing. These scripts are never lazy and
|
||||
// therefore only generated during initial parse.
|
||||
RefPtr<StencilAsmJSContainer> asmJS;
|
||||
|
||||
// A series of delazifications may also be associated with this stencil. They
|
||||
// contain bytecode, scopes, etc generated by delazification.
|
||||
UniquePtr<StencilDelazificationSet> delazificationSet;
|
||||
|
||||
// End of fields.
|
||||
|
||||
// Construct a CompilationStencil
|
||||
explicit CompilationStencil(ScriptSource* source)
|
||||
: alloc(LifoAllocChunkSize), source(source) {}
|
||||
|
||||
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; }
|
||||
|
||||
[[nodiscard]] static bool instantiateStencilAfterPreparation(
|
||||
JSContext* cx, CompilationInput& input, const CompilationStencil& stencil,
|
||||
CompilationGCOutput& gcOutput);
|
||||
[[nodiscard]] static bool instantiateBaseStencilAfterPreparation(
|
||||
JSContext* cx, CompilationInput& input,
|
||||
const BaseCompilationStencil& stencil, CompilationGCOutput& gcOutput);
|
||||
|
||||
[[nodiscard]] static bool prepareForInstantiate(
|
||||
JSContext* cx, CompilationInput& input, const CompilationStencil& stencil,
|
||||
CompilationGCOutput& gcOutput);
|
||||
CompilationGCOutput& gcOutput,
|
||||
CompilationGCOutput* gcOutputForDelazification = nullptr);
|
||||
|
||||
[[nodiscard]] static bool instantiateStencils(
|
||||
JSContext* cx, CompilationInput& input, const CompilationStencil& stencil,
|
||||
CompilationGCOutput& gcOutput);
|
||||
CompilationGCOutput& gcOutput,
|
||||
CompilationGCOutput* gcOutputForDelazification = nullptr);
|
||||
|
||||
[[nodiscard]] bool serializeStencils(JSContext* cx, CompilationInput& input,
|
||||
JS::TranscodeBuffer& buf,
|
||||
|
@ -600,7 +618,7 @@ struct CompilationStencil {
|
|||
CompilationStencil& operator=(CompilationStencil&&) = delete;
|
||||
|
||||
static inline ScriptStencilIterable functionScriptStencils(
|
||||
const CompilationStencil& stencil, CompilationGCOutput& gcOutput);
|
||||
const BaseCompilationStencil& stencil, CompilationGCOutput& gcOutput);
|
||||
|
||||
void setFunctionKey(BaseScript* lazy) {
|
||||
functionKey = toFunctionKey(lazy->extent());
|
||||
|
@ -611,9 +629,6 @@ struct CompilationStencil {
|
|||
return mallocSizeOf(this) + sizeOfExcludingThis(mallocSizeOf);
|
||||
}
|
||||
|
||||
// Steal ExtensibleCompilationStencil content.
|
||||
[[nodiscard]] bool steal(JSContext* cx, ExtensibleCompilationStencil&& other);
|
||||
|
||||
#ifdef DEBUG
|
||||
void assertNoExternalDependency() const;
|
||||
#endif
|
||||
|
@ -622,22 +637,33 @@ struct CompilationStencil {
|
|||
void dump() const;
|
||||
void dump(js::JSONPrinter& json) const;
|
||||
void dumpFields(js::JSONPrinter& json) const;
|
||||
|
||||
void dumpAtom(TaggedParserAtomIndex index) const;
|
||||
#endif
|
||||
};
|
||||
|
||||
// The top level struct of stencil specialized for extensible case.
|
||||
// Used as the temporary storage during compilation, an the compilation output.
|
||||
inline CompilationStencil& BaseCompilationStencil::asCompilationStencil() {
|
||||
MOZ_ASSERT(isInitialStencil(),
|
||||
"cast from BaseCompilationStencil to CompilationStencil is "
|
||||
"allowed only for initial stencil");
|
||||
return *static_cast<CompilationStencil*>(this);
|
||||
}
|
||||
|
||||
inline const CompilationStencil& BaseCompilationStencil::asCompilationStencil()
|
||||
const {
|
||||
MOZ_ASSERT(isInitialStencil(),
|
||||
"cast from BaseCompilationStencil to CompilationStencil is "
|
||||
"allowed only for initial stencil");
|
||||
return *static_cast<const CompilationStencil*>(this);
|
||||
}
|
||||
|
||||
// Temporary space to accumulate stencil data.
|
||||
// Copied to BaseCompilationStencil/CompilationStencil by `finish` method.
|
||||
//
|
||||
// All not-owning pointer fields point the internal LifoAlloc.
|
||||
//
|
||||
// See CompilationStencil for each field's description.
|
||||
// See BaseCompilationStencil/CompilationStencil for each field's description.
|
||||
struct ExtensibleCompilationStencil {
|
||||
using FunctionKey = CompilationStencil::FunctionKey;
|
||||
using FunctionKey = BaseCompilationStencil::FunctionKey;
|
||||
|
||||
// Data pointed by other fields are allocated in this LifoAlloc,
|
||||
// and moved to `CompilationStencil.alloc`.
|
||||
// and moved to `BaseCompilationStencil.alloc`.
|
||||
LifoAlloc alloc;
|
||||
|
||||
RefPtr<ScriptSource> source;
|
||||
|
@ -668,7 +694,7 @@ struct ExtensibleCompilationStencil {
|
|||
// Table of parser atoms for this compilation.
|
||||
ParserAtomsTable parserAtoms;
|
||||
|
||||
FunctionKey functionKey = CompilationStencil::NullFunctionKey;
|
||||
FunctionKey functionKey = BaseCompilationStencil::NullFunctionKey;
|
||||
|
||||
ExtensibleCompilationStencil(JSContext* cx, CompilationInput& input);
|
||||
|
||||
|
@ -718,15 +744,14 @@ struct ExtensibleCompilationStencil {
|
|||
}
|
||||
|
||||
void setFunctionKey(BaseScript* lazy) {
|
||||
functionKey = CompilationStencil::toFunctionKey(lazy->extent());
|
||||
functionKey = BaseCompilationStencil::toFunctionKey(lazy->extent());
|
||||
}
|
||||
|
||||
bool isInitialStencil() const {
|
||||
return functionKey == CompilationStencil::NullFunctionKey;
|
||||
return functionKey == BaseCompilationStencil::NullFunctionKey;
|
||||
}
|
||||
|
||||
// Steal CompilationStencil content.
|
||||
[[nodiscard]] bool steal(JSContext* cx, CompilationStencil&& other);
|
||||
[[nodiscard]] bool finish(JSContext* cx, CompilationStencil& stencil);
|
||||
|
||||
inline size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
|
||||
size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
|
||||
|
@ -800,6 +825,32 @@ class MOZ_STACK_CLASS BorrowingCompilationStencil : public CompilationStencil {
|
|||
ExtensibleCompilationStencil& extensibleStencil);
|
||||
};
|
||||
|
||||
// A set of stencils generated by delazifying functions. This should only be
|
||||
// used by a CompilationStencil that owns this. This is primarily used for
|
||||
// bytecode caching with XDR.
|
||||
struct StencilDelazificationSet {
|
||||
Vector<BaseCompilationStencil, 0, js::SystemAllocPolicy> delazifications;
|
||||
Vector<ScriptIndex, 0, js::SystemAllocPolicy> delazificationIndices;
|
||||
|
||||
size_t maxScriptDataLength = 0;
|
||||
size_t maxScopeDataLength = 0;
|
||||
size_t maxParserAtomDataLength = 0;
|
||||
|
||||
bool hasDelazificationIndices() {
|
||||
MOZ_ASSERT(!delazifications.empty());
|
||||
return !delazificationIndices.empty();
|
||||
}
|
||||
|
||||
[[nodiscard]] bool buildDelazificationIndices(
|
||||
JSContext* cx, const CompilationStencil& stencil);
|
||||
|
||||
size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
|
||||
return mallocSizeOf(this) +
|
||||
delazifications.sizeOfExcludingThis(mallocSizeOf) +
|
||||
delazificationIndices.sizeOfExcludingThis(mallocSizeOf);
|
||||
}
|
||||
};
|
||||
|
||||
// Size of dynamic data. Ignores Spans (unless their contents are in the
|
||||
// LifoAlloc) and RefPtrs since we are not the unique owner.
|
||||
inline size_t CompilationStencil::sizeOfExcludingThis(
|
||||
|
@ -807,9 +858,13 @@ inline size_t CompilationStencil::sizeOfExcludingThis(
|
|||
size_t moduleMetadataSize =
|
||||
moduleMetadata ? moduleMetadata->sizeOfIncludingThis(mallocSizeOf) : 0;
|
||||
size_t asmJSSize = asmJS ? asmJS->sizeOfIncludingThis(mallocSizeOf) : 0;
|
||||
size_t delazificationSetSize =
|
||||
delazificationSet ? delazificationSet->sizeOfIncludingThis(mallocSizeOf)
|
||||
: 0;
|
||||
|
||||
return alloc.sizeOfExcludingThis(mallocSizeOf) + moduleMetadataSize +
|
||||
asmJSSize + sharedData.sizeOfExcludingThis(mallocSizeOf);
|
||||
asmJSSize + delazificationSetSize +
|
||||
BaseCompilationStencil::sizeOfExcludingThis(mallocSizeOf);
|
||||
}
|
||||
|
||||
inline size_t ExtensibleCompilationStencil::sizeOfExcludingThis(
|
||||
|
@ -904,17 +959,17 @@ class ScriptStencilIterable {
|
|||
|
||||
class Iterator {
|
||||
size_t index_ = 0;
|
||||
const CompilationStencil& stencil_;
|
||||
const BaseCompilationStencil& stencil_;
|
||||
CompilationGCOutput& gcOutput_;
|
||||
|
||||
Iterator(const CompilationStencil& stencil, CompilationGCOutput& gcOutput,
|
||||
size_t index)
|
||||
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 CompilationStencil& stencil,
|
||||
explicit Iterator(const BaseCompilationStencil& stencil,
|
||||
CompilationGCOutput& gcOutput)
|
||||
: stencil_(stencil), gcOutput_(gcOutput) {
|
||||
skipTopLevelNonFunction();
|
||||
|
@ -956,22 +1011,22 @@ class ScriptStencilIterable {
|
|||
const ScriptStencil& script = stencil_.scriptData[index];
|
||||
const ScriptStencilExtra* scriptExtra = nullptr;
|
||||
if (stencil_.isInitialStencil()) {
|
||||
scriptExtra = &stencil_.scriptExtra[index];
|
||||
scriptExtra = &stencil_.asCompilationStencil().scriptExtra[index];
|
||||
}
|
||||
return ScriptAndFunction(script, scriptExtra, gcOutput_.functions[index],
|
||||
index);
|
||||
}
|
||||
|
||||
static Iterator end(const CompilationStencil& stencil,
|
||||
static Iterator end(const BaseCompilationStencil& stencil,
|
||||
CompilationGCOutput& gcOutput) {
|
||||
return Iterator(stencil, gcOutput, stencil.scriptData.size());
|
||||
}
|
||||
};
|
||||
|
||||
const CompilationStencil& stencil_;
|
||||
const BaseCompilationStencil& stencil_;
|
||||
CompilationGCOutput& gcOutput_;
|
||||
|
||||
explicit ScriptStencilIterable(const CompilationStencil& stencil,
|
||||
explicit ScriptStencilIterable(const BaseCompilationStencil& stencil,
|
||||
CompilationGCOutput& gcOutput)
|
||||
: stencil_(stencil), gcOutput_(gcOutput) {}
|
||||
|
||||
|
@ -981,56 +1036,10 @@ class ScriptStencilIterable {
|
|||
};
|
||||
|
||||
inline ScriptStencilIterable CompilationStencil::functionScriptStencils(
|
||||
const CompilationStencil& stencil, CompilationGCOutput& gcOutput) {
|
||||
const BaseCompilationStencil& stencil, CompilationGCOutput& gcOutput) {
|
||||
return ScriptStencilIterable(stencil, gcOutput);
|
||||
}
|
||||
|
||||
// Merge CompilationStencil for delazification into initial
|
||||
// ExtensibleCompilationStencil.
|
||||
struct CompilationStencilMerger {
|
||||
private:
|
||||
using FunctionKey = ExtensibleCompilationStencil::FunctionKey;
|
||||
|
||||
// The stencil for the initial compilation.
|
||||
// Delazifications are merged into this.
|
||||
//
|
||||
// If any failure happens during merge operation, this field is reset to
|
||||
// nullptr.
|
||||
UniquePtr<ExtensibleCompilationStencil> initial_;
|
||||
|
||||
// A Map from function key to the ScriptIndex in the initial stencil.
|
||||
using FunctionKeyToScriptIndexMap =
|
||||
HashMap<FunctionKey, ScriptIndex, mozilla::DefaultHasher<FunctionKey>,
|
||||
js::SystemAllocPolicy>;
|
||||
FunctionKeyToScriptIndexMap functionKeyToInitialScriptIndex_;
|
||||
|
||||
[[nodiscard]] bool buildFunctionKeyToIndex(JSContext* cx);
|
||||
|
||||
ScriptIndex getInitialScriptIndexFor(
|
||||
const CompilationStencil& delazification) const;
|
||||
|
||||
// A map from delazification's ParserAtomIndex to
|
||||
// initial's TaggedParserAtomIndex
|
||||
using AtomIndexMap = Vector<TaggedParserAtomIndex, 0, js::SystemAllocPolicy>;
|
||||
|
||||
[[nodiscard]] bool buildAtomIndexMap(JSContext* cx,
|
||||
const CompilationStencil& delazification,
|
||||
AtomIndexMap& atomIndexMap);
|
||||
|
||||
public:
|
||||
CompilationStencilMerger() = default;
|
||||
|
||||
// Set the initial stencil and prepare for merging.
|
||||
[[nodiscard]] bool setInitial(
|
||||
JSContext* cx, UniquePtr<ExtensibleCompilationStencil>&& initial);
|
||||
|
||||
// Merge the delazification stencil into the initial stencil.
|
||||
[[nodiscard]] bool addDelazification(
|
||||
JSContext* cx, const CompilationStencil& delazification);
|
||||
|
||||
ExtensibleCompilationStencil& getResult() const { return *initial_; }
|
||||
};
|
||||
|
||||
} // namespace frontend
|
||||
} // namespace js
|
||||
|
||||
|
|
|
@ -11,9 +11,9 @@
|
|||
|
||||
#include "NamespaceImports.h" // ValueVector
|
||||
|
||||
#include "builtin/Array.h" // NewDenseCopiedArray
|
||||
#include "frontend/CompilationStencil.h" // frontend::{CompilationStencil, CompilationAtomCache}
|
||||
#include "frontend/ParserAtom.h" // frontend::ParserAtomTable
|
||||
#include "builtin/Array.h" // NewDenseCopiedArray
|
||||
#include "frontend/CompilationStencil.h" // frontend::CompilationAtomCache
|
||||
#include "frontend/ParserAtom.h" // frontend::ParserAtomTable
|
||||
#include "frontend/TaggedParserAtomIndexHasher.h" // TaggedParserAtomIndexHasher
|
||||
#include "gc/AllocKind.h" // gc::AllocKind
|
||||
#include "gc/Rooting.h" // RootedPlainObject
|
||||
|
@ -259,7 +259,7 @@ static void DumpObjLiteralFlagsItems(js::JSONPrinter& json,
|
|||
}
|
||||
|
||||
static void DumpObjLiteral(js::JSONPrinter& json,
|
||||
const frontend::CompilationStencil* stencil,
|
||||
const frontend::BaseCompilationStencil* stencil,
|
||||
mozilla::Span<const uint8_t> code,
|
||||
const ObjLiteralFlags& flags,
|
||||
uint32_t propertyCount) {
|
||||
|
@ -328,15 +328,17 @@ void ObjLiteralWriter::dump() const {
|
|||
dump(json, nullptr);
|
||||
}
|
||||
|
||||
void ObjLiteralWriter::dump(js::JSONPrinter& json,
|
||||
const frontend::CompilationStencil* stencil) const {
|
||||
void ObjLiteralWriter::dump(
|
||||
js::JSONPrinter& json,
|
||||
const frontend::BaseCompilationStencil* stencil) const {
|
||||
json.beginObject();
|
||||
dumpFields(json, stencil);
|
||||
json.endObject();
|
||||
}
|
||||
|
||||
void ObjLiteralWriter::dumpFields(
|
||||
js::JSONPrinter& json, const frontend::CompilationStencil* stencil) const {
|
||||
js::JSONPrinter& json,
|
||||
const frontend::BaseCompilationStencil* stencil) const {
|
||||
DumpObjLiteral(json, stencil, getCode(), flags_, propertyCount_);
|
||||
}
|
||||
|
||||
|
@ -347,14 +349,16 @@ void ObjLiteralStencil::dump() const {
|
|||
}
|
||||
|
||||
void ObjLiteralStencil::dump(
|
||||
js::JSONPrinter& json, const frontend::CompilationStencil* stencil) const {
|
||||
js::JSONPrinter& json,
|
||||
const frontend::BaseCompilationStencil* stencil) const {
|
||||
json.beginObject();
|
||||
dumpFields(json, stencil);
|
||||
json.endObject();
|
||||
}
|
||||
|
||||
void ObjLiteralStencil::dumpFields(
|
||||
js::JSONPrinter& json, const frontend::CompilationStencil* stencil) const {
|
||||
js::JSONPrinter& json,
|
||||
const frontend::BaseCompilationStencil* stencil) const {
|
||||
DumpObjLiteral(json, stencil, code_, flags_, propertyCount_);
|
||||
}
|
||||
|
||||
|
|
|
@ -111,7 +111,7 @@ class JSONPrinter;
|
|||
|
||||
namespace frontend {
|
||||
struct CompilationAtomCache;
|
||||
struct CompilationStencil;
|
||||
struct BaseCompilationStencil;
|
||||
class StencilXDR;
|
||||
} // namespace frontend
|
||||
|
||||
|
@ -380,9 +380,9 @@ struct ObjLiteralWriter : private ObjLiteralWriterBase {
|
|||
#if defined(DEBUG) || defined(JS_JITSPEW)
|
||||
void dump() const;
|
||||
void dump(JSONPrinter& json,
|
||||
const frontend::CompilationStencil* stencil) const;
|
||||
const frontend::BaseCompilationStencil* stencil) const;
|
||||
void dumpFields(JSONPrinter& json,
|
||||
const frontend::CompilationStencil* stencil) const;
|
||||
const frontend::BaseCompilationStencil* stencil) const;
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
@ -476,8 +476,6 @@ struct ObjLiteralReaderBase {
|
|||
[[nodiscard]] bool readAtomArg(frontend::TaggedParserAtomIndex* atomIndex) {
|
||||
return readRawData(atomIndex->rawDataRef());
|
||||
}
|
||||
|
||||
size_t cursor() const { return cursor_; }
|
||||
};
|
||||
|
||||
// A single object-literal instruction, creating one property on an object.
|
||||
|
@ -591,71 +589,6 @@ struct ObjLiteralReader : private ObjLiteralReaderBase {
|
|||
}
|
||||
};
|
||||
|
||||
// A class to modify the code, while keeping the structure.
|
||||
struct ObjLiteralModifier : private ObjLiteralReaderBase {
|
||||
mozilla::Span<uint8_t> mutableData_;
|
||||
|
||||
public:
|
||||
explicit ObjLiteralModifier(mozilla::Span<uint8_t> data)
|
||||
: ObjLiteralReaderBase(data), mutableData_(data) {}
|
||||
|
||||
private:
|
||||
// Map `atom` with `map`, and write to `atomCursor` of `mutableData_`.
|
||||
template <typename MapT>
|
||||
void mapOneAtom(MapT map, frontend::TaggedParserAtomIndex atom,
|
||||
size_t atomCursor) {
|
||||
auto atomIndex = map(atom);
|
||||
mozilla::NativeEndian::copyAndSwapToLittleEndian(
|
||||
reinterpret_cast<void*>(mutableData_.data() + atomCursor),
|
||||
atomIndex.rawDataRef(), 1);
|
||||
}
|
||||
|
||||
// Map atoms in single instruction.
|
||||
// Return true if it successfully maps.
|
||||
// Return false if there's no more instruction.
|
||||
template <typename MapT>
|
||||
bool mapInsnAtom(MapT map) {
|
||||
ObjLiteralOpcode op;
|
||||
ObjLiteralKey key;
|
||||
|
||||
size_t opCursor = cursor();
|
||||
if (!readOpAndKey(&op, &key)) {
|
||||
return false;
|
||||
}
|
||||
if (key.isAtomIndex()) {
|
||||
static constexpr size_t OpLength = 1;
|
||||
size_t atomCursor = opCursor + OpLength;
|
||||
mapOneAtom(map, key.getAtomIndex(), atomCursor);
|
||||
}
|
||||
|
||||
if (ObjLiteralOpcodeHasValueArg(op)) {
|
||||
JS::Value value;
|
||||
if (!readValueArg(&value)) {
|
||||
return false;
|
||||
}
|
||||
} else if (ObjLiteralOpcodeHasAtomArg(op)) {
|
||||
size_t atomCursor = cursor();
|
||||
|
||||
frontend::TaggedParserAtomIndex atomIndex;
|
||||
if (!readAtomArg(&atomIndex)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mapOneAtom(map, atomIndex, atomCursor);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public:
|
||||
// Map TaggedParserAtomIndex inside the code in place, with given function.
|
||||
template <typename MapT>
|
||||
void mapAtom(MapT map) {
|
||||
while (mapInsnAtom(map)) {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class ObjLiteralStencil {
|
||||
friend class frontend::StencilXDR;
|
||||
|
||||
|
@ -675,10 +608,6 @@ class ObjLiteralStencil {
|
|||
JSObject* create(JSContext* cx,
|
||||
const frontend::CompilationAtomCache& atomCache) const;
|
||||
|
||||
mozilla::Span<const uint8_t> code() const { return code_; }
|
||||
ObjLiteralFlags flags() const { return flags_; }
|
||||
uint32_t propertyCount() const { return propertyCount_; }
|
||||
|
||||
#ifdef DEBUG
|
||||
bool isContainedIn(const LifoAlloc& alloc) const;
|
||||
#endif
|
||||
|
@ -686,9 +615,9 @@ class ObjLiteralStencil {
|
|||
#if defined(DEBUG) || defined(JS_JITSPEW)
|
||||
void dump() const;
|
||||
void dump(JSONPrinter& json,
|
||||
const frontend::CompilationStencil* stencil) const;
|
||||
const frontend::BaseCompilationStencil* stencil) const;
|
||||
void dumpFields(JSONPrinter& json,
|
||||
const frontend::CompilationStencil* stencil) const;
|
||||
const frontend::BaseCompilationStencil* stencil) const;
|
||||
|
||||
#endif
|
||||
};
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
|
||||
#include "jsnum.h"
|
||||
|
||||
#include "frontend/CompilationStencil.h" // ExtensibleCompilationStencil
|
||||
#include "frontend/FullParseHandler.h"
|
||||
#include "frontend/ParseContext.h"
|
||||
#include "frontend/Parser.h" // ParserBase
|
||||
|
|
|
@ -320,56 +320,6 @@ TaggedParserAtomIndex ParserAtomsTable::internLatin1(
|
|||
return internChar16Seq<Latin1Char>(cx, addPtr, lookup.hash(), seq, length);
|
||||
}
|
||||
|
||||
bool IsWide(const InflatedChar16Sequence<char16_t>& seq) {
|
||||
InflatedChar16Sequence<char16_t> seqCopy = seq;
|
||||
while (seqCopy.hasMore()) {
|
||||
char16_t ch = seqCopy.next();
|
||||
if (ch > MAX_LATIN1_CHAR) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename AtomCharT>
|
||||
TaggedParserAtomIndex ParserAtomsTable::internExternalParserAtomImpl(
|
||||
JSContext* cx, const ParserAtom* atom) {
|
||||
InflatedChar16Sequence<AtomCharT> seq(atom->chars<AtomCharT>(),
|
||||
atom->length());
|
||||
SpecificParserAtomLookup<AtomCharT> lookup(seq, atom->hash());
|
||||
|
||||
// Check for existing atom.
|
||||
auto addPtr = entryMap_.lookupForAdd(lookup);
|
||||
if (addPtr) {
|
||||
return addPtr->value();
|
||||
}
|
||||
|
||||
return internChar16Seq<AtomCharT>(cx, addPtr, atom->hash(), seq,
|
||||
atom->length());
|
||||
}
|
||||
|
||||
TaggedParserAtomIndex ParserAtomsTable::internExternalParserAtom(
|
||||
JSContext* cx, const ParserAtom* atom) {
|
||||
if (atom->hasLatin1Chars()) {
|
||||
return internExternalParserAtomImpl<JS::Latin1Char>(cx, atom);
|
||||
}
|
||||
return internExternalParserAtomImpl<char16_t>(cx, atom);
|
||||
}
|
||||
|
||||
bool ParserAtomsTable::addPlaceholder(JSContext* cx) {
|
||||
ParserAtomIndex index = ParserAtomIndex(entries_.length());
|
||||
if (size_t(index) >= TaggedParserAtomIndex::IndexLimit) {
|
||||
ReportAllocationOverflow(cx);
|
||||
return false;
|
||||
}
|
||||
if (!entries_.append(nullptr)) {
|
||||
js::ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
ParserAtomSpanBuilder::ParserAtomSpanBuilder(JSRuntime* rt,
|
||||
ParserAtomSpan& entries)
|
||||
: wellKnownTable_(*rt->commonParserNames), entries_(entries) {}
|
||||
|
@ -462,8 +412,20 @@ TaggedParserAtomIndex ParserAtomsTable::internChar16(JSContext* cx,
|
|||
return addPtr->value();
|
||||
}
|
||||
|
||||
// Compute the target encoding.
|
||||
// NOTE: Length in code-points will be same, even if we deflate to Latin1.
|
||||
bool wide = false;
|
||||
InflatedChar16Sequence<char16_t> seqCopy = seq;
|
||||
while (seqCopy.hasMore()) {
|
||||
char16_t ch = seqCopy.next();
|
||||
if (ch > MAX_LATIN1_CHAR) {
|
||||
wide = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, add new entry.
|
||||
return IsWide(seq)
|
||||
return wide
|
||||
? internChar16Seq<char16_t>(cx, addPtr, lookup.hash(), seq, length)
|
||||
: internChar16Seq<Latin1Char>(cx, addPtr, lookup.hash(), seq,
|
||||
length);
|
||||
|
|
|
@ -598,10 +598,6 @@ class ParserAtomsTable {
|
|||
InflatedChar16Sequence<SeqCharT> seq,
|
||||
uint32_t length);
|
||||
|
||||
template <typename AtomCharT>
|
||||
TaggedParserAtomIndex internExternalParserAtomImpl(JSContext* cx,
|
||||
const ParserAtom* atom);
|
||||
|
||||
public:
|
||||
TaggedParserAtomIndex internAscii(JSContext* cx, const char* asciiPtr,
|
||||
uint32_t length);
|
||||
|
@ -621,11 +617,6 @@ class ParserAtomsTable {
|
|||
CompilationAtomCache& atomCache,
|
||||
JSAtom* atom);
|
||||
|
||||
TaggedParserAtomIndex internExternalParserAtom(JSContext* cx,
|
||||
const ParserAtom* atom);
|
||||
|
||||
bool addPlaceholder(JSContext* cx);
|
||||
|
||||
private:
|
||||
const ParserAtom* getWellKnown(WellKnownAtomId atomId) const;
|
||||
ParserAtom* getParserAtom(ParserAtomIndex index) const;
|
||||
|
|
|
@ -351,7 +351,7 @@ class FunctionBox : public SuspendableContext {
|
|||
// Any update after the copy should be synced to the ScriptStencil.
|
||||
TaggedParserAtomIndex atom_;
|
||||
|
||||
// Index into CompilationStencil::scriptData.
|
||||
// Index into BaseCompilationStencil::scriptData.
|
||||
ScriptIndex funcDataIndex_ = ScriptIndex(-1);
|
||||
|
||||
// See: FunctionFlags
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -50,8 +50,8 @@ namespace frontend {
|
|||
|
||||
struct CompilationStencil;
|
||||
struct CompilationAtomCache;
|
||||
struct BaseCompilationStencil;
|
||||
struct CompilationGCOutput;
|
||||
struct CompilationStencilMerger;
|
||||
class RegExpStencil;
|
||||
class BigIntStencil;
|
||||
class StencilXDR;
|
||||
|
@ -118,11 +118,34 @@ using ParserBindingIter = AbstractBindingIter<TaggedParserAtomIndex>;
|
|||
// we then package up into the `CompilationStencil` type. This contains a series
|
||||
// of vectors segregated by stencil type for fast processing. Delazifying a
|
||||
// function will generate its bytecode but some fields remain unchanged from the
|
||||
// initial lazy parse.
|
||||
// initial lazy parse. We use a base class to capture fields that are meaningful
|
||||
// for both the initial lazy and delazification parse.
|
||||
//
|
||||
// struct BaseCompilationStencil {
|
||||
// FunctionKey functionKey;
|
||||
// Span<ScriptStencil> scriptData;
|
||||
// Span<ScopeStencil> scopeData;
|
||||
// ...
|
||||
// }
|
||||
//
|
||||
// struct StencilDelazificationSet {
|
||||
// Span<BaseCompilationStencil> delazifications;
|
||||
// ...
|
||||
// }
|
||||
//
|
||||
// struct CompilationStencil : BaseCompilationStencil {
|
||||
// LifoAlloc alloc;
|
||||
// CompilationInput input;
|
||||
// Span<ScriptStencilExtra> scriptExtra;
|
||||
// StencilDelazifcationSet* delazificationSet;
|
||||
// ...
|
||||
// }
|
||||
//
|
||||
// When we delazify a function that was lazily parsed, we generate a new Stencil
|
||||
// at the point too. These delazifications can be merged into the Stencil of
|
||||
// the initial parse.
|
||||
// at the point too. These delazifications can be cached as well. When loading
|
||||
// back from a cache we group these together in a `StencilDelazificationSet`
|
||||
// structure that hangs off the `CompilationStencil`. This delazification data
|
||||
// is only meaningful if we also have the initial parse stencil.
|
||||
//
|
||||
//
|
||||
// CompilationGCOutput
|
||||
|
@ -143,7 +166,7 @@ using RegExpIndex = TypedIndex<RegExpStencil>;
|
|||
using BigIntIndex = TypedIndex<BigIntStencil>;
|
||||
using ObjLiteralIndex = TypedIndex<ObjLiteralStencil>;
|
||||
|
||||
// Index into {ExtensibleCompilationStencil,CompilationStencil}.gcThingData.
|
||||
// Index into {ExtensibleCompilationStencil,BaseCompilationStencil}.gcThingData.
|
||||
class CompilationGCThingType {};
|
||||
using CompilationGCThingIndex = TypedIndex<CompilationGCThingType>;
|
||||
|
||||
|
@ -161,8 +184,6 @@ class RegExpStencil {
|
|||
// Use uint32_t to make this struct fully-packed.
|
||||
uint32_t flags_;
|
||||
|
||||
friend struct CompilationStencilMerger;
|
||||
|
||||
public:
|
||||
RegExpStencil() = default;
|
||||
|
||||
|
@ -175,15 +196,16 @@ class RegExpStencil {
|
|||
const CompilationAtomCache& atomCache) const;
|
||||
|
||||
// This is used by `Reflect.parse` when we need the RegExpObject but are not
|
||||
// doing a complete instantiation of the CompilationStencil.
|
||||
// doing a complete instantiation of the BaseCompilationStencil.
|
||||
RegExpObject* createRegExpAndEnsureAtom(
|
||||
JSContext* cx, ParserAtomsTable& parserAtoms,
|
||||
CompilationAtomCache& atomCache) const;
|
||||
|
||||
#if defined(DEBUG) || defined(JS_JITSPEW)
|
||||
void dump() const;
|
||||
void dump(JSONPrinter& json, const CompilationStencil* stencil) const;
|
||||
void dumpFields(JSONPrinter& json, const CompilationStencil* stencil) const;
|
||||
void dump(JSONPrinter& json, const BaseCompilationStencil* stencil) const;
|
||||
void dumpFields(JSONPrinter& json,
|
||||
const BaseCompilationStencil* stencil) const;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
@ -201,7 +223,7 @@ class BigIntStencil {
|
|||
BigIntStencil() = default;
|
||||
|
||||
[[nodiscard]] bool init(JSContext* cx, LifoAlloc& alloc,
|
||||
const mozilla::Span<const char16_t> buf);
|
||||
const Vector<char16_t, 32>& buf);
|
||||
|
||||
BigInt* createBigInt(JSContext* cx) const {
|
||||
mozilla::Range<const char16_t> source(source_.data(), source_.size());
|
||||
|
@ -213,8 +235,6 @@ class BigIntStencil {
|
|||
return js::BigIntLiteralIsZero(source);
|
||||
}
|
||||
|
||||
mozilla::Span<const char16_t> source() const { return source_; }
|
||||
|
||||
#ifdef DEBUG
|
||||
bool isContainedIn(const LifoAlloc& alloc) const;
|
||||
#endif
|
||||
|
@ -228,7 +248,6 @@ class BigIntStencil {
|
|||
|
||||
class ScopeStencil {
|
||||
friend class StencilXDR;
|
||||
friend struct CompilationStencilMerger;
|
||||
|
||||
// The enclosing scope. Valid only if HasEnclosing flag is set.
|
||||
// compilation applies.
|
||||
|
@ -382,9 +401,9 @@ class ScopeStencil {
|
|||
#if defined(DEBUG) || defined(JS_JITSPEW)
|
||||
void dump() const;
|
||||
void dump(JSONPrinter& json, const BaseParserScopeData* baseScopeData,
|
||||
const CompilationStencil* stencil) const;
|
||||
const BaseCompilationStencil* stencil) const;
|
||||
void dumpFields(JSONPrinter& json, const BaseParserScopeData* baseScopeData,
|
||||
const CompilationStencil* stencil) const;
|
||||
const BaseCompilationStencil* stencil) const;
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
@ -593,8 +612,9 @@ class StencilModuleMetadata
|
|||
|
||||
#if defined(DEBUG) || defined(JS_JITSPEW)
|
||||
void dump() const;
|
||||
void dump(JSONPrinter& json, const CompilationStencil* stencil) const;
|
||||
void dumpFields(JSONPrinter& json, const CompilationStencil* stencil) const;
|
||||
void dump(JSONPrinter& json, const BaseCompilationStencil* stencil) const;
|
||||
void dumpFields(JSONPrinter& json,
|
||||
const BaseCompilationStencil* stencil) const;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
@ -731,8 +751,6 @@ class TaggedScriptThingIndex {
|
|||
|
||||
// Data generated by frontend that will be used to create a js::BaseScript.
|
||||
class ScriptStencil {
|
||||
friend struct CompilationStencilMerger;
|
||||
|
||||
public:
|
||||
// Fields for BaseScript.
|
||||
// Used by:
|
||||
|
@ -743,7 +761,7 @@ class ScriptStencil {
|
|||
// * lazy Function (cannot be asm.js module)
|
||||
|
||||
// GCThings are stored into
|
||||
// {ExtensibleCompilationStencil,CompilationStencil}.gcThingData,
|
||||
// {ExtensibleCompilationStencil,BaseCompilationStencil}.gcThingData,
|
||||
// in [gcThingsOffset, gcThingsOffset + gcThingsLength) range.
|
||||
CompilationGCThingIndex gcThingsOffset;
|
||||
uint32_t gcThingsLength = 0;
|
||||
|
@ -781,7 +799,7 @@ class ScriptStencil {
|
|||
static constexpr uint16_t AllowRelazifyFlag = 1 << 1;
|
||||
|
||||
// Set if this is non-lazy script and shared data is created.
|
||||
// The shared data is stored into CompilationStencil.sharedData.
|
||||
// The shared data is stored into BaseCompilationStencil.sharedData.
|
||||
static constexpr uint16_t HasSharedDataFlag = 1 << 2;
|
||||
|
||||
// True if this script is lazy function and has enclosing scope.
|
||||
|
@ -804,7 +822,7 @@ class ScriptStencil {
|
|||
bool hasGCThings() const { return gcThingsLength; }
|
||||
|
||||
mozilla::Span<TaggedScriptThingIndex> gcthings(
|
||||
const CompilationStencil& stencil) const;
|
||||
const BaseCompilationStencil& stencil) const;
|
||||
|
||||
bool wasEmittedByEnclosingScript() const {
|
||||
return flags_ & WasEmittedByEnclosingScriptFlag;
|
||||
|
@ -837,11 +855,6 @@ class ScriptStencil {
|
|||
setHasLazyFunctionEnclosingScopeIndex();
|
||||
}
|
||||
|
||||
void resetHasLazyFunctionEnclosingScopeIndexAfterStencilMerge() {
|
||||
flags_ &= ~HasLazyFunctionEnclosingScopeIndexFlag;
|
||||
lazyFunctionEnclosingScopeIndex_ = ScopeIndex::invalid();
|
||||
}
|
||||
|
||||
ScopeIndex lazyFunctionEnclosingScopeIndex() const {
|
||||
MOZ_ASSERT(hasLazyFunctionEnclosingScopeIndex());
|
||||
return lazyFunctionEnclosingScopeIndex_;
|
||||
|
@ -849,8 +862,9 @@ class ScriptStencil {
|
|||
|
||||
#if defined(DEBUG) || defined(JS_JITSPEW)
|
||||
void dump() const;
|
||||
void dump(JSONPrinter& json, const CompilationStencil* stencil) const;
|
||||
void dumpFields(JSONPrinter& json, const CompilationStencil* stencil) const;
|
||||
void dump(JSONPrinter& json, const BaseCompilationStencil* stencil) const;
|
||||
void dumpFields(JSONPrinter& json,
|
||||
const BaseCompilationStencil* stencil) const;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
@ -904,11 +918,11 @@ class ScriptStencilExtra {
|
|||
#if defined(DEBUG) || defined(JS_JITSPEW)
|
||||
void DumpTaggedParserAtomIndex(js::JSONPrinter& json,
|
||||
TaggedParserAtomIndex taggedIndex,
|
||||
const CompilationStencil* stencil);
|
||||
const BaseCompilationStencil* stencil);
|
||||
|
||||
void DumpTaggedParserAtomIndexNoQuote(GenericPrinter& out,
|
||||
TaggedParserAtomIndex taggedIndex,
|
||||
const CompilationStencil* stencil);
|
||||
const BaseCompilationStencil* stencil);
|
||||
#endif
|
||||
|
||||
} /* namespace frontend */
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
#include <type_traits> // std::has_unique_object_representations
|
||||
#include <utility> // std::forward
|
||||
|
||||
#include "frontend/CompilationStencil.h" // CompilationStencil
|
||||
#include "frontend/CompilationStencil.h" // BaseCompilationStencil
|
||||
#include "frontend/ScriptIndex.h" // ScriptIndex
|
||||
#include "vm/JSScript.h" // js::CheckCompileOptionsMatch
|
||||
#include "vm/Scope.h" // SizeOfParserScopeData
|
||||
|
@ -412,33 +412,41 @@ XDRResult XDRSharedDataContainer(XDRState<mode>* xdr,
|
|||
}
|
||||
|
||||
template <XDRMode mode>
|
||||
XDRResult XDRCompilationStencilSpanSize(
|
||||
XDRResult XDRBaseCompilationStencilSpanSize(
|
||||
XDRState<mode>* xdr, uint32_t* scriptSize, uint32_t* gcThingSize,
|
||||
uint32_t* scopeSize, uint32_t* scriptExtraSize, uint32_t* regExpSize,
|
||||
uint32_t* bigIntSize, uint32_t* objLiteralSize) {
|
||||
uint32_t* scopeSize, uint32_t* regExpSize, uint32_t* bigIntSize,
|
||||
uint32_t* objLiteralSize) {
|
||||
// Compress the series of span sizes, to avoid consuming extra space for
|
||||
// unused/small span sizes.
|
||||
// There will be align32 shortly after this section, so try to make the
|
||||
// padding smaller.
|
||||
|
||||
enum XDRSpanSizeKind {
|
||||
// All of the size values fit in 1 byte each. The entire section takes 7
|
||||
// bytes, and expect no padding.
|
||||
// The scriptSize, gcThingSize, and scopeSize fit in 1 byte, and others have
|
||||
// a value of 0. The entire section takes 4 bytes, and expect no padding.
|
||||
Base8Kind,
|
||||
|
||||
// All of the size values can fit in 1 byte each. The entire section takes 7
|
||||
// bytes, and expect 1 byte padding.
|
||||
All8Kind,
|
||||
|
||||
// Other cases. All of the size values fit in 4 bytes each. Expect 3 bytes
|
||||
// padding for `sizeKind`.
|
||||
// Other. This case is less than 1% in practice and indicates the stencil is
|
||||
// already quite large, so don't try to compress. Expect 3 bytes padding for
|
||||
// `sizeKind`.
|
||||
All32Kind,
|
||||
};
|
||||
|
||||
uint8_t sizeKind = All32Kind;
|
||||
if (mode == XDR_ENCODE) {
|
||||
uint32_t mask = (*scriptSize) | (*gcThingSize) | (*scopeSize) |
|
||||
(*scriptExtraSize) | (*regExpSize) | (*bigIntSize) |
|
||||
(*objLiteralSize);
|
||||
uint32_t mask_base = (*scriptSize) | (*gcThingSize) | (*scopeSize);
|
||||
uint32_t mask_ext = (*regExpSize) | (*bigIntSize) | (*objLiteralSize);
|
||||
|
||||
if (mask <= 0xff) {
|
||||
sizeKind = All8Kind;
|
||||
if (mask_base <= 0xff) {
|
||||
if (mask_ext == 0x00) {
|
||||
sizeKind = Base8Kind;
|
||||
} else if (mask_ext <= 0xFF) {
|
||||
sizeKind = All8Kind;
|
||||
}
|
||||
}
|
||||
}
|
||||
MOZ_TRY(xdr->codeUint8(&sizeKind));
|
||||
|
@ -447,7 +455,6 @@ XDRResult XDRCompilationStencilSpanSize(
|
|||
MOZ_TRY(xdr->codeUint32(scriptSize));
|
||||
MOZ_TRY(xdr->codeUint32(gcThingSize));
|
||||
MOZ_TRY(xdr->codeUint32(scopeSize));
|
||||
MOZ_TRY(xdr->codeUint32(scriptExtraSize));
|
||||
MOZ_TRY(xdr->codeUint32(regExpSize));
|
||||
MOZ_TRY(xdr->codeUint32(bigIntSize));
|
||||
MOZ_TRY(xdr->codeUint32(objLiteralSize));
|
||||
|
@ -455,7 +462,6 @@ XDRResult XDRCompilationStencilSpanSize(
|
|||
uint8_t scriptSize8 = 0;
|
||||
uint8_t gcThingSize8 = 0;
|
||||
uint8_t scopeSize8 = 0;
|
||||
uint8_t scriptExtraSize8 = 0;
|
||||
uint8_t regExpSize8 = 0;
|
||||
uint8_t bigIntSize8 = 0;
|
||||
uint8_t objLiteralSize8 = 0;
|
||||
|
@ -464,7 +470,6 @@ XDRResult XDRCompilationStencilSpanSize(
|
|||
scriptSize8 = uint8_t(*scriptSize);
|
||||
gcThingSize8 = uint8_t(*gcThingSize);
|
||||
scopeSize8 = uint8_t(*scopeSize);
|
||||
scriptExtraSize8 = uint8_t(*scriptExtraSize);
|
||||
regExpSize8 = uint8_t(*regExpSize);
|
||||
bigIntSize8 = uint8_t(*bigIntSize);
|
||||
objLiteralSize8 = uint8_t(*objLiteralSize);
|
||||
|
@ -473,16 +478,21 @@ XDRResult XDRCompilationStencilSpanSize(
|
|||
MOZ_TRY(xdr->codeUint8(&scriptSize8));
|
||||
MOZ_TRY(xdr->codeUint8(&gcThingSize8));
|
||||
MOZ_TRY(xdr->codeUint8(&scopeSize8));
|
||||
MOZ_TRY(xdr->codeUint8(&scriptExtraSize8));
|
||||
MOZ_TRY(xdr->codeUint8(®ExpSize8));
|
||||
MOZ_TRY(xdr->codeUint8(&bigIntSize8));
|
||||
MOZ_TRY(xdr->codeUint8(&objLiteralSize8));
|
||||
|
||||
if (sizeKind == All8Kind) {
|
||||
MOZ_TRY(xdr->codeUint8(®ExpSize8));
|
||||
MOZ_TRY(xdr->codeUint8(&bigIntSize8));
|
||||
MOZ_TRY(xdr->codeUint8(&objLiteralSize8));
|
||||
} else {
|
||||
MOZ_ASSERT(regExpSize8 == 0);
|
||||
MOZ_ASSERT(bigIntSize8 == 0);
|
||||
MOZ_ASSERT(objLiteralSize8 == 0);
|
||||
}
|
||||
|
||||
if (mode == XDR_DECODE) {
|
||||
*scriptSize = scriptSize8;
|
||||
*gcThingSize = gcThingSize8;
|
||||
*scopeSize = scopeSize8;
|
||||
*scriptExtraSize = scriptExtraSize8;
|
||||
*regExpSize = regExpSize8;
|
||||
*bigIntSize = bigIntSize8;
|
||||
*objLiteralSize = objLiteralSize8;
|
||||
|
@ -493,17 +503,11 @@ XDRResult XDRCompilationStencilSpanSize(
|
|||
}
|
||||
|
||||
template <XDRMode mode>
|
||||
XDRResult XDRCompilationStencil(XDRState<mode>* xdr,
|
||||
CompilationStencil& stencil) {
|
||||
MOZ_ASSERT(!stencil.asmJS);
|
||||
|
||||
if (mode == XDR_DECODE) {
|
||||
stencil.hasExternalDependency = true;
|
||||
}
|
||||
|
||||
XDRResult XDRBaseCompilationStencil(XDRState<mode>* xdr,
|
||||
BaseCompilationStencil& stencil) {
|
||||
MOZ_TRY(xdr->codeUint32(&stencil.functionKey));
|
||||
|
||||
uint32_t scriptSize, gcThingSize, scopeSize, scriptExtraSize;
|
||||
uint32_t scriptSize, gcThingSize, scopeSize;
|
||||
uint32_t regExpSize, bigIntSize, objLiteralSize;
|
||||
if (mode == XDR_ENCODE) {
|
||||
scriptSize = stencil.scriptData.size();
|
||||
|
@ -511,15 +515,13 @@ XDRResult XDRCompilationStencil(XDRState<mode>* xdr,
|
|||
scopeSize = stencil.scopeData.size();
|
||||
MOZ_ASSERT(scopeSize == stencil.scopeNames.size());
|
||||
|
||||
scriptExtraSize = stencil.scriptExtra.size();
|
||||
|
||||
regExpSize = stencil.regExpData.size();
|
||||
bigIntSize = stencil.bigIntData.size();
|
||||
objLiteralSize = stencil.objLiteralData.size();
|
||||
}
|
||||
MOZ_TRY(XDRCompilationStencilSpanSize(
|
||||
xdr, &scriptSize, &gcThingSize, &scopeSize, &scriptExtraSize, ®ExpSize,
|
||||
&bigIntSize, &objLiteralSize));
|
||||
MOZ_TRY(XDRBaseCompilationStencilSpanSize(xdr, &scriptSize, &gcThingSize,
|
||||
&scopeSize, ®ExpSize,
|
||||
&bigIntSize, &objLiteralSize));
|
||||
|
||||
// All of the vector-indexed data elements referenced by the
|
||||
// main script tree must be materialized first.
|
||||
|
@ -549,9 +551,32 @@ XDRResult XDRCompilationStencil(XDRState<mode>* xdr,
|
|||
MOZ_TRY(XDRSpanContent(xdr, stencil.gcThingData, gcThingSize));
|
||||
|
||||
// Now serialize the vector of ScriptStencils.
|
||||
|
||||
MOZ_TRY(XDRSpanContent(xdr, stencil.scriptData, scriptSize));
|
||||
|
||||
MOZ_TRY(XDRSpanContent(xdr, stencil.scriptExtra, scriptExtraSize));
|
||||
return Ok();
|
||||
}
|
||||
|
||||
template XDRResult XDRBaseCompilationStencil(XDRState<XDR_ENCODE>* xdr,
|
||||
BaseCompilationStencil& stencil);
|
||||
|
||||
template XDRResult XDRBaseCompilationStencil(XDRState<XDR_DECODE>* xdr,
|
||||
BaseCompilationStencil& stencil);
|
||||
|
||||
template <XDRMode mode>
|
||||
XDRResult XDRCompilationStencil(XDRState<mode>* xdr,
|
||||
CompilationStencil& stencil) {
|
||||
if (stencil.asmJS) {
|
||||
return xdr->fail(JS::TranscodeResult::Failure_AsmJSNotSupported);
|
||||
}
|
||||
|
||||
if (mode == XDR_DECODE) {
|
||||
stencil.hasExternalDependency = true;
|
||||
}
|
||||
|
||||
MOZ_TRY(XDRBaseCompilationStencil(xdr, stencil));
|
||||
|
||||
MOZ_TRY(XDRSpanContent(xdr, stencil.scriptExtra));
|
||||
|
||||
// We don't support coding non-initial CompilationStencil.
|
||||
MOZ_ASSERT(stencil.isInitialStencil());
|
||||
|
@ -577,30 +602,4 @@ template XDRResult XDRCompilationStencil(XDRState<XDR_ENCODE>* xdr,
|
|||
template XDRResult XDRCompilationStencil(XDRState<XDR_DECODE>* xdr,
|
||||
CompilationStencil& stencil);
|
||||
|
||||
template <XDRMode mode>
|
||||
XDRResult XDRCheckCompilationStencil(XDRState<mode>* xdr,
|
||||
CompilationStencil& stencil) {
|
||||
if (stencil.asmJS) {
|
||||
return xdr->fail(JS::TranscodeResult::Failure_AsmJSNotSupported);
|
||||
}
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
template XDRResult XDRCheckCompilationStencil(XDRState<XDR_ENCODE>* xdr,
|
||||
CompilationStencil& stencil);
|
||||
|
||||
template <XDRMode mode>
|
||||
XDRResult XDRCheckCompilationStencil(XDRState<mode>* xdr,
|
||||
ExtensibleCompilationStencil& stencil) {
|
||||
if (stencil.asmJS) {
|
||||
return xdr->fail(JS::TranscodeResult::Failure_AsmJSNotSupported);
|
||||
}
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
template XDRResult XDRCheckCompilationStencil(
|
||||
XDRState<XDR_ENCODE>* xdr, ExtensibleCompilationStencil& stencil);
|
||||
|
||||
} // namespace js
|
||||
|
|
|
@ -1,70 +0,0 @@
|
|||
load(libdir + 'bytecode-cache.js');
|
||||
|
||||
let test = `
|
||||
// Put some unused atoms in the initial stencil, to verify that atoms are
|
||||
// correctly mapped while merging stencils.
|
||||
if (false) {
|
||||
"unused text1";
|
||||
"unused text2";
|
||||
"unused text3";
|
||||
"unused text4";
|
||||
"unused text5";
|
||||
}
|
||||
|
||||
var result = 0;
|
||||
|
||||
function func() {
|
||||
var anonFunc = function() {
|
||||
// Method/accessor as inner-inner function.
|
||||
var obj = {
|
||||
method(name) {
|
||||
// Test object literal.
|
||||
var object = {
|
||||
propA: 9,
|
||||
propB: 10,
|
||||
propC: 11,
|
||||
};
|
||||
|
||||
// Test object property access.
|
||||
return object["prop" + name];
|
||||
},
|
||||
get prop1() {
|
||||
return 200;
|
||||
},
|
||||
set prop2(value) {
|
||||
result += value;
|
||||
}
|
||||
};
|
||||
result += obj.prop1;
|
||||
obj.prop2 = 3000;
|
||||
result += obj.method("B");
|
||||
};
|
||||
|
||||
function anotherFunc() {
|
||||
return 40000;
|
||||
}
|
||||
|
||||
function unused() {
|
||||
}
|
||||
|
||||
class MyClass {
|
||||
constructor() {
|
||||
result += 500000;
|
||||
}
|
||||
}
|
||||
|
||||
// Functions inside arrow parameters, that are parsed multiple times.
|
||||
const arrow = (a = (b = c => { result += 6000000 }) => b) => a()();
|
||||
|
||||
// Delazify in the different order as definition.
|
||||
new MyClass();
|
||||
anonFunc();
|
||||
result += anotherFunc();
|
||||
arrow();
|
||||
}
|
||||
func();
|
||||
|
||||
result;
|
||||
`;
|
||||
|
||||
evalWithCache(test, { incremental: true, oassertEqResult : true });
|
|
@ -12,6 +12,7 @@ test = `
|
|||
`;
|
||||
evalWithCache(test, {
|
||||
incremental: true,
|
||||
assertEqBytecode: true,
|
||||
assertEqResult : true
|
||||
});
|
||||
|
||||
|
@ -23,6 +24,7 @@ test = `
|
|||
`;
|
||||
evalWithCache(test, {
|
||||
incremental: true,
|
||||
assertEqBytecode: true,
|
||||
assertEqResult : true
|
||||
});
|
||||
|
||||
|
@ -34,6 +36,7 @@ test = `
|
|||
`;
|
||||
evalWithCache(test, {
|
||||
incremental: true,
|
||||
assertEqBytecode: true,
|
||||
assertEqResult : true
|
||||
});
|
||||
|
||||
|
@ -46,6 +49,7 @@ test = `
|
|||
`;
|
||||
evalWithCache(test, {
|
||||
incremental: true,
|
||||
assertEqBytecode: true,
|
||||
assertEqResult : true
|
||||
});
|
||||
|
||||
|
|
|
@ -5734,7 +5734,7 @@ static JS::TranscodeResult DecodeStencil(JSContext* cx,
|
|||
return JS::TranscodeResult::Throw;
|
||||
}
|
||||
|
||||
XDRResult res = decoder.codeStencil(input, stencil);
|
||||
XDRResult res = decoder.codeStencils(input, stencil);
|
||||
if (res.isErr()) {
|
||||
return res.unwrapErr();
|
||||
}
|
||||
|
@ -5767,8 +5767,9 @@ JS_PUBLIC_API JS::TranscodeResult JS::DecodeScriptMaybeStencil(
|
|||
}
|
||||
|
||||
Rooted<frontend::CompilationGCOutput> gcOutput(cx);
|
||||
if (!frontend::InstantiateStencils(cx, input.get(), stencil,
|
||||
gcOutput.get())) {
|
||||
Rooted<frontend::CompilationGCOutput> gcOutputForDelazification(cx);
|
||||
if (!frontend::InstantiateStencils(cx, input.get(), stencil, gcOutput.get(),
|
||||
gcOutputForDelazification.address())) {
|
||||
return JS::TranscodeResult::Throw;
|
||||
}
|
||||
|
||||
|
@ -5811,28 +5812,22 @@ JS_PUBLIC_API JS::TranscodeResult JS::DecodeScriptAndStartIncrementalEncoding(
|
|||
return res;
|
||||
}
|
||||
|
||||
UniquePtr<XDRIncrementalStencilEncoder> xdrEncoder;
|
||||
if (!stencil.source->xdrEncodeStencils(cx, input.get(), stencil,
|
||||
xdrEncoder)) {
|
||||
return JS::TranscodeResult::Throw;
|
||||
}
|
||||
|
||||
Rooted<frontend::CompilationGCOutput> gcOutput(cx);
|
||||
if (!frontend::InstantiateStencils(cx, input.get(), stencil,
|
||||
gcOutput.get())) {
|
||||
Rooted<frontend::CompilationGCOutput> gcOutputForDelazification(cx);
|
||||
if (!frontend::InstantiateStencils(cx, input.get(), stencil, gcOutput.get(),
|
||||
gcOutputForDelazification.address())) {
|
||||
return JS::TranscodeResult::Throw;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(gcOutput.get().script);
|
||||
|
||||
auto initial =
|
||||
js::MakeUnique<frontend::ExtensibleCompilationStencil>(cx, input.get());
|
||||
if (!initial) {
|
||||
ReportOutOfMemory(cx);
|
||||
return JS::TranscodeResult::Throw;
|
||||
}
|
||||
if (!initial->steal(cx, std::move(stencil))) {
|
||||
return JS::TranscodeResult::Throw;
|
||||
}
|
||||
|
||||
if (!gcOutput.get().script->scriptSource()->startIncrementalEncoding(
|
||||
cx, options, std::move(initial))) {
|
||||
return JS::TranscodeResult::Throw;
|
||||
}
|
||||
gcOutput.get().script->scriptSource()->setIncrementalEncoder(
|
||||
xdrEncoder.release());
|
||||
|
||||
scriptp.set(gcOutput.get().script);
|
||||
|
||||
|
|
|
@ -2435,12 +2435,6 @@ static bool Evaluate(JSContext* cx, unsigned argc, Value* vp) {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (saveIncrementalBytecode && assertEqBytecode) {
|
||||
JS_ReportErrorASCII(
|
||||
cx, "saveIncrementalBytecode cannot be used with assertEqBytecode.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (envChain.length() != 0) {
|
||||
|
|
|
@ -99,28 +99,30 @@ static JSScript* CompileSourceBufferAndStartIncrementalEncoding(
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
RootedScript script(cx);
|
||||
{
|
||||
frontend::BorrowingCompilationStencil borrowingStencil(*stencil);
|
||||
frontend::BorrowingCompilationStencil borrowingStencil(*stencil);
|
||||
|
||||
Rooted<frontend::CompilationGCOutput> gcOutput(cx);
|
||||
if (!frontend::InstantiateStencils(cx, input.get(), borrowingStencil,
|
||||
gcOutput.get())) {
|
||||
return nullptr;
|
||||
}
|
||||
Rooted<frontend::CompilationGCOutput> gcOutput(cx);
|
||||
if (!frontend::InstantiateStencils(cx, input.get(), borrowingStencil,
|
||||
gcOutput.get())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
script = gcOutput.get().script;
|
||||
if (!script) {
|
||||
return nullptr;
|
||||
}
|
||||
RootedScript script(cx, gcOutput.get().script);
|
||||
if (!script) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MOZ_DIAGNOSTIC_ASSERT(options.useStencilXDR);
|
||||
if (!script->scriptSource()->startIncrementalEncoding(cx, options,
|
||||
std::move(stencil))) {
|
||||
|
||||
UniquePtr<XDRIncrementalStencilEncoder> xdrEncoder;
|
||||
|
||||
if (!borrowingStencil.source->xdrEncodeInitialStencil(
|
||||
cx, input.get(), borrowingStencil, xdrEncoder)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
script->scriptSource()->setIncrementalEncoder(xdrEncoder.release());
|
||||
|
||||
return script;
|
||||
}
|
||||
|
||||
|
|
|
@ -529,6 +529,7 @@ struct ParseTask : public mozilla::LinkedListElement<ParseTask>,
|
|||
UniquePtr<frontend::ExtensibleCompilationStencil> extensibleStencil_;
|
||||
|
||||
frontend::CompilationGCOutput gcOutput_;
|
||||
frontend::CompilationGCOutput gcOutputForDelazification_;
|
||||
|
||||
// Any errors or warnings produced during compilation. These are reported
|
||||
// when finishing the script.
|
||||
|
|
|
@ -587,6 +587,7 @@ void ParseTask::trace(JSTracer* trc) {
|
|||
}
|
||||
|
||||
gcOutput_.trace(trc);
|
||||
gcOutputForDelazification_.trace(trc);
|
||||
}
|
||||
|
||||
size_t ParseTask::sizeOfExcludingThis(
|
||||
|
@ -606,7 +607,8 @@ size_t ParseTask::sizeOfExcludingThis(
|
|||
scripts.sizeOfExcludingThis(mallocSizeOf) +
|
||||
sourceObjects.sizeOfExcludingThis(mallocSizeOf) + stencilInputSize +
|
||||
stencilSize + extensibleStencilSize +
|
||||
gcOutput_.sizeOfExcludingThis(mallocSizeOf);
|
||||
gcOutput_.sizeOfExcludingThis(mallocSizeOf) +
|
||||
gcOutputForDelazification_.sizeOfExcludingThis(mallocSizeOf);
|
||||
}
|
||||
|
||||
void ParseTask::runHelperThreadTask(AutoLockHelperThreadState& locked) {
|
||||
|
@ -719,12 +721,13 @@ bool ParseTask::instantiateStencils(JSContext* cx) {
|
|||
|
||||
bool result;
|
||||
if (stencil_) {
|
||||
result =
|
||||
frontend::InstantiateStencils(cx, *stencilInput_, *stencil_, gcOutput_);
|
||||
result = frontend::InstantiateStencils(
|
||||
cx, *stencilInput_, *stencil_, gcOutput_, &gcOutputForDelazification_);
|
||||
} else {
|
||||
frontend::BorrowingCompilationStencil borrowingStencil(*extensibleStencil_);
|
||||
result = frontend::InstantiateStencils(cx, *stencilInput_, borrowingStencil,
|
||||
gcOutput_);
|
||||
result =
|
||||
frontend::InstantiateStencils(cx, *stencilInput_, borrowingStencil,
|
||||
gcOutput_, &gcOutputForDelazification_);
|
||||
}
|
||||
|
||||
// Whatever happens to the top-level script compilation (even if it fails),
|
||||
|
@ -821,14 +824,15 @@ void ScriptDecodeTask::parse(JSContext* cx) {
|
|||
}
|
||||
|
||||
XDRStencilDecoder decoder(cx, &options, range);
|
||||
XDRResult res = decoder.codeStencil(*stencilInput_, *stencil_);
|
||||
XDRResult res = decoder.codeStencils(*stencilInput_, *stencil_);
|
||||
if (!res.isOk()) {
|
||||
stencil_.reset();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!frontend::PrepareForInstantiate(cx, *stencilInput_, *stencil_,
|
||||
gcOutput_)) {
|
||||
gcOutput_,
|
||||
&gcOutputForDelazification_)) {
|
||||
stencil_.reset();
|
||||
}
|
||||
|
||||
|
@ -2121,28 +2125,24 @@ JSScript* GlobalHelperThreadState::finishSingleParseTask(
|
|||
if (startEncoding == StartEncoding::Yes) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(parseTask->options.useStencilXDR);
|
||||
|
||||
if (parseTask->stencil_) {
|
||||
auto initial = js::MakeUnique<frontend::ExtensibleCompilationStencil>(
|
||||
cx, *parseTask->stencilInput_);
|
||||
if (!initial) {
|
||||
ReportOutOfMemory(cx);
|
||||
return nullptr;
|
||||
}
|
||||
if (!initial->steal(cx, std::move(*parseTask->stencil_))) {
|
||||
return nullptr;
|
||||
}
|
||||
UniquePtr<XDRIncrementalStencilEncoder> xdrEncoder;
|
||||
|
||||
if (!script->scriptSource()->startIncrementalEncoding(
|
||||
cx, parseTask->options, std::move(initial))) {
|
||||
if (parseTask->stencil_) {
|
||||
auto* stencil = parseTask->stencil_.get();
|
||||
if (!stencil->source->xdrEncodeStencils(cx, *parseTask->stencilInput_,
|
||||
*stencil, xdrEncoder)) {
|
||||
return nullptr;
|
||||
}
|
||||
} else if (parseTask->extensibleStencil_) {
|
||||
if (!script->scriptSource()->startIncrementalEncoding(
|
||||
cx, parseTask->options,
|
||||
std::move(parseTask->extensibleStencil_))) {
|
||||
frontend::BorrowingCompilationStencil borrowingStencil(
|
||||
*parseTask->extensibleStencil_);
|
||||
if (!borrowingStencil.source->xdrEncodeStencils(
|
||||
cx, *parseTask->stencilInput_, borrowingStencil, xdrEncoder)) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
script->scriptSource()->setIncrementalEncoder(xdrEncoder.release());
|
||||
}
|
||||
|
||||
return script;
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
|
||||
#include "frontend/BytecodeCompiler.h"
|
||||
#include "frontend/BytecodeEmitter.h"
|
||||
#include "frontend/CompilationStencil.h" // frontend::CompilationStencil
|
||||
#include "frontend/CompilationStencil.h" // frontend::BaseCompilationStencil
|
||||
#include "frontend/SharedContext.h"
|
||||
#include "frontend/SourceNotes.h" // SrcNote, SrcNoteType, SrcNoteIterator
|
||||
#include "frontend/StencilXdr.h" // frontend::StencilXdr::SharedData, CanCopyDataToDisk
|
||||
|
@ -2688,30 +2688,26 @@ void ScriptSource::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
|
|||
info->numScripts++;
|
||||
}
|
||||
|
||||
bool ScriptSource::startIncrementalEncoding(
|
||||
JSContext* cx, const JS::ReadOnlyCompileOptions& options,
|
||||
UniquePtr<frontend::ExtensibleCompilationStencil>&& initial) {
|
||||
bool ScriptSource::xdrEncodeInitialStencil(
|
||||
JSContext* cx, frontend::CompilationInput& input,
|
||||
const frontend::CompilationStencil& stencil,
|
||||
UniquePtr<XDRIncrementalStencilEncoder>& xdrEncoder) {
|
||||
// Encoding failures are reported by the xdrFinalizeEncoder function.
|
||||
if (containsAsmJS()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Remove the reference to the source, to avoid the circular reference.
|
||||
initial->source = nullptr;
|
||||
|
||||
xdrEncoder_ = js::MakeUnique<XDRIncrementalStencilEncoder>(cx);
|
||||
if (!xdrEncoder_) {
|
||||
xdrEncoder = js::MakeUnique<XDRIncrementalStencilEncoder>(cx);
|
||||
if (!xdrEncoder) {
|
||||
ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
|
||||
AutoIncrementalTimer timer(cx->realm()->timers.xdrEncodingTime);
|
||||
auto failureCase =
|
||||
mozilla::MakeScopeExit([&] { xdrEncoder_.reset(nullptr); });
|
||||
auto failureCase = mozilla::MakeScopeExit([&] { xdrEncoder.reset(nullptr); });
|
||||
|
||||
XDRResult res = xdrEncoder_->setInitial(
|
||||
options,
|
||||
std::forward<UniquePtr<frontend::ExtensibleCompilationStencil>>(initial));
|
||||
XDRResult res = xdrEncoder->codeStencil(
|
||||
input, const_cast<frontend::CompilationStencil&>(stencil));
|
||||
if (res.isErr()) {
|
||||
// On encoding failure, let failureCase destroy encoder and return true
|
||||
// to avoid failing any currently executing script.
|
||||
|
@ -2722,14 +2718,44 @@ bool ScriptSource::startIncrementalEncoding(
|
|||
return true;
|
||||
}
|
||||
|
||||
bool ScriptSource::addDelazificationToIncrementalEncoding(
|
||||
JSContext* cx, const frontend::CompilationStencil& stencil) {
|
||||
bool ScriptSource::xdrEncodeStencils(
|
||||
JSContext* cx, frontend::CompilationInput& input,
|
||||
const frontend::CompilationStencil& stencil,
|
||||
UniquePtr<XDRIncrementalStencilEncoder>& xdrEncoder) {
|
||||
if (!xdrEncodeInitialStencil(cx, input, stencil, xdrEncoder)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (stencil.delazificationSet) {
|
||||
for (auto& delazification : stencil.delazificationSet->delazifications) {
|
||||
if (!xdrEncodeFunctionStencilWith(cx, delazification, xdrEncoder)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ScriptSource::setIncrementalEncoder(
|
||||
XDRIncrementalStencilEncoder* xdrEncoder) {
|
||||
xdrEncoder_.reset(xdrEncoder);
|
||||
}
|
||||
|
||||
bool ScriptSource::xdrEncodeFunctionStencil(
|
||||
JSContext* cx, const frontend::BaseCompilationStencil& stencil) {
|
||||
MOZ_ASSERT(hasEncoder());
|
||||
AutoIncrementalTimer timer(cx->realm()->timers.xdrEncodingTime);
|
||||
auto failureCase =
|
||||
mozilla::MakeScopeExit([&] { xdrEncoder_.reset(nullptr); });
|
||||
return xdrEncodeFunctionStencilWith(cx, stencil, xdrEncoder_);
|
||||
}
|
||||
|
||||
XDRResult res = xdrEncoder_->addDelazification(stencil);
|
||||
bool ScriptSource::xdrEncodeFunctionStencilWith(
|
||||
JSContext* cx, const frontend::BaseCompilationStencil& stencil,
|
||||
UniquePtr<XDRIncrementalStencilEncoder>& xdrEncoder) {
|
||||
auto failureCase = mozilla::MakeScopeExit([&] { xdrEncoder.reset(nullptr); });
|
||||
|
||||
XDRResult res = xdrEncoder->codeFunctionStencil(
|
||||
const_cast<frontend::BaseCompilationStencil&>(stencil));
|
||||
if (res.isErr()) {
|
||||
// On encoding failure, let failureCase destroy encoder and return true
|
||||
// to avoid failing any currently executing script.
|
||||
|
@ -2750,13 +2776,7 @@ bool ScriptSource::xdrFinalizeEncoder(JSContext* cx,
|
|||
auto cleanup = mozilla::MakeScopeExit([&] { xdrEncoder_.reset(nullptr); });
|
||||
|
||||
XDRResult res = xdrEncoder_->linearize(buffer, this);
|
||||
if (res.isErr()) {
|
||||
if (JS::IsTranscodeFailureResult(res.unwrapErr())) {
|
||||
JS_ReportErrorASCII(cx, "XDR encoding failure");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return res.isOk();
|
||||
}
|
||||
|
||||
template <typename Unit>
|
||||
|
@ -3613,7 +3633,7 @@ PrivateScriptData* PrivateScriptData::new_(JSContext* cx, uint32_t ngcthings) {
|
|||
bool PrivateScriptData::InitFromStencil(
|
||||
JSContext* cx, js::HandleScript script,
|
||||
const js::frontend::CompilationInput& input,
|
||||
const js::frontend::CompilationStencil& stencil,
|
||||
const js::frontend::BaseCompilationStencil& stencil,
|
||||
js::frontend::CompilationGCOutput& gcOutput,
|
||||
const js::frontend::ScriptIndex scriptIndex) {
|
||||
js::frontend::ScriptStencil& scriptStencil = stencil.scriptData[scriptIndex];
|
||||
|
@ -3707,7 +3727,7 @@ bool JSScript::createPrivateScriptData(JSContext* cx, HandleScript script,
|
|||
/* static */
|
||||
bool JSScript::fullyInitFromStencil(
|
||||
JSContext* cx, const js::frontend::CompilationInput& input,
|
||||
const js::frontend::CompilationStencil& stencil,
|
||||
const js::frontend::BaseCompilationStencil& stencil,
|
||||
frontend::CompilationGCOutput& gcOutput, HandleScript script,
|
||||
const js::frontend::ScriptIndex scriptIndex) {
|
||||
MutableScriptFlags lazyMutableFlags;
|
||||
|
@ -3761,8 +3781,9 @@ bool JSScript::fullyInitFromStencil(
|
|||
// Note: These flags should already be correct when the BaseScript was
|
||||
// allocated.
|
||||
MOZ_ASSERT_IF(stencil.isInitialStencil(),
|
||||
script->immutableFlags() ==
|
||||
stencil.scriptExtra[scriptIndex].immutableFlags);
|
||||
script->immutableFlags() == stencil.asCompilationStencil()
|
||||
.scriptExtra[scriptIndex]
|
||||
.immutableFlags);
|
||||
|
||||
// Create and initialize PrivateScriptData
|
||||
if (!PrivateScriptData::InitFromStencil(cx, script, input, stencil, gcOutput,
|
||||
|
@ -3775,8 +3796,9 @@ bool JSScript::fullyInitFromStencil(
|
|||
// away.
|
||||
if (script->useMemberInitializers()) {
|
||||
if (stencil.isInitialStencil()) {
|
||||
MemberInitializers initializers(
|
||||
stencil.scriptExtra[scriptIndex].memberInitializers());
|
||||
MemberInitializers initializers(stencil.asCompilationStencil()
|
||||
.scriptExtra[scriptIndex]
|
||||
.memberInitializers());
|
||||
script->setMemberInitializers(initializers);
|
||||
} else {
|
||||
script->setMemberInitializers(lazyData.get()->getMemberInitializers());
|
||||
|
|
|
@ -79,6 +79,7 @@ class DebugScript;
|
|||
|
||||
namespace frontend {
|
||||
struct CompilationStencil;
|
||||
struct BaseCompilationStencil;
|
||||
struct CompilationGCOutput;
|
||||
} // namespace frontend
|
||||
|
||||
|
@ -1014,13 +1015,40 @@ class ScriptSource {
|
|||
// Return wether an XDR encoder is present or not.
|
||||
bool hasEncoder() const { return bool(xdrEncoder_); }
|
||||
|
||||
[[nodiscard]] bool startIncrementalEncoding(
|
||||
JSContext* cx, const JS::ReadOnlyCompileOptions& options,
|
||||
UniquePtr<frontend::ExtensibleCompilationStencil>&& initial);
|
||||
// Create a new XDR encoder, and encode the stencil for the initial
|
||||
// compilation. The created XDR encoder isn't stored into `xdrEncoder_`
|
||||
// field. Caller is responsible for calling `setIncrementalEncoder` after
|
||||
// instantiating stencil (so, corresponding canonical ScriptSourceObject
|
||||
// gets created).
|
||||
bool xdrEncodeInitialStencil(
|
||||
JSContext* cx, frontend::CompilationInput& input,
|
||||
const frontend::CompilationStencil& stencil,
|
||||
UniquePtr<XDRIncrementalStencilEncoder>& xdrEncoder);
|
||||
|
||||
[[nodiscard]] bool addDelazificationToIncrementalEncoding(
|
||||
JSContext* cx, const frontend::CompilationStencil& stencil);
|
||||
// Create a new XDR encoder, and encode the stencils.
|
||||
// The created XDR encoder isn't stored into `xdrEncoder_` field.
|
||||
// Caller is responsible for calling `setIncrementalEncoder` after
|
||||
// instantiating stencil (so, corresponding canonical ScriptSourceObject
|
||||
// gets created).
|
||||
bool xdrEncodeStencils(JSContext* cx, frontend::CompilationInput& input,
|
||||
const frontend::CompilationStencil& stencil,
|
||||
UniquePtr<XDRIncrementalStencilEncoder>& xdrEncoder);
|
||||
|
||||
void setIncrementalEncoder(XDRIncrementalStencilEncoder* xdrEncoder);
|
||||
|
||||
// Encode a delazified function's stencil. In case of errors, the XDR
|
||||
// encoder is freed.
|
||||
bool xdrEncodeFunctionStencil(
|
||||
JSContext* cx, const frontend::BaseCompilationStencil& stencil);
|
||||
|
||||
private:
|
||||
// Encode a delazified function's stencil. In case of errors, the passed
|
||||
// XDR encoder is freed.
|
||||
bool xdrEncodeFunctionStencilWith(
|
||||
JSContext* cx, const frontend::BaseCompilationStencil& stencil,
|
||||
UniquePtr<XDRIncrementalStencilEncoder>& xdrEncoder);
|
||||
|
||||
public:
|
||||
// Linearize the encoded content in the |buffer| provided as argument to
|
||||
// |xdrEncodeTopLevel|, and free the XDR encoder. In case of errors, the
|
||||
// |buffer| is considered undefined.
|
||||
|
@ -1325,11 +1353,12 @@ class alignas(uintptr_t) PrivateScriptData final : public TrailingArray {
|
|||
static bool Clone(JSContext* cx, js::HandleScript src, js::HandleScript dst,
|
||||
js::MutableHandle<JS::GCVector<js::Scope*>> scopes);
|
||||
|
||||
static bool InitFromStencil(JSContext* cx, js::HandleScript script,
|
||||
const js::frontend::CompilationInput& input,
|
||||
const js::frontend::CompilationStencil& stencil,
|
||||
js::frontend::CompilationGCOutput& gcOutput,
|
||||
const js::frontend::ScriptIndex scriptIndex);
|
||||
static bool InitFromStencil(
|
||||
JSContext* cx, js::HandleScript script,
|
||||
const js::frontend::CompilationInput& input,
|
||||
const js::frontend::BaseCompilationStencil& stencil,
|
||||
js::frontend::CompilationGCOutput& gcOutput,
|
||||
const js::frontend::ScriptIndex scriptIndex);
|
||||
|
||||
void trace(JSTracer* trc);
|
||||
|
||||
|
@ -1837,7 +1866,7 @@ class JSScript : public js::BaseScript {
|
|||
friend bool js::PrivateScriptData::InitFromStencil(
|
||||
JSContext* cx, js::HandleScript script,
|
||||
const js::frontend::CompilationInput& input,
|
||||
const js::frontend::CompilationStencil& stencil,
|
||||
const js::frontend::BaseCompilationStencil& stencil,
|
||||
js::frontend::CompilationGCOutput& gcOutput,
|
||||
const js::frontend::ScriptIndex scriptIndex);
|
||||
|
||||
|
@ -1865,7 +1894,7 @@ class JSScript : public js::BaseScript {
|
|||
public:
|
||||
static bool fullyInitFromStencil(
|
||||
JSContext* cx, const js::frontend::CompilationInput& input,
|
||||
const js::frontend::CompilationStencil& stencil,
|
||||
const js::frontend::BaseCompilationStencil& stencil,
|
||||
js::frontend::CompilationGCOutput& gcOutput, js::HandleScript script,
|
||||
const js::frontend::ScriptIndex scriptIndex);
|
||||
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
#include "mozilla/Casting.h" // mozilla::AssertedCast
|
||||
#include "mozilla/Maybe.h" // mozilla::Maybe
|
||||
#include "mozilla/MemoryReporting.h" // mozilla::MallocSizeOf
|
||||
#include "mozilla/Span.h" // mozilla::Span
|
||||
|
||||
#include <algorithm> // std::fill_n
|
||||
#include <stddef.h> // size_t
|
||||
|
@ -58,7 +57,6 @@ class GenericPrinter;
|
|||
|
||||
namespace frontend {
|
||||
struct CompilationAtomCache;
|
||||
struct CompilationStencilMerger;
|
||||
class ScopeStencil;
|
||||
class ParserAtom;
|
||||
} // namespace frontend
|
||||
|
@ -198,10 +196,6 @@ class AbstractBindingName<frontend::TaggedParserAtomIndex> {
|
|||
isTopLevelFunction());
|
||||
}
|
||||
|
||||
void updateNameAfterStencilMerge(TaggedParserAtomIndex name) {
|
||||
bits_ = (bits_ & FlagMask) | name.rawData();
|
||||
}
|
||||
|
||||
private:
|
||||
friend class BaseAbstractBindingIter<TaggedParserAtomIndex>;
|
||||
friend class frontend::ScopeStencil;
|
||||
|
@ -1765,16 +1759,6 @@ inline size_t SizeOfParserScopeData(ScopeKind kind, uint32_t length) {
|
|||
sizeof(AbstractBindingName<frontend::TaggedParserAtomIndex>) * length;
|
||||
}
|
||||
|
||||
inline mozilla::Span<AbstractBindingName<frontend::TaggedParserAtomIndex>>
|
||||
GetParserScopeDataTrailingNames(
|
||||
ScopeKind kind,
|
||||
AbstractBaseScopeData<frontend::TaggedParserAtomIndex>* data) {
|
||||
return mozilla::Span(
|
||||
reinterpret_cast<AbstractBindingName<frontend::TaggedParserAtomIndex>*>(
|
||||
uintptr_t(data) + GetOffsetOfParserScopeDataTrailingNames(kind)),
|
||||
data->length);
|
||||
}
|
||||
|
||||
} // namespace js
|
||||
|
||||
namespace JS {
|
||||
|
|
|
@ -19,9 +19,9 @@
|
|||
|
||||
#include "builtin/ModuleObject.h"
|
||||
#include "debugger/DebugAPI.h"
|
||||
#include "frontend/CompilationStencil.h" // frontend::{CompilationStencil, ExtensibleCompilationStencil, CompilationStencilMerger, BorrowingCompilationStencil}
|
||||
#include "frontend/ParserAtom.h" // frontend::ParserAtom
|
||||
#include "js/BuildId.h" // JS::BuildIdCharVector
|
||||
#include "frontend/CompilationStencil.h" // frontend::BaseCompilationStencil, frontend::CompilationStencil
|
||||
#include "frontend/ParserAtom.h" // frontend::ParserAtom
|
||||
#include "js/BuildId.h" // JS::BuildIdCharVector
|
||||
#include "vm/JSContext.h"
|
||||
#include "vm/JSScript.h"
|
||||
#include "vm/SharedStencil.h" // js::SourceExtent
|
||||
|
@ -291,7 +291,7 @@ static XDRResult XDRAtomCount(XDRState<mode>* xdr, uint32_t* atomCount) {
|
|||
|
||||
template <XDRMode mode>
|
||||
static XDRResult XDRParserAtomTable(XDRState<mode>* xdr,
|
||||
frontend::CompilationStencil& stencil) {
|
||||
frontend::BaseCompilationStencil& stencil) {
|
||||
if (mode == XDR_ENCODE) {
|
||||
uint32_t atomVectorLength = stencil.parserAtomData.size();
|
||||
MOZ_TRY(XDRAtomCount(xdr, &atomVectorLength));
|
||||
|
@ -345,6 +345,11 @@ static XDRResult XDRParserAtomTable(XDRState<mode>* xdr,
|
|||
return Ok();
|
||||
}
|
||||
|
||||
template <XDRMode mode>
|
||||
static XDRResult XDRChunkCount(XDRState<mode>* xdr, uint32_t* sliceCount) {
|
||||
return xdr->codeUint32(sliceCount);
|
||||
}
|
||||
|
||||
template <XDRMode mode>
|
||||
XDRResult XDRState<mode>::codeScript(MutableHandleScript scriptp) {
|
||||
TraceLoggerThread* logger = TraceLoggerForCurrentThread(cx());
|
||||
|
@ -374,104 +379,73 @@ XDRResult XDRState<mode>::codeScript(MutableHandleScript scriptp) {
|
|||
template <XDRMode mode>
|
||||
static XDRResult XDRStencilHeader(
|
||||
XDRState<mode>* xdr, const JS::ReadOnlyCompileOptions* maybeOptions,
|
||||
RefPtr<ScriptSource>& source) {
|
||||
RefPtr<ScriptSource>& source, uint32_t* pNumChunks) {
|
||||
// The XDR-Stencil header is inserted at beginning of buffer, but it is
|
||||
// computed at the end the incremental-encoding process.
|
||||
|
||||
MOZ_TRY(VersionCheck(xdr, XDRFormatType::Stencil));
|
||||
MOZ_TRY(ScriptSource::XDR(xdr, maybeOptions, source));
|
||||
MOZ_TRY(XDRChunkCount(xdr, pNumChunks));
|
||||
MOZ_TRY(xdr->align32());
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
template <XDRMode mode>
|
||||
XDRResult XDRState<mode>::codeStencil(frontend::CompilationInput& input,
|
||||
frontend::CompilationStencil& stencil) {
|
||||
#ifdef DEBUG
|
||||
auto sanityCheck = mozilla::MakeScopeExit(
|
||||
[&] { MOZ_ASSERT(validateResultCode(cx(), resultCode())); });
|
||||
#endif
|
||||
|
||||
// Instrumented scripts cannot be encoded, as they have extra instructions
|
||||
// which are not normally present. Globals with instrumentation enabled must
|
||||
// compile scripts via the bytecode emitter, which will insert these
|
||||
// instructions.
|
||||
if (mode == XDR_ENCODE) {
|
||||
if (!!input.options.instrumentationKinds) {
|
||||
return fail(JS::TranscodeResult::Failure);
|
||||
}
|
||||
}
|
||||
|
||||
// Process the header now if decoding. If we are encoding, we defer generating
|
||||
// the header data until the `linearize` call, but still prepend it to final
|
||||
// buffer before giving to the caller.
|
||||
if (mode == XDR_DECODE) {
|
||||
MOZ_TRY(XDRStencilHeader(this, &input.options, stencil.source, &nchunks()));
|
||||
}
|
||||
|
||||
MOZ_TRY(XDRParserAtomTable(this, stencil));
|
||||
MOZ_TRY(XDRCompilationStencil(this, stencil));
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
template <XDRMode mode>
|
||||
XDRResult XDRState<mode>::codeFunctionStencil(
|
||||
frontend::BaseCompilationStencil& stencil) {
|
||||
#ifdef DEBUG
|
||||
auto sanityCheck = mozilla::MakeScopeExit(
|
||||
[&] { MOZ_ASSERT(validateResultCode(cx(), resultCode())); });
|
||||
#endif
|
||||
bool isAlreadyCoded = false;
|
||||
MOZ_TRY_VAR(isAlreadyCoded, checkAlreadyCoded(stencil));
|
||||
if (isAlreadyCoded) {
|
||||
return Ok();
|
||||
}
|
||||
|
||||
MOZ_TRY(XDRParserAtomTable(this, stencil));
|
||||
MOZ_TRY(XDRBaseCompilationStencil(this, stencil));
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
template class js::XDRState<XDR_ENCODE>;
|
||||
template class js::XDRState<XDR_DECODE>;
|
||||
|
||||
static bool IsOptionCompatibleWithEncoding(
|
||||
const JS::ReadOnlyCompileOptions& options) {
|
||||
// Instrumented scripts cannot be encoded, as they have extra instructions
|
||||
// which are not normally present. Globals with instrumentation enabled must
|
||||
// compile scripts via the bytecode emitter, which will insert these
|
||||
// instructions.
|
||||
return !options.instrumentationKinds;
|
||||
}
|
||||
|
||||
XDRResult XDRStencilEncoder::codeStencil(
|
||||
frontend::CompilationInput& input, frontend::CompilationStencil& stencil) {
|
||||
#ifdef DEBUG
|
||||
auto sanityCheck = mozilla::MakeScopeExit(
|
||||
[&] { MOZ_ASSERT(validateResultCode(cx(), resultCode())); });
|
||||
#endif
|
||||
|
||||
if (!IsOptionCompatibleWithEncoding(input.options)) {
|
||||
return fail(JS::TranscodeResult::Failure);
|
||||
}
|
||||
|
||||
MOZ_TRY(XDRCheckCompilationStencil(this, stencil));
|
||||
|
||||
MOZ_TRY(XDRStencilHeader(this, &input.options, stencil.source));
|
||||
MOZ_TRY(XDRParserAtomTable(this, stencil));
|
||||
MOZ_TRY(XDRCompilationStencil(this, stencil));
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
XDRIncrementalStencilEncoder::~XDRIncrementalStencilEncoder() {
|
||||
if (merger_) {
|
||||
js_delete(merger_);
|
||||
}
|
||||
}
|
||||
|
||||
XDRResult XDRIncrementalStencilEncoder::setInitial(
|
||||
const JS::ReadOnlyCompileOptions& options,
|
||||
UniquePtr<frontend::ExtensibleCompilationStencil>&& initial) {
|
||||
#ifdef DEBUG
|
||||
auto sanityCheck = mozilla::MakeScopeExit(
|
||||
[&] { MOZ_ASSERT(validateResultCode(cx(), resultCode())); });
|
||||
#endif
|
||||
|
||||
if (!IsOptionCompatibleWithEncoding(options)) {
|
||||
return fail(JS::TranscodeResult::Failure);
|
||||
}
|
||||
|
||||
MOZ_TRY(XDRCheckCompilationStencil(this, *initial));
|
||||
|
||||
merger_ = cx()->new_<frontend::CompilationStencilMerger>();
|
||||
if (!merger_) {
|
||||
return fail(JS::TranscodeResult::Throw);
|
||||
}
|
||||
|
||||
if (!merger_->setInitial(
|
||||
cx(), std::forward<UniquePtr<frontend::ExtensibleCompilationStencil>>(
|
||||
initial))) {
|
||||
return fail(JS::TranscodeResult::Throw);
|
||||
}
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
XDRResult XDRIncrementalStencilEncoder::addDelazification(
|
||||
const frontend::CompilationStencil& delazification) {
|
||||
#ifdef DEBUG
|
||||
auto sanityCheck = mozilla::MakeScopeExit(
|
||||
[&] { MOZ_ASSERT(validateResultCode(cx(), resultCode())); });
|
||||
#endif
|
||||
|
||||
if (!merger_->addDelazification(cx(), delazification)) {
|
||||
return fail(JS::TranscodeResult::Throw);
|
||||
}
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
XDRResult XDRIncrementalStencilEncoder::linearize(JS::TranscodeBuffer& buffer,
|
||||
ScriptSource* ss) {
|
||||
#ifdef DEBUG
|
||||
auto sanityCheck = mozilla::MakeScopeExit(
|
||||
[&] { MOZ_ASSERT(validateResultCode(cx(), resultCode())); });
|
||||
#endif
|
||||
|
||||
// NOTE: If buffer is empty, buffer.begin() doesn't point valid buffer.
|
||||
MOZ_ASSERT_IF(!buffer.empty(),
|
||||
JS::IsTranscodingBytecodeAligned(buffer.begin()));
|
||||
|
@ -481,40 +455,105 @@ XDRResult XDRIncrementalStencilEncoder::linearize(JS::TranscodeBuffer& buffer,
|
|||
// the buffer so ensure we skip over it.
|
||||
XDRBuffer<XDR_ENCODE> outputBuf(cx(), buffer, buffer.length());
|
||||
|
||||
switchToBuffer(&outputBuf);
|
||||
|
||||
RefPtr<ScriptSource> source(ss);
|
||||
MOZ_TRY(XDRStencilHeader(this, nullptr, source));
|
||||
|
||||
// Code the header directly in the output buffer.
|
||||
{
|
||||
frontend::BorrowingCompilationStencil borrowingStencil(
|
||||
merger_->getResult());
|
||||
MOZ_TRY(XDRParserAtomTable(this, borrowingStencil));
|
||||
MOZ_TRY(XDRCompilationStencil(this, borrowingStencil));
|
||||
switchToBuffer(&outputBuf);
|
||||
|
||||
RefPtr<ScriptSource> source(ss);
|
||||
uint32_t nchunks = 1 + encodedFunctions_.count();
|
||||
MOZ_TRY(XDRStencilHeader(this, nullptr, source, &nchunks));
|
||||
|
||||
switchToBuffer(&mainBuf);
|
||||
}
|
||||
|
||||
switchToBuffer(&mainBuf);
|
||||
// The accumlated transcode data can now be copied to the output buffer.
|
||||
if (!buffer.append(slices_.begin(), slices_.length())) {
|
||||
return fail(JS::TranscodeResult::Throw);
|
||||
}
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
void XDRDecoder::trace(JSTracer* trc) { atomTable_.trace(trc); }
|
||||
|
||||
XDRResult XDRStencilDecoder::codeStencil(
|
||||
XDRResult XDRStencilDecoder::codeStencils(
|
||||
frontend::CompilationInput& input, frontend::CompilationStencil& stencil) {
|
||||
#ifdef DEBUG
|
||||
auto sanityCheck = mozilla::MakeScopeExit(
|
||||
[&] { MOZ_ASSERT(validateResultCode(cx(), resultCode())); });
|
||||
#endif
|
||||
MOZ_ASSERT(!stencil.delazificationSet);
|
||||
|
||||
frontend::ParserAtomSpanBuilder parserAtomBuilder(cx()->runtime(),
|
||||
stencil.parserAtomData);
|
||||
parserAtomBuilder_ = &parserAtomBuilder;
|
||||
stencilAlloc_ = &stencil.alloc;
|
||||
|
||||
MOZ_TRY(XDRStencilHeader(this, &input.options, stencil.source));
|
||||
MOZ_TRY(XDRParserAtomTable(this, stencil));
|
||||
MOZ_TRY(XDRCompilationStencil(this, stencil));
|
||||
MOZ_TRY(codeStencil(input, stencil));
|
||||
|
||||
// Decode any delazification stencil from XDR.
|
||||
if (nchunks_ > 1) {
|
||||
auto delazificationSet = MakeUnique<frontend::StencilDelazificationSet>();
|
||||
if (!delazificationSet) {
|
||||
ReportOutOfMemory(cx());
|
||||
return fail(JS::TranscodeResult::Throw);
|
||||
}
|
||||
|
||||
if (!delazificationSet->delazifications.reserve(nchunks_ - 1)) {
|
||||
ReportOutOfMemory(cx());
|
||||
return fail(JS::TranscodeResult::Throw);
|
||||
}
|
||||
|
||||
for (size_t i = 1; i < nchunks_; i++) {
|
||||
delazificationSet->delazifications.infallibleEmplaceBack();
|
||||
auto& delazification = delazificationSet->delazifications[i - 1];
|
||||
|
||||
hasFinishedAtomTable_ = false;
|
||||
|
||||
frontend::ParserAtomSpanBuilder parserAtomBuilder(
|
||||
cx()->runtime(), delazification.parserAtomData);
|
||||
parserAtomBuilder_ = &parserAtomBuilder;
|
||||
|
||||
MOZ_TRY(codeFunctionStencil(delazification));
|
||||
}
|
||||
|
||||
// NOTE: This also computes the `max*DataLength` values.
|
||||
if (!delazificationSet->buildDelazificationIndices(cx(), stencil)) {
|
||||
return fail(JS::TranscodeResult::Throw);
|
||||
}
|
||||
|
||||
stencil.delazificationSet = std::move(delazificationSet);
|
||||
}
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
XDRResult XDRIncrementalStencilEncoder::codeStencils(
|
||||
frontend::CompilationInput& input, frontend::CompilationStencil& stencil) {
|
||||
MOZ_ASSERT(encodedFunctions_.count() == 0);
|
||||
|
||||
MOZ_TRY(codeStencil(input, stencil));
|
||||
|
||||
if (stencil.delazificationSet) {
|
||||
for (auto& delazification : stencil.delazificationSet->delazifications) {
|
||||
MOZ_TRY(codeFunctionStencil(delazification));
|
||||
}
|
||||
}
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
XDRResultT<bool> XDRIncrementalStencilEncoder::checkAlreadyCoded(
|
||||
const frontend::BaseCompilationStencil& stencil) {
|
||||
static_assert(std::is_same_v<frontend::BaseCompilationStencil::FunctionKey,
|
||||
XDRIncrementalStencilEncoder::FunctionKey>);
|
||||
|
||||
auto key = stencil.functionKey;
|
||||
auto p = encodedFunctions_.lookupForAdd(key);
|
||||
if (p) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!encodedFunctions_.add(p, key)) {
|
||||
ReportOutOfMemory(cx());
|
||||
return fail<bool>(JS::TranscodeResult::Throw);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
201
js/src/vm/Xdr.h
201
js/src/vm/Xdr.h
|
@ -29,9 +29,8 @@ struct SourceExtent;
|
|||
|
||||
namespace frontend {
|
||||
struct CompilationStencil;
|
||||
struct ExtensibleCompilationStencil;
|
||||
struct CompilationStencilMerger;
|
||||
struct CompilationInput;
|
||||
struct BaseCompilationStencil;
|
||||
} // namespace frontend
|
||||
|
||||
class LifoAlloc;
|
||||
|
@ -225,6 +224,11 @@ class XDRState : public XDRCoderBase {
|
|||
virtual ~XDRState() = default;
|
||||
|
||||
JSContext* cx() const { return mainBuf.cx(); }
|
||||
virtual bool isForStencil() const { return false; }
|
||||
virtual XDRResultT<bool> checkAlreadyCoded(
|
||||
const frontend::BaseCompilationStencil& stencil) {
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool isMultiDecode() const { return false; }
|
||||
|
||||
|
@ -237,6 +241,9 @@ class XDRState : public XDRCoderBase {
|
|||
MOZ_CRASH("does not have scriptSourceObjectOut.");
|
||||
}
|
||||
|
||||
// The number of chunks (BaseCompilationStencils) in the buffer.
|
||||
virtual uint32_t& nchunks() { MOZ_CRASH("does not have nchunks."); }
|
||||
|
||||
virtual bool hasAtomTable() const { return false; }
|
||||
virtual XDRAtomTable& atomTable() { MOZ_CRASH("does not have atomTable"); }
|
||||
virtual frontend::ParserAtomSpanBuilder& frontendAtoms() {
|
||||
|
@ -245,6 +252,11 @@ class XDRState : public XDRCoderBase {
|
|||
virtual LifoAlloc& stencilAlloc() { MOZ_CRASH("does not have stencilAlloc"); }
|
||||
virtual void finishAtomTable() { MOZ_CRASH("does not have atomTable"); }
|
||||
|
||||
virtual XDRResult codeDelazificationStencils(
|
||||
frontend::CompilationStencil& stencil) {
|
||||
MOZ_CRASH("cannot code delazification stencils.");
|
||||
}
|
||||
|
||||
template <typename T = mozilla::Ok>
|
||||
XDRResultT<T> fail(JS::TranscodeResult code) {
|
||||
#ifdef DEBUG
|
||||
|
@ -474,6 +486,9 @@ class XDRState : public XDRCoderBase {
|
|||
|
||||
XDRResult codeModuleObject(MutableHandleModuleObject modp);
|
||||
XDRResult codeScript(MutableHandleScript scriptp);
|
||||
XDRResult codeStencil(frontend::CompilationInput& input,
|
||||
frontend::CompilationStencil& stencil);
|
||||
XDRResult codeFunctionStencil(frontend::BaseCompilationStencil& stencil);
|
||||
};
|
||||
|
||||
using XDREncoder = XDRState<XDR_ENCODE>;
|
||||
|
@ -509,6 +524,60 @@ class XDRDecoder : public XDRDecoderBase {
|
|||
bool hasFinishedAtomTable_ = false;
|
||||
};
|
||||
|
||||
/*
|
||||
* The stencil decoder accepts `options` and `range` as input, along
|
||||
* with a freshly initialized `parserAtoms` table.
|
||||
*
|
||||
* The decoded stencils are outputted to the default-initialized
|
||||
* `stencil` parameter of `codeStencil` method, and decoded atoms are
|
||||
* interned into the `parserAtoms` parameter of the ctor.
|
||||
*
|
||||
* The decoded stencils borrow the input `buffer`/`range`, and the consumer
|
||||
* has to keep the buffer alive while the decoded stencils are alive.
|
||||
*/
|
||||
class XDRStencilDecoder : public XDRDecoderBase {
|
||||
uint32_t nchunks_ = 0;
|
||||
|
||||
public:
|
||||
XDRStencilDecoder(JSContext* cx, const JS::ReadOnlyCompileOptions* options,
|
||||
JS::TranscodeBuffer& buffer, size_t cursor)
|
||||
: XDRDecoderBase(cx, buffer, cursor), options_(options) {
|
||||
MOZ_ASSERT(JS::IsTranscodingBytecodeAligned(buffer.begin()));
|
||||
MOZ_ASSERT(JS::IsTranscodingBytecodeOffsetAligned(cursor));
|
||||
MOZ_ASSERT(options_);
|
||||
}
|
||||
|
||||
XDRStencilDecoder(JSContext* cx, const JS::ReadOnlyCompileOptions* options,
|
||||
const JS::TranscodeRange& range)
|
||||
: XDRDecoderBase(cx, range), options_(options) {
|
||||
MOZ_ASSERT(JS::IsTranscodingBytecodeAligned(range.begin().get()));
|
||||
MOZ_ASSERT(options_);
|
||||
}
|
||||
|
||||
uint32_t& nchunks() override { return nchunks_; }
|
||||
|
||||
bool isForStencil() const override { return true; }
|
||||
|
||||
bool hasAtomTable() const override { return hasFinishedAtomTable_; }
|
||||
frontend::ParserAtomSpanBuilder& frontendAtoms() override {
|
||||
return *parserAtomBuilder_;
|
||||
}
|
||||
LifoAlloc& stencilAlloc() override { return *stencilAlloc_; }
|
||||
void finishAtomTable() override { hasFinishedAtomTable_ = true; }
|
||||
|
||||
bool hasOptions() const override { return true; }
|
||||
const JS::ReadOnlyCompileOptions& options() override { return *options_; }
|
||||
|
||||
XDRResult codeStencils(frontend::CompilationInput& input,
|
||||
frontend::CompilationStencil& stencil);
|
||||
|
||||
private:
|
||||
const JS::ReadOnlyCompileOptions* options_;
|
||||
bool hasFinishedAtomTable_ = false;
|
||||
frontend::ParserAtomSpanBuilder* parserAtomBuilder_ = nullptr;
|
||||
LifoAlloc* stencilAlloc_ = nullptr;
|
||||
};
|
||||
|
||||
class XDROffThreadDecoder : public XDRDecoder {
|
||||
ScriptSourceObject** sourceObjectOut_;
|
||||
bool isMultiDecode_;
|
||||
|
@ -545,100 +614,46 @@ class XDROffThreadDecoder : public XDRDecoder {
|
|||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* The structure of the Stencil XDR buffer is:
|
||||
*
|
||||
* 1. Header
|
||||
* a. Version
|
||||
* b. ScriptSource
|
||||
* d. Alignment padding
|
||||
* 2. Stencil
|
||||
* a. ParseAtomTable
|
||||
* b. CompilationStencil
|
||||
*/
|
||||
|
||||
/*
|
||||
* The stencil decoder accepts `options` and `range` as input, along
|
||||
* with a freshly initialized `parserAtoms` table.
|
||||
*
|
||||
* The decoded stencils are outputted to the default-initialized
|
||||
* `stencil` parameter of `codeStencil` method, and decoded atoms are
|
||||
* interned into the `parserAtoms` parameter of the ctor.
|
||||
*
|
||||
* The decoded stencils borrow the input `buffer`/`range`, and the consumer
|
||||
* has to keep the buffer alive while the decoded stencils are alive.
|
||||
*/
|
||||
class XDRStencilDecoder : public XDRDecoderBase {
|
||||
public:
|
||||
XDRStencilDecoder(JSContext* cx, const JS::ReadOnlyCompileOptions* options,
|
||||
JS::TranscodeBuffer& buffer, size_t cursor)
|
||||
: XDRDecoderBase(cx, buffer, cursor), options_(options) {
|
||||
MOZ_ASSERT(JS::IsTranscodingBytecodeAligned(buffer.begin()));
|
||||
MOZ_ASSERT(JS::IsTranscodingBytecodeOffsetAligned(cursor));
|
||||
MOZ_ASSERT(options_);
|
||||
}
|
||||
|
||||
XDRStencilDecoder(JSContext* cx, const JS::ReadOnlyCompileOptions* options,
|
||||
const JS::TranscodeRange& range)
|
||||
: XDRDecoderBase(cx, range), options_(options) {
|
||||
MOZ_ASSERT(JS::IsTranscodingBytecodeAligned(range.begin().get()));
|
||||
MOZ_ASSERT(options_);
|
||||
}
|
||||
|
||||
bool hasAtomTable() const override { return hasFinishedAtomTable_; }
|
||||
frontend::ParserAtomSpanBuilder& frontendAtoms() override {
|
||||
return *parserAtomBuilder_;
|
||||
}
|
||||
LifoAlloc& stencilAlloc() override { return *stencilAlloc_; }
|
||||
void finishAtomTable() override { hasFinishedAtomTable_ = true; }
|
||||
|
||||
bool hasOptions() const override { return true; }
|
||||
const JS::ReadOnlyCompileOptions& options() override { return *options_; }
|
||||
|
||||
XDRResult codeStencil(frontend::CompilationInput& input,
|
||||
frontend::CompilationStencil& stencil);
|
||||
|
||||
private:
|
||||
const JS::ReadOnlyCompileOptions* options_;
|
||||
bool hasFinishedAtomTable_ = false;
|
||||
frontend::ParserAtomSpanBuilder* parserAtomBuilder_ = nullptr;
|
||||
LifoAlloc* stencilAlloc_ = nullptr;
|
||||
};
|
||||
|
||||
class XDRStencilEncoder : public XDREncoder {
|
||||
public:
|
||||
explicit XDRStencilEncoder(JSContext* cx, JS::TranscodeBuffer& buffer)
|
||||
: XDREncoder(cx, buffer, 0) {
|
||||
// NOTE: If buffer is empty, buffer.begin() doesn't point valid buffer.
|
||||
MOZ_ASSERT_IF(!buffer.empty(),
|
||||
JS::IsTranscodingBytecodeAligned(buffer.begin()));
|
||||
MOZ_ASSERT(JS::IsTranscodingBytecodeOffsetAligned(buffer.length()));
|
||||
}
|
||||
|
||||
XDRResult codeStencil(frontend::CompilationInput& input,
|
||||
frontend::CompilationStencil& stencil);
|
||||
};
|
||||
|
||||
class XDRIncrementalStencilEncoder : public XDREncoder {
|
||||
// The target buffer isn't available until linearize.
|
||||
// Hold dummy buffer to initialize XDREncoder.
|
||||
JS::TranscodeBuffer dummy_;
|
||||
// The structure of the resulting buffer is:
|
||||
//
|
||||
// 1. Header
|
||||
// a. Version
|
||||
// b. ScriptSource
|
||||
// c. Chunk count
|
||||
// d. Alignment padding
|
||||
// 2. Initial Chunk
|
||||
// a. ParseAtomTable
|
||||
// b. BaseCompilationStencil
|
||||
// c. ScriptStencilExtra[]
|
||||
// d. StencilModuleMetadata (if exists)
|
||||
// 3. Array of Delazification Chunks
|
||||
// a. ParseAtomTable
|
||||
// b. BaseCompilationStencil
|
||||
|
||||
frontend::CompilationStencilMerger* merger_ = nullptr;
|
||||
JS::TranscodeBuffer slices_;
|
||||
|
||||
// A set of functions that is passed to codeFunctionStencil.
|
||||
// Used to avoid encoding delazification for same function twice.
|
||||
// NOTE: This is not a set of all encoded functions.
|
||||
using FunctionKey = uint32_t;
|
||||
HashSet<FunctionKey> encodedFunctions_;
|
||||
|
||||
public:
|
||||
explicit XDRIncrementalStencilEncoder(JSContext* cx)
|
||||
: XDREncoder(cx, dummy_, 0) {}
|
||||
: XDREncoder(cx, slices_, 0), encodedFunctions_(cx) {}
|
||||
|
||||
virtual ~XDRIncrementalStencilEncoder();
|
||||
virtual ~XDRIncrementalStencilEncoder() = default;
|
||||
|
||||
XDRResultT<bool> checkAlreadyCoded(
|
||||
const frontend::BaseCompilationStencil& stencil) override;
|
||||
|
||||
bool isForStencil() const override { return true; }
|
||||
|
||||
XDRResult linearize(JS::TranscodeBuffer& buffer, js::ScriptSource* ss);
|
||||
|
||||
XDRResult setInitial(
|
||||
const JS::ReadOnlyCompileOptions& options,
|
||||
UniquePtr<frontend::ExtensibleCompilationStencil>&& initial);
|
||||
XDRResult addDelazification(
|
||||
const frontend::CompilationStencil& delazification);
|
||||
XDRResult codeStencils(frontend::CompilationInput& input,
|
||||
frontend::CompilationStencil& stencil);
|
||||
|
||||
private:
|
||||
void switchToBuffer(XDRBuffer<XDR_ENCODE>* target) { buf = target; }
|
||||
|
@ -656,18 +671,14 @@ XDRResult XDRAtomData(XDRState<mode>* xdr, js::MutableHandleAtom atomp);
|
|||
template <XDRMode mode>
|
||||
XDRResult XDRParserAtom(XDRState<mode>* xdr, frontend::ParserAtom** atomp);
|
||||
|
||||
template <XDRMode mode>
|
||||
XDRResult XDRBaseCompilationStencil(XDRState<mode>* xdr,
|
||||
frontend::BaseCompilationStencil& stencil);
|
||||
|
||||
template <XDRMode mode>
|
||||
XDRResult XDRCompilationStencil(XDRState<mode>* xdr,
|
||||
frontend::CompilationStencil& stencil);
|
||||
|
||||
template <XDRMode mode>
|
||||
XDRResult XDRCheckCompilationStencil(XDRState<mode>* xdr,
|
||||
frontend::CompilationStencil& stencil);
|
||||
|
||||
template <XDRMode mode>
|
||||
XDRResult XDRCheckCompilationStencil(
|
||||
XDRState<mode>* xdr, frontend::ExtensibleCompilationStencil& stencil);
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
#endif /* vm_Xdr_h */
|
||||
|
|
Загрузка…
Ссылка в новой задаче