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:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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>();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user