diff --git a/dom/base/JSExecutionContext.cpp b/dom/base/JSExecutionContext.cpp index aa9af727a452..e581d83ba514 100644 --- a/dom/base/JSExecutionContext.cpp +++ b/dom/base/JSExecutionContext.cpp @@ -180,7 +180,9 @@ nsresult JSExecutionContext::Decode(mozilla::Vector& aBytecodeBuf, } JS::CompileOptions options(mCx, mCompileOptions); - options.borrowBuffer = true; + + JS::DecodeOptions decodeOptions(options); + decodeOptions.borrowBuffer = true; JS::TranscodeRange range(aBytecodeBuf.begin() + aBytecodeIndex, aBytecodeBuf.length() - aBytecodeIndex); @@ -188,7 +190,7 @@ nsresult JSExecutionContext::Decode(mozilla::Vector& aBytecodeBuf, MOZ_ASSERT(!mWantsReturnValue); RefPtr stencil; JS::TranscodeResult tr = - JS::DecodeStencil(mCx, options, range, getter_AddRefs(stencil)); + JS::DecodeStencil(mCx, decodeOptions, range, getter_AddRefs(stencil)); // These errors are external parameters which should be handled before the // decoding phase, and which are the only reasons why you might want to // fallback on decoding failures. diff --git a/dom/base/nsFrameMessageManager.cpp b/dom/base/nsFrameMessageManager.cpp index 1f092c23d238..d018ae95f1fc 100644 --- a/dom/base/nsFrameMessageManager.cpp +++ b/dom/base/nsFrameMessageManager.cpp @@ -1271,14 +1271,12 @@ nsMessageManagerScriptExecutor::TryCacheLoadAndCompileScript( } JSContext* cx = jsapi.cx(); - JS::CompileOptions options(cx); - FillCompileOptionsForCachedStencil(options); - options.setFileAndLine(url.get(), 1); - RefPtr stencil; if (useScriptPreloader) { - stencil = - ScriptPreloader::GetChildSingleton().GetCachedStencil(cx, options, url); + JS::DecodeOptions decodeOptions; + ScriptPreloader::FillDecodeOptionsForCachedStencil(decodeOptions); + stencil = ScriptPreloader::GetChildSingleton().GetCachedStencil( + cx, decodeOptions, url); } if (!stencil) { @@ -1315,6 +1313,10 @@ nsMessageManagerScriptExecutor::TryCacheLoadAndCompileScript( return nullptr; } + JS::CompileOptions options(cx); + FillCompileOptionsForCachedStencil(options); + options.setFileAndLine(url.get(), 1); + // If we are not encoding to the ScriptPreloader cache, we can now relax the // compile options and use the JS syntax-parser for lower latency. if (!useScriptPreloader || !ScriptPreloader::GetChildSingleton().Active()) { @@ -1338,6 +1340,12 @@ nsMessageManagerScriptExecutor::TryCacheLoadAndCompileScript( auto* holder = new nsMessageManagerScriptHolder(stencil); sCachedScripts->InsertOrUpdate(aURL, holder); } + +#ifdef DEBUG + // The above shouldn't touch any options for instantiation. + JS::InstantiateOptions instantiateOptions(options); + instantiateOptions.assertDefault(); +#endif } MOZ_ASSERT(stencil); diff --git a/dom/xul/nsXULElement.cpp b/dom/xul/nsXULElement.cpp index db6156dd7cac..ee03ba922d20 100644 --- a/dom/xul/nsXULElement.cpp +++ b/dom/xul/nsXULElement.cpp @@ -1607,7 +1607,7 @@ static nsresult WriteStencil(nsIObjectOutputStream* aStream, JSContext* aCx, } static nsresult ReadStencil(nsIObjectInputStream* aStream, JSContext* aCx, - const JS::ReadOnlyCompileOptions& aOptions, + const JS::DecodeOptions& aOptions, JS::Stencil** aStencilOut) { // We don't serialize mutedError-ness of scripts, which is fine as long as // we only serialize system and XUL-y things. We can detect this by checking @@ -1750,9 +1750,7 @@ nsresult nsXULPrototypeScript::Deserialize( } JSContext* cx = jsapi.cx(); - JS::CompileOptions options(cx); - FillCompileOptions(options); - + JS::DecodeOptions options; RefPtr newStencil; rv = ReadStencil(aStream, cx, options, getter_AddRefs(newStencil)); NS_ENSURE_SUCCESS(rv, rv); diff --git a/js/public/CompileOptions.h b/js/public/CompileOptions.h index 95d9162bc5b7..d8fa61f77573 100644 --- a/js/public/CompileOptions.h +++ b/js/public/CompileOptions.h @@ -73,6 +73,7 @@ enum class AsmJSOption : uint8_t { }; class JS_PUBLIC_API InstantiateOptions; +class JS_PUBLIC_API DecodeOptions; /** * The common base class for the CompileOptions hierarchy. @@ -81,6 +82,8 @@ class JS_PUBLIC_API InstantiateOptions; * compilation unit to another. */ class JS_PUBLIC_API TransitiveCompileOptions { + friend class JS_PUBLIC_API DecodeOptions; + protected: /** * The Web Platform allows scripts to be loaded from arbitrary cross-origin @@ -485,6 +488,42 @@ class JS_PUBLIC_API InstantiateOptions { #endif }; +/** + * Subset of CompileOptions fields used while decoding Stencils. + */ +class JS_PUBLIC_API DecodeOptions { + public: + bool borrowBuffer = false; + bool usePinnedBytecode = false; + + const char* introducerFilename = nullptr; + + // See `TransitiveCompileOptions::introductionType` field for details. + const char* introductionType = nullptr; + + unsigned introductionLineno = 0; + uint32_t introductionOffset = 0; + + DecodeOptions() = default; + + explicit DecodeOptions(const ReadOnlyCompileOptions& options) + : borrowBuffer(options.borrowBuffer), + usePinnedBytecode(options.usePinnedBytecode), + introducerFilename(options.introducerFilename()), + introductionType(options.introductionType), + introductionLineno(options.introductionLineno), + introductionOffset(options.introductionOffset) {} + + void copyTo(CompileOptions& options) const { + options.borrowBuffer = borrowBuffer; + options.usePinnedBytecode = usePinnedBytecode; + options.introducerFilename_ = introducerFilename; + options.introductionType = introductionType; + options.introductionLineno = introductionLineno; + options.introductionOffset = introductionOffset; + } +}; + } // namespace JS #endif /* js_CompileOptions_h */ diff --git a/js/public/experimental/JSStencil.h b/js/public/experimental/JSStencil.h index 1e4313dde1ba..3fdde2fa427f 100644 --- a/js/public/experimental/JSStencil.h +++ b/js/public/experimental/JSStencil.h @@ -23,7 +23,7 @@ #include "jstypes.h" // JS_PUBLIC_API -#include "js/CompileOptions.h" // JS::ReadOnlyCompileOptions +#include "js/CompileOptions.h" // JS::ReadOnlyCompileOptions, JS::InstantiateOptions, JS::DecodeOptions #include "js/OffThreadScriptCompilation.h" // JS::OffThreadCompileCallback #include "js/SourceText.h" // JS::SourceText #include "js/Transcoding.h" // JS::TranscodeSource @@ -101,9 +101,10 @@ extern JS_PUBLIC_API TranscodeResult EncodeStencil(JSContext* cx, TranscodeBuffer& buffer); // Deserialize data and create a new Stencil. -extern JS_PUBLIC_API TranscodeResult -DecodeStencil(JSContext* cx, const ReadOnlyCompileOptions& options, - const TranscodeRange& range, Stencil** stencilOut); +extern JS_PUBLIC_API TranscodeResult DecodeStencil(JSContext* cx, + const DecodeOptions& options, + const TranscodeRange& range, + Stencil** stencilOut); extern JS_PUBLIC_API size_t SizeOfStencil(Stencil* stencil, mozilla::MallocSizeOf mallocSizeOf); diff --git a/js/src/frontend/Stencil.cpp b/js/src/frontend/Stencil.cpp index d2d3cd04b66f..097953c7ed2f 100644 --- a/js/src/frontend/Stencil.cpp +++ b/js/src/frontend/Stencil.cpp @@ -25,6 +25,7 @@ #include "gc/Rooting.h" // RootedAtom #include "gc/Tracer.h" // TraceNullableRoot #include "js/CallArgs.h" // JSNative +#include "js/CompileOptions.h" // JS::DecodeOptions #include "js/experimental/JSStencil.h" // JS::Stencil #include "js/GCAPI.h" // JS::AutoCheckCannotGC #include "js/RootingAPI.h" // Rooted @@ -1874,8 +1875,9 @@ bool CompilationStencil::deserializeStencils(JSContext* cx, } MOZ_ASSERT(parserAtomData.empty()); XDRStencilDecoder decoder(cx, range); + JS::DecodeOptions options(input.options); - XDRResult res = decoder.codeStencil(input.options, *this); + XDRResult res = decoder.codeStencil(options, *this); if (res.isErr()) { if (JS::IsTranscodeFailureResult(res.unwrapErr())) { return true; @@ -4102,15 +4104,14 @@ JS::TranscodeResult JS::EncodeStencil(JSContext* cx, JS::Stencil* stencil, } JS::TranscodeResult JS::DecodeStencil(JSContext* cx, - const JS::ReadOnlyCompileOptions& options, + const JS::DecodeOptions& options, const JS::TranscodeRange& range, JS::Stencil** stencilOut) { - Rooted input(cx, CompilationInput(options)); - if (!input.get().initForGlobal(cx)) { + RefPtr source = cx->new_(); + if (!source) { return TranscodeResult::Throw; } - UniquePtr stencil( - MakeUnique(input.get().source)); + UniquePtr stencil(MakeUnique(source)); if (!stencil) { return TranscodeResult::Throw; } diff --git a/js/src/jsapi-tests/testStencil.cpp b/js/src/jsapi-tests/testStencil.cpp index f21c3a28715b..1e86701b7f49 100644 --- a/js/src/jsapi-tests/testStencil.cpp +++ b/js/src/jsapi-tests/testStencil.cpp @@ -238,13 +238,13 @@ BEGIN_TEST(testStencil_Transcode) { { // Decode the stencil into new range - JS::CompileOptions options(cx); RefPtr stencil; { + JS::DecodeOptions decodeOptions; JS::TranscodeRange range(buffer.begin(), buffer.length()); JS::TranscodeResult res = - JS::DecodeStencil(cx, options, range, getter_AddRefs(stencil)); + JS::DecodeStencil(cx, decodeOptions, range, getter_AddRefs(stencil)); CHECK(res == JS::TranscodeResult::Ok); } @@ -254,7 +254,7 @@ BEGIN_TEST(testStencil_Transcode) { buffer.clear(); // Instantiate and Run - JS::InstantiateOptions instantiateOptions(options); + JS::InstantiateOptions instantiateOptions; JS::RootedScript script( cx, JS::InstantiateGlobalStencil(cx, instantiateOptions, stencil)); stencil = nullptr; @@ -299,14 +299,14 @@ BEGIN_TEST(testStencil_TranscodeBorrowing) { JS::RootedScript script(cx); { JS::TranscodeRange range(buffer.begin(), buffer.length()); - JS::CompileOptions options(cx); - options.borrowBuffer = true; + JS::DecodeOptions decodeOptions; + decodeOptions.borrowBuffer = true; RefPtr stencil; JS::TranscodeResult res = - JS::DecodeStencil(cx, options, range, getter_AddRefs(stencil)); + JS::DecodeStencil(cx, decodeOptions, range, getter_AddRefs(stencil)); CHECK(res == JS::TranscodeResult::Ok); - JS::InstantiateOptions instantiateOptions(options); + JS::InstantiateOptions instantiateOptions; script = JS::InstantiateGlobalStencil(cx, instantiateOptions, stencil); CHECK(script); } diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index f704643d6db8..4546d7d93f00 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -2474,8 +2474,10 @@ static bool Evaluate(JSContext* cx, unsigned argc, Value* vp) { RefPtr stencil; - JS::TranscodeResult rv = - JS::DecodeStencil(cx, options, range, getter_AddRefs(stencil)); + JS::DecodeOptions decodeOptions(options); + + JS::TranscodeResult rv = JS::DecodeStencil(cx, decodeOptions, range, + getter_AddRefs(stencil)); if (!ConvertTranscodeResultToJSException(cx, rv)) { return false; } diff --git a/js/src/vm/HelperThreads.cpp b/js/src/vm/HelperThreads.cpp index d14300186a67..692bca1a59f7 100644 --- a/js/src/vm/HelperThreads.cpp +++ b/js/src/vm/HelperThreads.cpp @@ -20,6 +20,7 @@ #include "gc/GC.h" // gc::MergeRealms #include "jit/IonCompileTask.h" #include "jit/JitRuntime.h" +#include "js/CompileOptions.h" // JS::CompileOptions, JS::DecodeOptions, JS::ReadOnlyCompileOptions #include "js/ContextOptions.h" // JS::ContextOptions #include "js/experimental/JSStencil.h" #include "js/friend/StackLimits.h" // js::ReportOverRecursed @@ -855,7 +856,8 @@ void ScriptDecodeTask::parse(JSContext* cx) { } XDRStencilDecoder decoder(cx, range); - XDRResult res = decoder.codeStencil(stencilInput_->options, *stencil_); + JS::DecodeOptions options(stencilInput_->options); + XDRResult res = decoder.codeStencil(options, *stencil_); if (!res.isOk()) { stencil_.reset(); return; @@ -866,7 +868,7 @@ void ScriptDecodeTask::parse(JSContext* cx) { stencil_.reset(); } - if (options.useOffThreadParseGlobal) { + if (stencilInput_->options.useOffThreadParseGlobal) { (void)instantiateStencils(cx); } } @@ -886,12 +888,10 @@ void MultiStencilsDecodeTask::parse(JSContext* cx) { } for (auto& source : *sources) { - CompileOptions opts(cx, options); - opts.setFileAndLine(source.filename, source.lineno); - + JS::DecodeOptions decodeOptions(options); RefPtr stencil; - if (JS::DecodeStencil(cx, options, source.range, getter_AddRefs(stencil)) != - JS::TranscodeResult::Ok) { + if (JS::DecodeStencil(cx, decodeOptions, source.range, + getter_AddRefs(stencil)) != JS::TranscodeResult::Ok) { break; } diff --git a/js/src/vm/JSScript.cpp b/js/src/vm/JSScript.cpp index 0d85fad266dd..b7b69c664e16 100644 --- a/js/src/vm/JSScript.cpp +++ b/js/src/vm/JSScript.cpp @@ -2195,7 +2195,9 @@ XDRResult ScriptSource::xdrData(XDRState* const xdr, template /* static */ -XDRResult ScriptSource::XDR(XDRState* xdr, RefPtr& source) { +XDRResult ScriptSource::XDR(XDRState* xdr, + const JS::DecodeOptions* maybeOptions, + RefPtr& source) { JSContext* cx = xdr->cx(); if (mode == XDR_DECODE) { @@ -2283,6 +2285,18 @@ XDRResult ScriptSource::XDR(XDRState* xdr, RefPtr& source) { MOZ_TRY(xdr->codeUint32(&source->startLine_)); + // The introduction info doesn't persist across encode/decode. + if (mode == XDR_DECODE) { + source->introductionType_ = maybeOptions->introductionType; + source->setIntroductionOffset(maybeOptions->introductionOffset); + if (maybeOptions->introducerFilename) { + if (!source->setIntroducerFilename(cx, + maybeOptions->introducerFilename)) { + return xdr->fail(JS::TranscodeResult::Throw); + } + } + } + MOZ_TRY(xdrData(xdr, source.get())); return Ok(); @@ -2290,10 +2304,14 @@ XDRResult ScriptSource::XDR(XDRState* xdr, RefPtr& source) { template /* static */ XDRResult - ScriptSource::XDR(XDRState* xdr, RefPtr& holder); + ScriptSource::XDR(XDRState* xdr, + const JS::DecodeOptions* maybeOptions, + RefPtr& holder); template /* static */ XDRResult - ScriptSource::XDR(XDRState* xdr, RefPtr& holder); + ScriptSource::XDR(XDRState* xdr, + const JS::DecodeOptions* maybeOptions, + RefPtr& holder); // Format and return a cx->pod_malloc'ed URL for a generated script like: // {filename} line {lineno} > {introducer} diff --git a/js/src/vm/JSScript.h b/js/src/vm/JSScript.h index 219a475670a1..a7f9ffdb9615 100644 --- a/js/src/vm/JSScript.h +++ b/js/src/vm/JSScript.h @@ -1058,6 +1058,7 @@ class ScriptSource { public: template [[nodiscard]] static XDRResult XDR(XDRState* xdr, + const JS::DecodeOptions* maybeOptions, RefPtr& source); }; diff --git a/js/src/vm/OffThreadScriptCompilation.cpp b/js/src/vm/OffThreadScriptCompilation.cpp index 2a830799853f..0ccb46cf2adc 100644 --- a/js/src/vm/OffThreadScriptCompilation.cpp +++ b/js/src/vm/OffThreadScriptCompilation.cpp @@ -182,6 +182,9 @@ JS_PUBLIC_API bool JS::CanDecodeOffThread(JSContext* cx, return CanDoOffThread(cx, options, length, OffThread::Decode); } +// TODO: Once off-thread instantiation is removed, use JS::DecodeOptions here +// and split the instantiation off from the off-thread API. +// Until then, options here is used for both decode and instantiation. JS_PUBLIC_API JS::OffThreadToken* JS::DecodeOffThreadScript( JSContext* cx, const ReadOnlyCompileOptions& options, mozilla::Vector& buffer /* TranscodeBuffer& */, size_t cursor, diff --git a/js/src/vm/Xdr.cpp b/js/src/vm/Xdr.cpp index e367e45b1689..6a6268452d65 100644 --- a/js/src/vm/Xdr.cpp +++ b/js/src/vm/Xdr.cpp @@ -247,12 +247,13 @@ static XDRResult VersionCheck(XDRState* xdr) { template static XDRResult XDRStencilHeader(XDRState* xdr, + const JS::DecodeOptions* maybeOptions, RefPtr& source) { // 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)); - MOZ_TRY(ScriptSource::XDR(xdr, source)); + MOZ_TRY(ScriptSource::XDR(xdr, maybeOptions, source)); return Ok(); } @@ -270,7 +271,8 @@ XDRResult XDRStencilEncoder::codeStencil( MOZ_TRY(frontend::StencilXDR::checkCompilationStencil(this, stencil)); - MOZ_TRY(XDRStencilHeader(this, const_cast&>(source))); + MOZ_TRY(XDRStencilHeader(this, nullptr, + const_cast&>(source))); MOZ_TRY(frontend::StencilXDR::codeCompilationStencil( this, const_cast(stencil))); @@ -331,8 +333,7 @@ XDRResult XDRIncrementalStencilEncoder::linearize(JSContext* cx, } XDRResult XDRStencilDecoder::codeStencil( - const JS::ReadOnlyCompileOptions& options, - frontend::CompilationStencil& stencil) { + const JS::DecodeOptions& options, frontend::CompilationStencil& stencil) { #ifdef DEBUG auto sanityCheck = mozilla::MakeScopeExit( [&] { MOZ_ASSERT(validateResultCode(cx(), resultCode())); }); @@ -341,7 +342,7 @@ XDRResult XDRStencilDecoder::codeStencil( auto resetOptions = mozilla::MakeScopeExit([&] { options_ = nullptr; }); options_ = &options; - MOZ_TRY(XDRStencilHeader(this, stencil.source)); + MOZ_TRY(XDRStencilHeader(this, &options, stencil.source)); MOZ_TRY(frontend::StencilXDR::codeCompilationStencil(this, stencil)); return Ok(); diff --git a/js/src/vm/Xdr.h b/js/src/vm/Xdr.h index 2f3ce3a33295..93160a45e521 100644 --- a/js/src/vm/Xdr.h +++ b/js/src/vm/Xdr.h @@ -19,7 +19,7 @@ #include // std::enable_if_t #include "js/AllocPolicy.h" // ReportOutOfMemory -#include "js/CompileOptions.h" // JS::ReadOnlyCompileOptions +#include "js/CompileOptions.h" // JS::DecodeOptions #include "js/Transcoding.h" // JS::TranscodeResult, JS::TranscodeBuffer, JS::TranscodeRange, IsTranscodingBytecodeAligned, IsTranscodingBytecodeOffsetAligned #include "js/TypeDecls.h" // JS::Latin1Char #include "js/UniquePtr.h" // UniquePtr @@ -454,16 +454,16 @@ class XDRStencilDecoder : public XDRState { MOZ_ASSERT(JS::IsTranscodingBytecodeAligned(range.begin().get())); } - XDRResult codeStencil(const JS::ReadOnlyCompileOptions& options, + XDRResult codeStencil(const JS::DecodeOptions& options, frontend::CompilationStencil& stencil); - const JS::ReadOnlyCompileOptions& options() { + const JS::DecodeOptions& options() { MOZ_ASSERT(options_); return *options_; } private: - const JS::ReadOnlyCompileOptions* options_ = nullptr; + const JS::DecodeOptions* options_ = nullptr; }; class XDRIncrementalStencilEncoder; diff --git a/js/xpconnect/loader/ScriptPreloader.cpp b/js/xpconnect/loader/ScriptPreloader.cpp index c74c626969c8..97ed210daf34 100644 --- a/js/xpconnect/loader/ScriptPreloader.cpp +++ b/js/xpconnect/loader/ScriptPreloader.cpp @@ -883,22 +883,18 @@ void ScriptPreloader::FillCompileOptionsForCachedStencil( // called on functions in these scripts, the source-hook will fetch it over, // so using `toString` of functions should be avoided in chrome js. options.setSourceIsLazy(true); +} +/* static */ +void ScriptPreloader::FillDecodeOptionsForCachedStencil( + JS::DecodeOptions& options) { // ScriptPreloader's XDR buffer is alive during the entire browser lifetime. // The decoded stencil can borrow from it. options.borrowBuffer = true; } already_AddRefed ScriptPreloader::GetCachedStencil( - JSContext* cx, const JS::ReadOnlyCompileOptions& options, - const nsCString& path) { - // Users of ScriptPreloader must agree on a standard set of compile options so - // that bytecode data can safely saved from one context and loaded in another. - MOZ_ASSERT(options.noScriptRval); - MOZ_ASSERT(!options.selfHostingMode); - MOZ_ASSERT(!options.isRunOnce); - MOZ_ASSERT(options.sourceIsLazy); - + JSContext* cx, const JS::DecodeOptions& options, const nsCString& path) { // If a script is used by both the parent and the child, it's stored only // in the child cache. if (mChildCache) { @@ -919,8 +915,7 @@ already_AddRefed ScriptPreloader::GetCachedStencil( } already_AddRefed ScriptPreloader::GetCachedStencilInternal( - JSContext* cx, const JS::ReadOnlyCompileOptions& options, - const nsCString& path) { + JSContext* cx, const JS::DecodeOptions& options, const nsCString& path) { auto* cachedScript = mScripts.Get(path); if (cachedScript) { return WaitForCachedStencil(cx, options, cachedScript); @@ -929,8 +924,7 @@ already_AddRefed ScriptPreloader::GetCachedStencilInternal( } already_AddRefed ScriptPreloader::WaitForCachedStencil( - JSContext* cx, const JS::ReadOnlyCompileOptions& options, - CachedStencil* script) { + JSContext* cx, const JS::DecodeOptions& options, CachedStencil* script) { // Always check for finished operations so that we can move on to decoding the // next batch as soon as possible after the pending batch is ready. If we wait // until we hit an unfinished script, we wind up having at most one batch of @@ -1175,7 +1169,7 @@ bool ScriptPreloader::CachedStencil::XDREncode(JSContext* cx) { } already_AddRefed ScriptPreloader::CachedStencil::GetStencil( - JSContext* cx, const JS::ReadOnlyCompileOptions& options) { + JSContext* cx, const JS::DecodeOptions& options) { MOZ_ASSERT(mReadyToExecute); if (mStencil) { return do_AddRef(mStencil); diff --git a/js/xpconnect/loader/ScriptPreloader.h b/js/xpconnect/loader/ScriptPreloader.h index 49f2c419aab7..c679e1fa43bc 100644 --- a/js/xpconnect/loader/ScriptPreloader.h +++ b/js/xpconnect/loader/ScriptPreloader.h @@ -26,6 +26,7 @@ #include "nsIThread.h" #include "nsITimer.h" +#include "js/CompileOptions.h" // JS::DecodeOptions #include "js/experimental/JSStencil.h" #include "js/GCAnnotations.h" // for JS_HAZ_NON_GC_POINTER #include "js/RootingAPI.h" // for Handle, Heap @@ -91,12 +92,12 @@ class ScriptPreloader : public nsIObserver, // Fill some options that should be consistent across all scripts stored // into preloader cache. static void FillCompileOptionsForCachedStencil(JS::CompileOptions& options); + static void FillDecodeOptionsForCachedStencil(JS::DecodeOptions& options); // Retrieves the stencil with the given cache key from the cache. // Returns null if the stencil is not cached. already_AddRefed GetCachedStencil( - JSContext* cx, const JS::ReadOnlyCompileOptions& options, - const nsCString& path); + JSContext* cx, const JS::DecodeOptions& options, const nsCString& path); // Notes the execution of a script with the given URL and cache key. // Depending on the stage of startup, the script may be serialized and @@ -125,8 +126,7 @@ class ScriptPreloader : public nsIObserver, private: Result InitCacheInternal(JS::HandleObject scope = nullptr); already_AddRefed GetCachedStencilInternal( - JSContext* cx, const JS::ReadOnlyCompileOptions& options, - const nsCString& path); + JSContext* cx, const JS::DecodeOptions& options, const nsCString& path); public: static ProcessType CurrentProcessType() { @@ -283,8 +283,8 @@ class ScriptPreloader : public nsIObserver, bool HasArray() { return mXDRData.constructed>(); } - already_AddRefed GetStencil( - JSContext* cx, const JS::ReadOnlyCompileOptions& options); + already_AddRefed GetStencil(JSContext* cx, + const JS::DecodeOptions& options); size_t HeapSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) { auto size = mallocSizeOf(this); @@ -435,8 +435,7 @@ class ScriptPreloader : public nsIObserver, // Waits for the given cached script to finish compiling off-thread, or // decodes it synchronously on the main thread, as appropriate. already_AddRefed WaitForCachedStencil( - JSContext* cx, const JS::ReadOnlyCompileOptions& options, - CachedStencil* script); + JSContext* cx, const JS::DecodeOptions& options, CachedStencil* script); void DecodeNextBatch(size_t chunkSize, JS::HandleObject scope = nullptr); diff --git a/js/xpconnect/loader/mozJSComponentLoader.cpp b/js/xpconnect/loader/mozJSComponentLoader.cpp index 216842ae3e56..16ec667e7427 100644 --- a/js/xpconnect/loader/mozJSComponentLoader.cpp +++ b/js/xpconnect/loader/mozJSComponentLoader.cpp @@ -751,17 +751,16 @@ nsresult mozJSComponentLoader::ObjectForLocation( rv = PathifyURI(aInfo.ResolvedURI(), cachePath); NS_ENSURE_SUCCESS(rv, rv); - CompileOptions options(cx); - ScriptPreloader::FillCompileOptionsForCachedStencil(options); - options.setFileAndLine(nativePath.get(), 1); - options.setForceStrictMode(); - options.setNonSyntacticScope(true); + JS::DecodeOptions decodeOptions; + ScriptPreloader::FillDecodeOptionsForCachedStencil(decodeOptions); RefPtr stencil = - ScriptPreloader::GetSingleton().GetCachedStencil(cx, options, cachePath); + ScriptPreloader::GetSingleton().GetCachedStencil(cx, decodeOptions, + cachePath); if (!stencil && cache) { - ReadCachedStencil(cache, cachePath, cx, options, getter_AddRefs(stencil)); + ReadCachedStencil(cache, cachePath, cx, decodeOptions, + getter_AddRefs(stencil)); if (!stencil) { JS_ClearPendingException(cx); @@ -775,6 +774,12 @@ nsresult mozJSComponentLoader::ObjectForLocation( // The script wasn't in the cache , so compile it now. LOG(("Slow loading %s\n", nativePath.get())); + CompileOptions options(cx); + ScriptPreloader::FillCompileOptionsForCachedStencil(options); + options.setFileAndLine(nativePath.get(), 1); + options.setForceStrictMode(); + options.setNonSyntacticScope(true); + // If we can no longer write to caches, we should stop using lazy sources // and instead let normal syntax parsing occur. This can occur in content // processes after the ScriptPreloader is flushed where we can read but no @@ -807,6 +812,12 @@ nsresult mozJSComponentLoader::ObjectForLocation( } } +#ifdef DEBUG + // The above shouldn't touch any options for instantiation. + JS::InstantiateOptions instantiateOptions(options); + instantiateOptions.assertDefault(); +#endif + if (!stencil) { // Propagate the exception, if one exists. Also, don't leave the stale // exception on this context. @@ -819,7 +830,7 @@ nsresult mozJSComponentLoader::ObjectForLocation( } } - JS::InstantiateOptions instantiateOptions(options); + JS::InstantiateOptions instantiateOptions; RootedScript script( cx, JS::InstantiateGlobalStencil(cx, instantiateOptions, stencil)); if (!script) { @@ -835,13 +846,11 @@ nsresult mozJSComponentLoader::ObjectForLocation( // ScriptPreloader::NoteScript needs to be called unconditionally, to // reflect the usage into the next session's cache. - MOZ_ASSERT_IF(ScriptPreloader::GetSingleton().Active(), options.sourceIsLazy); ScriptPreloader::GetSingleton().NoteStencil(nativePath, cachePath, stencil); // Write to startup cache only when we didn't have any cache for the script // and compiled it. if (storeIntoStartupCache) { - MOZ_ASSERT(options.sourceIsLazy); MOZ_ASSERT(stencil); // We successfully compiled the script, so cache it. diff --git a/js/xpconnect/loader/mozJSLoaderUtils.cpp b/js/xpconnect/loader/mozJSLoaderUtils.cpp index 1515584cc218..aec8da3758df 100644 --- a/js/xpconnect/loader/mozJSLoaderUtils.cpp +++ b/js/xpconnect/loader/mozJSLoaderUtils.cpp @@ -34,7 +34,7 @@ static nsresult HandleTranscodeResult(JSContext* cx, } nsresult ReadCachedStencil(StartupCache* cache, nsACString& uri, JSContext* cx, - const JS::ReadOnlyCompileOptions& options, + const JS::DecodeOptions& options, JS::Stencil** stencilOut) { const char* buf; uint32_t len; diff --git a/js/xpconnect/loader/mozJSLoaderUtils.h b/js/xpconnect/loader/mozJSLoaderUtils.h index 396aedac3229..ab3f19a474f8 100644 --- a/js/xpconnect/loader/mozJSLoaderUtils.h +++ b/js/xpconnect/loader/mozJSLoaderUtils.h @@ -10,7 +10,7 @@ #include "nsString.h" #include "js/experimental/JSStencil.h" -#include "js/CompileOptions.h" // JS::ReadOnlyCompileOptions +#include "js/CompileOptions.h" // JS::DecodeOptions namespace mozilla { namespace scache { @@ -20,7 +20,7 @@ class StartupCache; nsresult ReadCachedStencil(mozilla::scache::StartupCache* cache, nsACString& uri, JSContext* cx, - const JS::ReadOnlyCompileOptions& options, + const JS::DecodeOptions& options, JS::Stencil** stencilOut); nsresult WriteCachedStencil(mozilla::scache::StartupCache* cache, diff --git a/js/xpconnect/loader/mozJSSubScriptLoader.cpp b/js/xpconnect/loader/mozJSSubScriptLoader.cpp index b38579987cea..f7932ab6832c 100644 --- a/js/xpconnect/loader/mozJSSubScriptLoader.cpp +++ b/js/xpconnect/loader/mozJSSubScriptLoader.cpp @@ -20,7 +20,7 @@ #include "jsfriendapi.h" #include "xpcprivate.h" // xpc::OptionsBase #include "js/CompilationAndEvaluation.h" // JS::Compile -#include "js/CompileOptions.h" // JS::ReadOnlyCompileOptions +#include "js/CompileOptions.h" // JS::ReadOnlyCompileOptions, JS::DecodeOptions #include "js/friend/JSMEnvironment.h" // JS::ExecuteInJSMEnvironment, JS::IsJSMEnvironment #include "js/SourceText.h" // JS::Source{Ownership,Text} #include "js/Wrapper.h" @@ -126,14 +126,12 @@ static void ReportError(JSContext* cx, const char* origMsg, nsIURI* uri) { static bool EvalStencil(JSContext* cx, HandleObject targetObj, HandleObject loadScope, MutableHandleValue retval, nsIURI* uri, bool storeIntoStartupCache, - bool storeIntoPreloadCache, - const ReadOnlyCompileOptions& options, - JS::Stencil* stencil) { + bool storeIntoPreloadCache, JS::Stencil* stencil) { MOZ_ASSERT(!js::IsWrapper(targetObj)); - JS::InstantiateOptions instantiateOptions(options); - JS::RootedScript script( - cx, JS::InstantiateGlobalStencil(cx, instantiateOptions, stencil)); + JS::InstantiateOptions options; + JS::RootedScript script(cx, + JS::InstantiateGlobalStencil(cx, options, stencil)); if (!script) { return false; } @@ -432,24 +430,18 @@ nsresult mozJSSubScriptLoader::DoLoadSubScriptWithOptions( nsAutoCString cachePath; SubscriptCachePath(cx, uri, targetObj, cachePath); - JS::CompileOptions compileOptions(cx); - ScriptPreloader::FillCompileOptionsForCachedStencil(compileOptions); - compileOptions.setFileAndLine(uriStr.get(), 1); - compileOptions.setNonSyntacticScope(!JS_IsGlobalObject(targetObj)); - - if (options.wantReturnValue) { - compileOptions.setNoScriptRval(false); - } + JS::DecodeOptions decodeOptions; + ScriptPreloader::FillDecodeOptionsForCachedStencil(decodeOptions); RefPtr stencil; if (!options.ignoreCache) { if (!options.wantReturnValue) { // NOTE: If we need the return value, we cannot use ScriptPreloader. stencil = ScriptPreloader::GetSingleton().GetCachedStencil( - cx, compileOptions, cachePath); + cx, decodeOptions, cachePath); } if (!stencil && cache) { - rv = ReadCachedStencil(cache, cachePath, cx, compileOptions, + rv = ReadCachedStencil(cache, cachePath, cx, decodeOptions, getter_AddRefs(stencil)); if (NS_FAILED(rv) || !stencil) { JS_ClearPendingException(cx); @@ -461,10 +453,26 @@ nsresult mozJSSubScriptLoader::DoLoadSubScriptWithOptions( if (!stencil) { // Store into startup cache only when the script isn't come from any cache. storeIntoStartupCache = cache; + + JS::CompileOptions compileOptions(cx); + ScriptPreloader::FillCompileOptionsForCachedStencil(compileOptions); + compileOptions.setFileAndLine(uriStr.get(), 1); + compileOptions.setNonSyntacticScope(!JS_IsGlobalObject(targetObj)); + + if (options.wantReturnValue) { + compileOptions.setNoScriptRval(false); + } + if (!ReadStencil(getter_AddRefs(stencil), uri, cx, compileOptions, serv, useCompilationScope)) { return NS_OK; } + +#ifdef DEBUG + // The above shouldn't touch any options for instantiation. + JS::InstantiateOptions instantiateOptions(compileOptions); + instantiateOptions.assertDefault(); +#endif } // As a policy choice, we don't store scripts that want return values @@ -472,7 +480,6 @@ nsresult mozJSSubScriptLoader::DoLoadSubScriptWithOptions( bool storeIntoPreloadCache = !ignoreCache && !options.wantReturnValue; Unused << EvalStencil(cx, targetObj, loadScope, retval, uri, - storeIntoStartupCache, storeIntoPreloadCache, - compileOptions, stencil); + storeIntoStartupCache, storeIntoPreloadCache, stencil); return NS_OK; }