Bug 1726498 - Add JS::DecodeOptions. r=tcampbell

Differential Revision: https://phabricator.services.mozilla.com/D128345
This commit is contained in:
Tooru Fujisawa 2021-10-21 21:48:48 +00:00
parent c9ab159bb0
commit c30ad11d7f
20 changed files with 187 additions and 104 deletions

View File

@ -180,7 +180,9 @@ nsresult JSExecutionContext::Decode(mozilla::Vector<uint8_t>& 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<uint8_t>& aBytecodeBuf,
MOZ_ASSERT(!mWantsReturnValue);
RefPtr<JS::Stencil> 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.

View File

@ -1271,14 +1271,12 @@ nsMessageManagerScriptExecutor::TryCacheLoadAndCompileScript(
}
JSContext* cx = jsapi.cx();
JS::CompileOptions options(cx);
FillCompileOptionsForCachedStencil(options);
options.setFileAndLine(url.get(), 1);
RefPtr<JS::Stencil> 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);

View File

@ -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<JS::Stencil> newStencil;
rv = ReadStencil(aStream, cx, options, getter_AddRefs(newStencil));
NS_ENSURE_SUCCESS(rv, rv);

View File

@ -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 */

View File

@ -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);

View File

@ -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<CompilationInput> input(cx, CompilationInput(options));
if (!input.get().initForGlobal(cx)) {
RefPtr<ScriptSource> source = cx->new_<ScriptSource>();
if (!source) {
return TranscodeResult::Throw;
}
UniquePtr<JS::Stencil> stencil(
MakeUnique<CompilationStencil>(input.get().source));
UniquePtr<JS::Stencil> stencil(MakeUnique<CompilationStencil>(source));
if (!stencil) {
return TranscodeResult::Throw;
}

View File

@ -238,13 +238,13 @@ BEGIN_TEST(testStencil_Transcode) {
{
// Decode the stencil into new range
JS::CompileOptions options(cx);
RefPtr<JS::Stencil> 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<JS::Stencil> 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);
}

View File

@ -2474,8 +2474,10 @@ static bool Evaluate(JSContext* cx, unsigned argc, Value* vp) {
RefPtr<JS::Stencil> 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;
}

View File

@ -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<JS::Stencil> 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;
}

View File

@ -2195,7 +2195,9 @@ XDRResult ScriptSource::xdrData(XDRState<mode>* const xdr,
template <XDRMode mode>
/* static */
XDRResult ScriptSource::XDR(XDRState<mode>* xdr, RefPtr<ScriptSource>& source) {
XDRResult ScriptSource::XDR(XDRState<mode>* xdr,
const JS::DecodeOptions* maybeOptions,
RefPtr<ScriptSource>& source) {
JSContext* cx = xdr->cx();
if (mode == XDR_DECODE) {
@ -2283,6 +2285,18 @@ XDRResult ScriptSource::XDR(XDRState<mode>* xdr, RefPtr<ScriptSource>& 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<mode>* xdr, RefPtr<ScriptSource>& source) {
template /* static */
XDRResult
ScriptSource::XDR(XDRState<XDR_ENCODE>* xdr, RefPtr<ScriptSource>& holder);
ScriptSource::XDR(XDRState<XDR_ENCODE>* xdr,
const JS::DecodeOptions* maybeOptions,
RefPtr<ScriptSource>& holder);
template /* static */
XDRResult
ScriptSource::XDR(XDRState<XDR_DECODE>* xdr, RefPtr<ScriptSource>& holder);
ScriptSource::XDR(XDRState<XDR_DECODE>* xdr,
const JS::DecodeOptions* maybeOptions,
RefPtr<ScriptSource>& holder);
// Format and return a cx->pod_malloc'ed URL for a generated script like:
// {filename} line {lineno} > {introducer}

View File

@ -1058,6 +1058,7 @@ class ScriptSource {
public:
template <XDRMode mode>
[[nodiscard]] static XDRResult XDR(XDRState<mode>* xdr,
const JS::DecodeOptions* maybeOptions,
RefPtr<ScriptSource>& source);
};

View File

@ -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<uint8_t>& buffer /* TranscodeBuffer& */, size_t cursor,

View File

@ -247,12 +247,13 @@ static XDRResult VersionCheck(XDRState<mode>* xdr) {
template <XDRMode mode>
static XDRResult XDRStencilHeader(XDRState<mode>* xdr,
const JS::DecodeOptions* maybeOptions,
RefPtr<ScriptSource>& 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<RefPtr<ScriptSource>&>(source)));
MOZ_TRY(XDRStencilHeader(this, nullptr,
const_cast<RefPtr<ScriptSource>&>(source)));
MOZ_TRY(frontend::StencilXDR::codeCompilationStencil(
this, const_cast<frontend::CompilationStencil&>(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();

View File

@ -19,7 +19,7 @@
#include <type_traits> // 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<XDR_DECODE> {
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;

View File

@ -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<JS::Stencil> 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<JS::Stencil> ScriptPreloader::GetCachedStencil(
}
already_AddRefed<JS::Stencil> 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<JS::Stencil> ScriptPreloader::GetCachedStencilInternal(
}
already_AddRefed<JS::Stencil> 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<JS::Stencil> ScriptPreloader::CachedStencil::GetStencil(
JSContext* cx, const JS::ReadOnlyCompileOptions& options) {
JSContext* cx, const JS::DecodeOptions& options) {
MOZ_ASSERT(mReadyToExecute);
if (mStencil) {
return do_AddRef(mStencil);

View File

@ -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<JS::Stencil> 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<Ok, nsresult> InitCacheInternal(JS::HandleObject scope = nullptr);
already_AddRefed<JS::Stencil> 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<nsTArray<uint8_t>>(); }
already_AddRefed<JS::Stencil> GetStencil(
JSContext* cx, const JS::ReadOnlyCompileOptions& options);
already_AddRefed<JS::Stencil> 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<JS::Stencil> 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);

View File

@ -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<JS::Stencil> 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.

View File

@ -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;

View File

@ -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,

View File

@ -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<JS::Stencil> 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;
}