Bug 1899090 - Part 2: Rebuild the incremental encoding with InitialStencilAndDelazifications. r=nbp

Create InitialStencilAndDelazifications and associate it to ScriptSourceObject,
and store on-demand delazifications into the InitialStencilAndDelazifications.

InitialStencilAndDelazifications is merged into single CompilationStencil when
finishing, but the JS::Stencil-based API is going to be rewritten later not
to merge.

Differential Revision: https://phabricator.services.mozilla.com/D230378
This commit is contained in:
Tooru Fujisawa
2024-12-04 00:54:44 +00:00
parent 1f8fbee7b9
commit c1b8d7b50e
12 changed files with 274 additions and 262 deletions

View File

@@ -236,7 +236,7 @@ nsresult ModuleLoader::CompileJavaScriptModule(
if (aRequest->IsTextSource() &&
aRequest->PassedConditionForBytecodeEncoding()) {
bool alreadyStarted;
if (!JS::StartIncrementalEncoding(aCx, std::move(stencil),
if (!JS::StartIncrementalEncoding(aCx, aModuleOut, stencil,
alreadyStarted)) {
return NS_ERROR_FAILURE;
}
@@ -284,7 +284,7 @@ nsresult ModuleLoader::CompileJavaScriptModule(
if (aRequest->IsTextSource() &&
aRequest->PassedConditionForBytecodeEncoding()) {
bool alreadyStarted;
if (!JS::StartIncrementalEncoding(aCx, std::move(stencil),
if (!JS::StartIncrementalEncoding(aCx, aModuleOut, stencil,
alreadyStarted)) {
return NS_ERROR_FAILURE;
}

View File

@@ -2762,7 +2762,7 @@ static void InstantiateStencil(
}
if (aEncodeBytecode) {
if (!JS::StartIncrementalEncoding(aCx, std::move(aStencil),
if (!JS::StartIncrementalEncoding(aCx, script, aStencil,
incrementalEncodingAlreadyStarted)) {
aRv.NoteJSContextException(aCx);
return;

View File

@@ -205,14 +205,20 @@ extern JS_PUBLIC_API TranscodeResult
DecodeStencil(JS::FrontendContext* fc, const ReadOnlyDecodeOptions& options,
const TranscodeRange& range, Stencil** stencilOut);
// Register an encoder on its script source, such that all functions can be
// encoded as they are delazified.
// Start collecting delazifications for given script or module's source object.
//
// If the incremental encoding is already started for given stencil's script
// source, alreadyStarted is set to true and returns true.
// alreadyStarted is set to false otherwise.
// If the source object is already collecting delazifications, alreadyStarted is
// set to true and returns true. alreadyStarted is set to false otherwise.
//
// TODO: Rename public APIs.
extern JS_PUBLIC_API bool StartIncrementalEncoding(JSContext* cx,
RefPtr<Stencil>&& stencil,
JS::Handle<JSScript*> script,
Stencil* stencil,
bool& alreadyStarted);
extern JS_PUBLIC_API bool StartIncrementalEncoding(JSContext* cx,
JS::Handle<JSObject*> module,
Stencil* stencil,
bool& alreadyStarted);
} // namespace JS

View File

@@ -1330,7 +1330,7 @@ ModuleObject* frontend::CompileModule(JSContext* cx, FrontendContext* fc,
}
static bool InstantiateLazyFunction(JSContext* cx, CompilationInput& input,
CompilationStencil& stencil,
const CompilationStencil& stencil,
BytecodeCompilerOutput& output) {
// We do check the type, but do not write anything to it as this is not
// necessary for lazy function, as the script is patched inside the
@@ -1343,12 +1343,6 @@ static bool InstantiateLazyFunction(JSContext* cx, CompilationInput& input,
Rooted<CompilationGCOutput> gcOutput(cx);
if (input.source->hasEncoder()) {
if (!input.source->addDelazificationToIncrementalEncoding(cx, stencil)) {
return false;
}
}
if (!CompilationStencil::instantiateStencils(cx, input, stencil,
gcOutput.get())) {
return false;
@@ -1410,6 +1404,11 @@ static GetCachedResult GetCachedLazyFunctionStencilMaybeInstantiate(
MOZ_ASSERT(maybeCx);
// NOTE: The concurrent delazification case doesn't store the delazification
// to the script source right now. This will be changed once the
// concurrent delazification is refactored to directly use the
// InitialStencilAndDelazifications.
if (!InstantiateLazyFunction(maybeCx, input, *stencil, output)) {
return GetCachedResult::Error;
}
@@ -1539,9 +1538,35 @@ static bool CompileLazyFunctionToStencilMaybeInstantiate(
output.as<RefPtr<CompilationStencil>>() = std::move(stencil);
} else {
MOZ_ASSERT(maybeCx);
BorrowingCompilationStencil borrowingStencil(compilationState);
if (!InstantiateLazyFunction(maybeCx, input, borrowingStencil, output)) {
return false;
if (input.lazyOuterScript().sourceObject() &&
input.lazyOuterScript().sourceObject()->maybeGetStencils()) {
RefPtr<frontend::InitialStencilAndDelazifications> stencils =
input.lazyOuterScript().sourceObject()->maybeGetStencils();
auto extensibleStencil =
maybeCx->make_unique<frontend::ExtensibleCompilationStencil>(
std::move(compilationState));
if (!extensibleStencil) {
return false;
}
RefPtr<CompilationStencil> stencil =
maybeCx->new_<CompilationStencil>(std::move(extensibleStencil));
if (!stencil) {
return false;
}
const CompilationStencil* borrowed =
stencils->storeDelazification(std::move(stencil));
if (!InstantiateLazyFunction(maybeCx, input, *borrowed, output)) {
return false;
}
} else {
BorrowingCompilationStencil borrowingStencil(compilationState);
if (!InstantiateLazyFunction(maybeCx, input, borrowingStencil, output)) {
return false;
}
}
}

View File

@@ -341,7 +341,15 @@ class InputScript {
bool isStencil() const {
return script_.match([](const BaseScript* ptr) { return false; },
[](const ScriptStencilRef&) { return true; });
};
}
ScriptSourceObject* sourceObject() const {
return script_.match(
[](const BaseScript* ptr) { return ptr->sourceObject(); },
[](const ScriptStencilRef&) {
return static_cast<ScriptSourceObject*>(nullptr);
});
}
};
// Iterator for walking the scope chain, this is identical to ScopeIter but

View File

@@ -1483,35 +1483,6 @@ JS::TranscodeResult JS::EncodeStencil(JSContext* cx, JS::Stencil* stencil,
return JS::TranscodeResult::Ok;
}
void StencilIncrementalEncoderPtr::reset() {
if (merger_) {
js_delete(merger_);
}
merger_ = nullptr;
}
bool StencilIncrementalEncoderPtr::setInitial(
JSContext* cx,
UniquePtr<frontend::ExtensibleCompilationStencil>&& initial) {
MOZ_ASSERT(!merger_);
AutoReportFrontendContext fc(cx);
merger_ = fc.getAllocator()->new_<frontend::CompilationStencilMerger>();
if (!merger_) {
return false;
}
return merger_->setInitial(
&fc,
std::forward<UniquePtr<frontend::ExtensibleCompilationStencil>>(initial));
}
bool StencilIncrementalEncoderPtr::addDelazification(
JSContext* cx, const frontend::CompilationStencil& delazification) {
AutoReportFrontendContext fc(cx);
return merger_->addDelazification(&fc, delazification);
}
XDRResult XDRStencilDecoder::codeStencil(
const JS::ReadOnlyDecodeOptions& options,
frontend::CompilationStencil& stencil) {

View File

@@ -15,5 +15,6 @@ try {
evalWithCache(test, {});
} catch (x) {
assertEq(x.message.includes("Asm.js is not supported by XDR") ||
x.message.includes("Not collecting delazifications") ||
x.message.includes("XDR encoding failure"), true);
}

View File

@@ -4876,53 +4876,6 @@ JS_PUBLIC_API void JS::detail::AssertArgumentsAreSane(JSContext* cx,
}
#endif /* JS_DEBUG */
JS_PUBLIC_API bool JS::FinishIncrementalEncoding(JSContext* cx,
JS::HandleScript script,
TranscodeBuffer& buffer) {
if (!script) {
return false;
}
if (!script->scriptSource()->xdrFinalizeEncoder(cx, buffer)) {
return false;
}
return true;
}
JS_PUBLIC_API bool JS::FinishIncrementalEncoding(JSContext* cx,
JS::HandleScript script,
JS::Stencil** stencilOut) {
if (!script) {
return false;
}
if (!script->scriptSource()->xdrFinalizeEncoder(cx, stencilOut)) {
return false;
}
return true;
}
JS_PUBLIC_API bool JS::FinishIncrementalEncoding(JSContext* cx,
JS::Handle<JSObject*> module,
TranscodeBuffer& buffer) {
if (!module->as<ModuleObject>()
.scriptSourceObject()
->source()
->xdrFinalizeEncoder(cx, buffer)) {
return false;
}
return true;
}
JS_PUBLIC_API void JS::AbortIncrementalEncoding(JS::HandleScript script) {
if (!script) {
return;
}
script->scriptSource()->xdrAbortEncoder();
}
JS_PUBLIC_API void JS::AbortIncrementalEncoding(JS::Handle<JSObject*> module) {
module->as<ModuleObject>().scriptSourceObject()->source()->xdrAbortEncoder();
}
bool JS::IsWasmModuleObject(HandleObject obj) {
return obj->canUnwrapAs<WasmModuleObject>();
}

View File

@@ -2900,8 +2900,7 @@ static bool Evaluate(JSContext* cx, unsigned argc, Value* vp) {
if (saveIncrementalBytecode) {
bool alreadyStarted;
if (!JS::StartIncrementalEncoding(cx, std::move(stencil),
alreadyStarted)) {
if (!JS::StartIncrementalEncoding(cx, script, stencil, alreadyStarted)) {
return false;
}
MOZ_ASSERT(!alreadyStarted);

View File

@@ -18,9 +18,10 @@
#include "debugger/DebugAPI.h"
#include "frontend/BytecodeCompiler.h" // frontend::{CompileGlobalScript, CompileStandaloneFunction, CompileStandaloneFunctionInNonSyntacticScope}
#include "frontend/CompilationStencil.h" // for frontened::{CompilationStencil, BorrowingCompilationStencil, CompilationGCOutput}
#include "frontend/CompilationStencil.h" // for frontened::{CompilationStencil, BorrowingCompilationStencil, CompilationGCOutput, InitialStencilAndDelazifications}
#include "frontend/FrontendContext.h" // js::AutoReportFrontendContext
#include "frontend/Parser.h" // frontend::Parser, frontend::ParseGoal
#include "frontend/Parser.h" // frontend::Parser, frontend::ParseGoal
#include "frontend/StencilXdr.h" // js::XDRStencilEncoder
#include "js/CharacterEncoding.h" // JS::UTF8Chars, JS::ConstUTF8CharsZ, JS::UTF8CharsToNewTwoByteCharsZ
#include "js/ColumnNumber.h" // JS::ColumnNumberOneOrigin
#include "js/EnvironmentChain.h" // JS::EnvironmentChain
@@ -28,9 +29,10 @@
#include "js/friend/ErrorMessages.h" // js::GetErrorMessage, JSMSG_*
#include "js/RootingAPI.h" // JS::Rooted
#include "js/SourceText.h" // JS::SourceText
#include "js/TypeDecls.h" // JS::HandleObject, JS::MutableHandleScript
#include "js/Utility.h" // js::MallocArena, JS::UniqueTwoByteChars
#include "js/Value.h" // JS::Value
#include "js/Transcoding.h" // JS::TranscodeBuffer, JS::IsTranscodeFailureResult
#include "js/TypeDecls.h" // JS::HandleObject, JS::MutableHandleScript
#include "js/Utility.h" // js::MallocArena, JS::UniqueTwoByteChars
#include "js/Value.h" // JS::Value
#include "util/CompleteFile.h" // js::FileContents, js::ReadCompleteFile
#include "util/Identifier.h" // js::IsIdentifier
#include "util/StringBuilder.h" // js::StringBuilder
@@ -38,6 +40,8 @@
#include "vm/ErrorReporting.h" // js::ErrorMetadata, js::ReportCompileErrorLatin1
#include "vm/Interpreter.h" // js::Execute
#include "vm/JSContext.h" // JSContext
#include "vm/JSScript.h" // js::ScriptSourceObject
#include "vm/Xdr.h" // XDRResult
#include "vm/JSContext-inl.h" // JSContext::check
@@ -110,33 +114,162 @@ JSScript* JS::Compile(JSContext* cx, const ReadOnlyCompileOptions& options,
return CompileSourceBuffer(cx, options, srcBuf);
}
JS_PUBLIC_API bool JS::StartIncrementalEncoding(JSContext* cx,
RefPtr<JS::Stencil>&& stencil,
bool& alreadyStarted) {
MOZ_ASSERT(cx);
MOZ_ASSERT(!stencil->hasMultipleReference());
auto* source = stencil->source.get();
UniquePtr<frontend::ExtensibleCompilationStencil> initial;
if (stencil->hasOwnedBorrow()) {
initial.reset(stencil->takeOwnedBorrow());
stencil = nullptr;
} else {
initial = cx->make_unique<frontend::ExtensibleCompilationStencil>(
stencil->source);
if (!initial) {
return false;
}
AutoReportFrontendContext fc(cx);
if (!initial->steal(&fc, std::move(stencil))) {
return false;
}
static already_AddRefed<frontend::InitialStencilAndDelazifications>
CreateInitialStencilAndDelazifications(JSContext* cx, JS::Stencil* initial) {
RefPtr stencils = cx->new_<frontend::InitialStencilAndDelazifications>();
if (!stencils) {
return nullptr;
}
return source->startIncrementalEncoding(cx, std::move(initial),
alreadyStarted);
AutoReportFrontendContext fc(cx);
if (!stencils->init(&fc, initial)) {
return nullptr;
}
return stencils.forget();
}
static bool StartCollectingDelazifications(JSContext* cx,
JS::Handle<ScriptSourceObject*> sso,
JS::Stencil* initial,
bool& alreadyStarted) {
if (sso->maybeGetStencils()) {
alreadyStarted = true;
return true;
}
alreadyStarted = false;
// We don't support asm.js in XDR.
// Failures are reported by the FinishIncrementalEncoding function below.
if (initial->asmJS) {
return true;
}
// TODO: The entire public API should be converted to take
// InitialStencilAndDelazifications.
RefPtr stencils = CreateInitialStencilAndDelazifications(cx, initial);
if (!stencils) {
return false;
}
sso->setStencils(stencils.forget());
return true;
}
JS_PUBLIC_API bool JS::StartIncrementalEncoding(JSContext* cx,
JS::Handle<JSScript*> script,
JS::Stencil* stencil,
bool& alreadyStarted) {
JS::Rooted<ScriptSourceObject*> sso(cx, script->sourceObject());
return StartCollectingDelazifications(cx, sso, stencil, alreadyStarted);
}
JS_PUBLIC_API bool JS::StartIncrementalEncoding(JSContext* cx,
JS::Handle<JSObject*> module,
JS::Stencil* stencil,
bool& alreadyStarted) {
JS::Rooted<ScriptSourceObject*> sso(
cx, module->as<ModuleObject>().scriptSourceObject());
return StartCollectingDelazifications(cx, sso, stencil, alreadyStarted);
}
static bool FinishIncrementalEncoding(JSContext* cx,
JS::Handle<ScriptSourceObject*> sso,
JS::TranscodeBuffer& buffer) {
RefPtr<frontend::InitialStencilAndDelazifications> stencils =
sso->maybeStealStencils();
if (!stencils) {
JS_ReportErrorASCII(cx, "Not collecting delazifications");
return false;
}
AutoReportFrontendContext fc(cx);
UniquePtr<frontend::CompilationStencil> stencilHolder;
const frontend::CompilationStencil* stencil;
if (stencils->canLazilyParse()) {
stencilHolder.reset(stencils->getMerged(&fc));
if (!stencilHolder) {
return false;
}
stencil = stencilHolder.get();
} else {
stencil = stencils->getInitial();
}
XDRStencilEncoder encoder(&fc, buffer);
XDRResult res = encoder.codeStencil(sso->source(), *stencil);
if (res.isErr()) {
if (JS::IsTranscodeFailureResult(res.unwrapErr())) {
fc.clearAutoReport();
JS_ReportErrorASCII(cx, "XDR encoding failure");
}
return false;
}
return true;
}
static bool FinishIncrementalEncoding(JSContext* cx,
JS::Handle<ScriptSourceObject*> sso,
JS::Stencil** stencilOut) {
RefPtr<frontend::InitialStencilAndDelazifications> stencils =
sso->maybeStealStencils();
if (!stencils) {
JS_ReportErrorASCII(cx, "Not collecting delazifications");
return false;
}
if (stencils->canLazilyParse()) {
// TODO: Remove the cast once JS::Stencils becomes an alias to
// InitialStencilAndDelazifications.
RefPtr initial =
const_cast<frontend::CompilationStencil*>(stencils->getInitial());
initial.forget(stencilOut);
return true;
}
AutoReportFrontendContext fc(cx);
RefPtr<frontend::CompilationStencil> stencil = stencils->getMerged(&fc);
if (!stencil) {
return false;
}
stencil.forget(stencilOut);
return true;
}
JS_PUBLIC_API bool JS::FinishIncrementalEncoding(JSContext* cx,
JS::HandleScript script,
JS::TranscodeBuffer& buffer) {
JS::Rooted<ScriptSourceObject*> sso(cx, script->sourceObject());
return ::FinishIncrementalEncoding(cx, sso, buffer);
}
JS_PUBLIC_API bool JS::FinishIncrementalEncoding(JSContext* cx,
JS::HandleScript script,
JS::Stencil** stencilOut) {
JS::Rooted<ScriptSourceObject*> sso(cx, script->sourceObject());
return ::FinishIncrementalEncoding(cx, sso, stencilOut);
}
JS_PUBLIC_API bool JS::FinishIncrementalEncoding(JSContext* cx,
JS::Handle<JSObject*> module,
JS::TranscodeBuffer& buffer) {
JS::Rooted<ScriptSourceObject*> sso(
cx, module->as<ModuleObject>().scriptSourceObject());
return ::FinishIncrementalEncoding(cx, sso, buffer);
}
JS_PUBLIC_API void JS::AbortIncrementalEncoding(JS::HandleScript script) {
if (!script) {
return;
}
script->sourceObject()->clearStencils();
}
JS_PUBLIC_API void JS::AbortIncrementalEncoding(JS::Handle<JSObject*> module) {
module->as<ModuleObject>().scriptSourceObject()->clearStencils();
}
JSScript* JS::CompileUtf8File(JSContext* cx,

View File

@@ -30,8 +30,8 @@
#include "jstypes.h"
#include "frontend/BytecodeSection.h"
#include "frontend/CompilationStencil.h" // frontend::CompilationStencil
#include "frontend/FrontendContext.h" // AutoReportFrontendContext
#include "frontend/CompilationStencil.h" // frontend::CompilationStencil, frontend::InitialStencilAndDelazifications
#include "frontend/FrontendContext.h" // AutoReportFrontendContext
#include "frontend/ParseContext.h"
#include "frontend/SourceNotes.h" // SrcNote, SrcNoteType, SrcNoteIterator
#include "frontend/Stencil.h" // DumpFunctionFlagsItems, DumpImmutableScriptFlags
@@ -694,6 +694,8 @@ void ScriptSourceObject::finalize(JS::GCContext* gcx, JSObject* obj) {
// Clear the private value, calling the release hook if necessary.
sso->setPrivate(gcx->runtime(), UndefinedValue());
sso->clearStencils();
}
static const JSClassOps ScriptSourceObjectClassOps = {
@@ -731,6 +733,8 @@ ScriptSourceObject* ScriptSourceObject::create(JSContext* cx,
obj->initReservedSlot(ELEMENT_PROPERTY_SLOT, MagicValue(JS_GENERIC_MAGIC));
obj->initReservedSlot(INTRODUCTION_SCRIPT_SLOT, MagicValue(JS_GENERIC_MAGIC));
obj->initReservedSlot(STENCILS_SLOT, UndefinedValue());
return obj;
}
@@ -1789,103 +1793,43 @@ void ScriptSource::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
info->numScripts++;
}
bool ScriptSource::startIncrementalEncoding(
JSContext* cx, UniquePtr<frontend::ExtensibleCompilationStencil>&& initial,
bool& alreadyStarted) {
// We don't support asm.js in XDR.
// Encoding failures are reported by the xdrFinalizeEncoder function.
if (initial->asmJS) {
alreadyStarted = false;
return true;
frontend::InitialStencilAndDelazifications*
ScriptSourceObject::maybeGetStencils() {
Value stencilsVal = getReservedSlot(STENCILS_SLOT);
if (stencilsVal.isUndefined()) {
return nullptr;
}
if (xdrEncoder_.hasEncoder()) {
alreadyStarted = true;
return true;
}
alreadyStarted = false;
// Remove the reference to the source, to avoid the circular reference.
initial->source = nullptr;
AutoIncrementalTimer timer(cx->realm()->timers.xdrEncodingTime);
auto failureCase = mozilla::MakeScopeExit([&] { xdrEncoder_.reset(); });
if (!xdrEncoder_.setInitial(
cx, std::forward<UniquePtr<frontend::ExtensibleCompilationStencil>>(
initial))) {
// On encoding failure, let failureCase destroy encoder and return true
// to avoid failing any currently executing script.
return false;
}
failureCase.release();
return true;
return reinterpret_cast<frontend::InitialStencilAndDelazifications*>(
stencilsVal.toPrivate());
}
bool ScriptSource::addDelazificationToIncrementalEncoding(
JSContext* cx, const frontend::CompilationStencil& stencil) {
MOZ_ASSERT(hasEncoder());
AutoIncrementalTimer timer(cx->realm()->timers.xdrEncodingTime);
auto failureCase = mozilla::MakeScopeExit([&] { xdrEncoder_.reset(); });
if (!xdrEncoder_.addDelazification(cx, stencil)) {
// On encoding failure, let failureCase destroy encoder and return true
// to avoid failing any currently executing script.
return false;
already_AddRefed<frontend::InitialStencilAndDelazifications>
ScriptSourceObject::maybeStealStencils() {
auto* stencils = maybeGetStencils();
if (!stencils) {
return nullptr;
}
failureCase.release();
return true;
setReservedSlot(STENCILS_SLOT, UndefinedValue());
return already_AddRefed(stencils);
}
bool ScriptSource::xdrFinalizeEncoder(JSContext* cx,
JS::TranscodeBuffer& buffer) {
if (!hasEncoder()) {
JS_ReportErrorASCII(cx, "XDR encoding failure");
return false;
void ScriptSourceObject::clearStencils() {
auto* stencils = maybeGetStencils();
if (!stencils) {
return;
}
auto cleanup = mozilla::MakeScopeExit([&] { xdrEncoder_.reset(); });
AutoReportFrontendContext fc(cx);
XDRStencilEncoder encoder(&fc, buffer);
frontend::BorrowingCompilationStencil borrowingStencil(
xdrEncoder_.merger_->getResult());
XDRResult res = encoder.codeStencil(this, borrowingStencil);
if (res.isErr()) {
if (JS::IsTranscodeFailureResult(res.unwrapErr())) {
fc.clearAutoReport();
JS_ReportErrorASCII(cx, "XDR encoding failure");
}
return false;
}
return true;
stencils->Release();
setReservedSlot(STENCILS_SLOT, UndefinedValue());
}
bool ScriptSource::xdrFinalizeEncoder(JSContext* cx, JS::Stencil** stencilOut) {
if (!hasEncoder()) {
JS_ReportErrorASCII(cx, "XDR encoding failure");
return false;
}
auto cleanup = mozilla::MakeScopeExit([&] { xdrEncoder_.reset(); });
UniquePtr<frontend::ExtensibleCompilationStencil> extensibleStencil =
xdrEncoder_.merger_->takeResult();
extensibleStencil->source = this;
RefPtr<frontend::CompilationStencil> stencil =
cx->new_<frontend::CompilationStencil>(std::move(extensibleStencil));
if (!stencil) {
return false;
}
stencil.forget(stencilOut);
return true;
void ScriptSourceObject::setStencils(
already_AddRefed<frontend::InitialStencilAndDelazifications> stencils) {
initReservedSlot(STENCILS_SLOT, PrivateValue(stencils.take()));
}
void ScriptSource::xdrAbortEncoder() { xdrEncoder_.reset(); }
template <typename Unit>
[[nodiscard]] bool ScriptSource::initializeUnretrievableUncompressedSource(
FrontendContext* fc, EntryUnits<Unit>&& source, size_t length) {

View File

@@ -86,6 +86,7 @@ namespace frontend {
struct CompilationStencil;
struct ExtensibleCompilationStencil;
struct CompilationGCOutput;
struct InitialStencilAndDelazifications;
struct CompilationStencilMerger;
class StencilXDR;
} // namespace frontend
@@ -191,29 +192,6 @@ using ScriptFinalWarmUpCountMap =
DefaultHasher<HeapPtr<BaseScript*>>, SystemAllocPolicy>;
#endif
// As we execute JS sources that used lazy parsing, we may generate additional
// bytecode that we would like to include in caches if they are being used.
// There is a dependency cycle between JSScript / ScriptSource /
// CompilationStencil for this scenario so introduce this smart-ptr wrapper to
// avoid needing the full details of the stencil-merger in this file.
class StencilIncrementalEncoderPtr {
public:
frontend::CompilationStencilMerger* merger_ = nullptr;
StencilIncrementalEncoderPtr() = default;
~StencilIncrementalEncoderPtr() { reset(); }
bool hasEncoder() const { return bool(merger_); }
void reset();
bool setInitial(JSContext* cx,
UniquePtr<frontend::ExtensibleCompilationStencil>&& initial);
bool addDelazification(JSContext* cx,
const frontend::CompilationStencil& delazification);
};
struct ScriptSourceChunk {
ScriptSource* ss = nullptr;
uint32_t chunk = 0;
@@ -597,11 +575,6 @@ class ScriptSource {
SharedImmutableTwoByteString displayURL_;
SharedImmutableTwoByteString sourceMapURL_;
// The bytecode cache encoder is used to encode only the content of function
// which are delazified. If this value is not nullptr, then each delazified
// function should be recorded before their first execution.
StencilIncrementalEncoderPtr xdrEncoder_;
// A string indicating how this source code was introduced into the system.
// This is a constant, statically allocated C string, so does not need memory
// management.
@@ -1079,27 +1052,6 @@ class ScriptSource {
MOZ_ASSERT(offset <= (uint32_t)INT32_MAX);
introductionOffset_.emplace(offset);
}
// Return wether an XDR encoder is present or not.
bool hasEncoder() const { return xdrEncoder_.hasEncoder(); }
[[nodiscard]] bool startIncrementalEncoding(
JSContext* cx,
UniquePtr<frontend::ExtensibleCompilationStencil>&& initial,
bool& alreadyStarted);
[[nodiscard]] bool addDelazificationToIncrementalEncoding(
JSContext* cx, const frontend::CompilationStencil& stencil);
// 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.
bool xdrFinalizeEncoder(JSContext* cx, JS::TranscodeBuffer& buffer);
bool xdrFinalizeEncoder(JSContext* cx, JS::Stencil** stencilOut);
// Discard the incremental encoding data and free the XDR encoder.
void xdrAbortEncoder();
};
// [SMDOC] ScriptSourceObject
@@ -1176,8 +1128,28 @@ class ScriptSourceObject : public NativeObject {
ELEMENT_PROPERTY_SLOT,
INTRODUCTION_SCRIPT_SLOT,
PRIVATE_SLOT,
STENCILS_SLOT,
RESERVED_SLOTS
};
public:
// Associate stencils to this ScriptSourceObject and start collecting the
// on-demand delazification result into the stencils.
void setStencils(
already_AddRefed<frontend::InitialStencilAndDelazifications> stencils);
// Return the associated stencils if any.
// Returns nullptr if stencils is not associated
frontend::InitialStencilAndDelazifications* maybeGetStencils();
// Return the associated stencils if any and stop collecting the on-demand
// delazifications.
// Returns nullptr if stencils is not associated
already_AddRefed<frontend::InitialStencilAndDelazifications>
maybeStealStencils();
// Stop collecting the on-demand delazifications.
void clearStencils();
};
// ScriptWarmUpData represents a pointer-sized field in BaseScript that stores