mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 13:51:41 +00:00
Bug 1726498 - Add JS::DecodeOptions. r=tcampbell
Differential Revision: https://phabricator.services.mozilla.com/D128345
This commit is contained in:
parent
c9ab159bb0
commit
c30ad11d7f
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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}
|
||||
|
@ -1058,6 +1058,7 @@ class ScriptSource {
|
||||
public:
|
||||
template <XDRMode mode>
|
||||
[[nodiscard]] static XDRResult XDR(XDRState<mode>* xdr,
|
||||
const JS::DecodeOptions* maybeOptions,
|
||||
RefPtr<ScriptSource>& source);
|
||||
};
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user