зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1662273 - Use stencil XDR in incremental encoding and off-thread single script decoding. r=tcampbell
Differential Revision: https://phabricator.services.mozilla.com/D91437
This commit is contained in:
Родитель
2119eb41da
Коммит
9ef7fb0845
|
@ -272,8 +272,8 @@ nsresult nsJSUtils::ExecutionContext::Decode(
|
|||
}
|
||||
|
||||
MOZ_ASSERT(!mWantsReturnValue);
|
||||
JS::TranscodeResult tr =
|
||||
JS::DecodeScript(mCx, aBytecodeBuf, &mScript, aBytecodeIndex);
|
||||
JS::TranscodeResult tr = JS::DecodeScriptMaybeStencil(
|
||||
mCx, aBytecodeBuf, aCompileOptions, &mScript, aBytecodeIndex);
|
||||
// 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.
|
||||
|
|
|
@ -117,6 +117,11 @@ extern JS_PUBLIC_API void CancelOffThreadModule(JSContext* cx,
|
|||
extern JS_PUBLIC_API bool CanDecodeOffThread(
|
||||
JSContext* cx, const ReadOnlyCompileOptions& options, size_t length);
|
||||
|
||||
// If options.useOffThreadParseGlobal is true,
|
||||
// decode JSScript from the buffer.
|
||||
//
|
||||
// If options.useOffThreadParseGlobal is false,
|
||||
// decode stencil from the buffer and instantiate JSScript from it.
|
||||
extern JS_PUBLIC_API bool DecodeOffThreadScript(
|
||||
JSContext* cx, const ReadOnlyCompileOptions& options,
|
||||
mozilla::Vector<uint8_t>& buffer /* TranscodeBuffer& */, size_t cursor,
|
||||
|
@ -135,6 +140,7 @@ extern JS_PUBLIC_API JSScript* FinishOffThreadScriptDecoder(
|
|||
extern JS_PUBLIC_API void CancelOffThreadScriptDecoder(JSContext* cx,
|
||||
OffThreadToken* token);
|
||||
|
||||
// Decode multiple JSScript from the sources.
|
||||
extern JS_PUBLIC_API bool DecodeMultiOffThreadScripts(
|
||||
JSContext* cx, const ReadOnlyCompileOptions& options,
|
||||
mozilla::Vector<TranscodeSource>& sources,
|
||||
|
@ -157,6 +163,11 @@ extern JS_PUBLIC_API void SetUseOffThreadParseGlobal(bool value);
|
|||
} // namespace JS
|
||||
|
||||
namespace js {
|
||||
// Returns the value set by JS::SetUseOffThreadParseGlobal.
|
||||
// The default value is true.
|
||||
//
|
||||
// This value is consumed internally, and public API consumer shouldn't
|
||||
// directly use this value.
|
||||
extern bool UseOffThreadParseGlobal();
|
||||
} // namespace js
|
||||
|
||||
|
|
|
@ -25,6 +25,8 @@ class JS_PUBLIC_API JSScript;
|
|||
|
||||
namespace JS {
|
||||
|
||||
class ReadOnlyCompileOptions;
|
||||
|
||||
using TranscodeBuffer = mozilla::Vector<uint8_t>;
|
||||
using TranscodeRange = mozilla::Range<uint8_t>;
|
||||
|
||||
|
@ -70,14 +72,32 @@ extern JS_PUBLIC_API TranscodeResult
|
|||
DecodeScript(JSContext* cx, const TranscodeRange& range,
|
||||
MutableHandle<JSScript*> scriptp);
|
||||
|
||||
// Decode JSScript from the buffer, and register an encoder on its script
|
||||
// source, such that all functions can be encoded as they are parsed. This
|
||||
// strategy is used to avoid blocking the main thread in a non-interruptible
|
||||
// way.
|
||||
// If js::UseOffThreadParseGlobal is true, decode JSScript from the buffer.
|
||||
//
|
||||
// If js::UseOffThreadParseGlobal is false, decode CompilationStencil from the
|
||||
// buffer and instantiate JSScript from it.
|
||||
//
|
||||
// options.useOffThreadParseGlobal should match JS::SetUseOffThreadParseGlobal.
|
||||
extern JS_PUBLIC_API TranscodeResult DecodeScriptMaybeStencil(
|
||||
JSContext* cx, TranscodeBuffer& buffer,
|
||||
const ReadOnlyCompileOptions& options, MutableHandle<JSScript*> scriptp,
|
||||
size_t cursorIndex = 0);
|
||||
|
||||
// If js::UseOffThreadParseGlobal is true, decode JSScript from the buffer.
|
||||
//
|
||||
// If js::UseOffThreadParseGlobal is false, decode CompilationStencil from the
|
||||
// buffer and instantiate JSScript from it.
|
||||
//
|
||||
// And then register an encoder on its script source, such that all functions
|
||||
// can be encoded as they are parsed. This strategy is used to avoid blocking
|
||||
// the main thread in a non-interruptible way.
|
||||
//
|
||||
// See also JS::FinishIncrementalEncoding.
|
||||
//
|
||||
// options.useOffThreadParseGlobal should match JS::SetUseOffThreadParseGlobal.
|
||||
extern JS_PUBLIC_API TranscodeResult DecodeScriptAndStartIncrementalEncoding(
|
||||
JSContext* cx, TranscodeBuffer& buffer, MutableHandle<JSScript*> scriptp,
|
||||
JSContext* cx, TranscodeBuffer& buffer,
|
||||
const ReadOnlyCompileOptions& options, MutableHandle<JSScript*> scriptp,
|
||||
size_t cursorIndex = 0);
|
||||
|
||||
// Finish incremental encoding started by one of:
|
||||
|
@ -91,6 +111,11 @@ extern JS_PUBLIC_API TranscodeResult DecodeScriptAndStartIncrementalEncoding(
|
|||
// The |buffer| argument of |FinishIncrementalEncoding| is used for appending
|
||||
// the encoded bytecode into the buffer. If any of these functions failed, the
|
||||
// content of |buffer| would be undefined.
|
||||
//
|
||||
// If js::UseOffThreadParseGlobal is true, |buffer| contains encoded JSScript.
|
||||
//
|
||||
// If js::UseOffThreadParseGlobal is false, |buffer| contains encoded
|
||||
// CompilationStencil.
|
||||
extern JS_PUBLIC_API bool FinishIncrementalEncoding(JSContext* cx,
|
||||
Handle<JSScript*> script,
|
||||
TranscodeBuffer& buffer);
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
#include "jstypes.h" // JS_PUBLIC_API
|
||||
|
||||
#include "frontend/CompilationInfo.h" // CompilationInfo, CompilationGCOutput
|
||||
#include "frontend/CompilationInfo.h" // CompilationInfo, CompilationInfoVector, CompilationGCOutput
|
||||
#include "frontend/ParseContext.h" // js::frontend::UsedNameTracker
|
||||
#include "frontend/SharedContext.h" // js::frontend::Directives, js::frontend::{,Eval,Global}SharedContext
|
||||
#include "js/CompileOptions.h" // JS::ReadOnlyCompileOptions
|
||||
|
@ -70,6 +70,10 @@ extern UniquePtr<CompilationInfo> CompileGlobalScriptToStencil(
|
|||
extern bool InstantiateStencils(JSContext* cx, CompilationInfo& compilationInfo,
|
||||
CompilationGCOutput& gcOutput);
|
||||
|
||||
extern bool InstantiateStencils(JSContext* cx,
|
||||
CompilationInfoVector& compilationInfos,
|
||||
CompilationGCOutput& gcOutput);
|
||||
|
||||
extern JSScript* CompileGlobalScript(JSContext* cx,
|
||||
const JS::ReadOnlyCompileOptions& options,
|
||||
JS::SourceText<char16_t>& srcBuf,
|
||||
|
|
|
@ -346,6 +346,32 @@ bool frontend::InstantiateStencils(JSContext* cx,
|
|||
return true;
|
||||
}
|
||||
|
||||
bool frontend::InstantiateStencils(JSContext* cx,
|
||||
CompilationInfoVector& compilationInfos,
|
||||
CompilationGCOutput& gcOutput) {
|
||||
{
|
||||
AutoGeckoProfilerEntry pseudoFrame(cx, "stencil instantiate",
|
||||
JS::ProfilingCategoryPair::JS_Parsing);
|
||||
|
||||
if (!compilationInfos.instantiateStencils(cx, gcOutput)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Enqueue an off-thread source compression task after finishing parsing.
|
||||
if (!cx->isHelperThreadContext()) {
|
||||
if (!compilationInfos.initial.input.source()->tryCompressOffThread(cx)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
tellDebuggerAboutCompiledScript(
|
||||
cx, compilationInfos.initial.input.options.hideScriptFromDebugger,
|
||||
gcOutput.script);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Unit>
|
||||
static JSScript* CompileGlobalScriptImpl(
|
||||
JSContext* cx, const JS::ReadOnlyCompileOptions& options,
|
||||
|
|
|
@ -14,5 +14,6 @@ var test = (function () {
|
|||
try {
|
||||
evalWithCache(test, {});
|
||||
} catch (x) {
|
||||
assertEq(x.message.includes("Asm.js is not supported by XDR"), true);
|
||||
assertEq(x.message.includes("Asm.js is not supported by XDR") ||
|
||||
x.message.includes("XDR encoding failure"), true);
|
||||
}
|
||||
|
|
|
@ -2,9 +2,9 @@ load(libdir + "asserts.js")
|
|||
|
||||
// JS::EncodeScript cannot be use for run-once scripts.
|
||||
evaluate(cacheEntry(""), { saveBytecode: true });
|
||||
evaluate(cacheEntry(""), { saveBytecode: true, isRunOnce: false })
|
||||
evaluate(cacheEntry(""), { saveBytecode: true, isRunOnce: false });
|
||||
assertErrorMessage(() => {
|
||||
evaluate(cacheEntry(""), { saveBytecode: true, isRunOnce: true })
|
||||
evaluate(cacheEntry(""), { saveBytecode: true, isRunOnce: true });
|
||||
}, Error, "run-once script are not supported by XDR");
|
||||
|
||||
// Incremental XDR doesn't have any of these restrictions.
|
||||
|
|
|
@ -42,7 +42,9 @@
|
|||
#ifdef JS_HAS_TYPED_OBJECTS
|
||||
# include "builtin/TypedObject.h"
|
||||
#endif
|
||||
#include "frontend/BytecodeCompilation.h" // frontend::CompileGlobalScriptToStencil, frontend::InstantiateStencils
|
||||
#include "frontend/BytecodeCompiler.h"
|
||||
#include "frontend/CompilationInfo.h" // frontend::CompilationInfo, frontend::CompilationInfoVector, frontend::CompilationGCOutput
|
||||
#include "gc/FreeOp.h"
|
||||
#include "gc/Marking.h"
|
||||
#include "gc/Policy.h"
|
||||
|
@ -5719,6 +5721,57 @@ JS_PUBLIC_API JS::TranscodeResult JS::DecodeScript(
|
|||
return JS::TranscodeResult_Ok;
|
||||
}
|
||||
|
||||
static JS::TranscodeResult DecodeStencil(
|
||||
JSContext* cx, JS::TranscodeBuffer& buffer,
|
||||
frontend::CompilationInfoVector& compilationInfos, size_t cursorIndex) {
|
||||
XDRStencilDecoder decoder(cx, &compilationInfos.initial.input.options, buffer,
|
||||
cursorIndex,
|
||||
compilationInfos.initial.stencil.parserAtoms);
|
||||
|
||||
if (!compilationInfos.initial.input.initForGlobal(cx)) {
|
||||
return JS::TranscodeResult_Throw;
|
||||
}
|
||||
|
||||
XDRResult res = decoder.codeStencils(compilationInfos);
|
||||
if (res.isErr()) {
|
||||
return res.unwrapErr();
|
||||
}
|
||||
|
||||
return JS::TranscodeResult_Ok;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API JS::TranscodeResult JS::DecodeScriptMaybeStencil(
|
||||
JSContext* cx, TranscodeBuffer& buffer,
|
||||
const ReadOnlyCompileOptions& options, JS::MutableHandleScript scriptp,
|
||||
size_t cursorIndex) {
|
||||
MOZ_ASSERT(options.useOffThreadParseGlobal == js::UseOffThreadParseGlobal());
|
||||
if (js::UseOffThreadParseGlobal()) {
|
||||
// The buffer contains JSScript.
|
||||
return JS::DecodeScript(cx, buffer, scriptp, cursorIndex);
|
||||
}
|
||||
|
||||
// The buffer contains stencil.
|
||||
|
||||
Rooted<frontend::CompilationInfoVector> compilationInfos(
|
||||
cx, frontend::CompilationInfoVector(cx, options));
|
||||
|
||||
JS::TranscodeResult res =
|
||||
DecodeStencil(cx, buffer, compilationInfos.get(), cursorIndex);
|
||||
if (res != JS::TranscodeResult_Ok) {
|
||||
return res;
|
||||
}
|
||||
|
||||
frontend::CompilationGCOutput gcOutput(cx);
|
||||
if (!frontend::InstantiateStencils(cx, compilationInfos.get(), gcOutput)) {
|
||||
return JS::TranscodeResult_Throw;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(gcOutput.script);
|
||||
scriptp.set(gcOutput.script);
|
||||
|
||||
return JS::TranscodeResult_Ok;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API JS::TranscodeResult JS::DecodeScript(
|
||||
JSContext* cx, const TranscodeRange& range,
|
||||
JS::MutableHandleScript scriptp) {
|
||||
|
@ -5737,9 +5790,13 @@ JS_PUBLIC_API JS::TranscodeResult JS::DecodeScript(
|
|||
}
|
||||
|
||||
JS_PUBLIC_API JS::TranscodeResult JS::DecodeScriptAndStartIncrementalEncoding(
|
||||
JSContext* cx, TranscodeBuffer& buffer, JS::MutableHandleScript scriptp,
|
||||
JSContext* cx, TranscodeBuffer& buffer,
|
||||
const ReadOnlyCompileOptions& options, JS::MutableHandleScript scriptp,
|
||||
size_t cursorIndex) {
|
||||
JS::TranscodeResult res = JS::DecodeScript(cx, buffer, scriptp, cursorIndex);
|
||||
MOZ_ASSERT(options.useOffThreadParseGlobal == js::UseOffThreadParseGlobal());
|
||||
if (js::UseOffThreadParseGlobal()) {
|
||||
JS::TranscodeResult res =
|
||||
JS::DecodeScript(cx, buffer, scriptp, cursorIndex);
|
||||
if (res != JS::TranscodeResult_Ok) {
|
||||
return res;
|
||||
}
|
||||
|
@ -5751,13 +5808,41 @@ JS_PUBLIC_API JS::TranscodeResult JS::DecodeScriptAndStartIncrementalEncoding(
|
|||
return JS::TranscodeResult_Ok;
|
||||
}
|
||||
|
||||
Rooted<frontend::CompilationInfoVector> compilationInfos(
|
||||
cx, frontend::CompilationInfoVector(cx, options));
|
||||
|
||||
JS::TranscodeResult res =
|
||||
DecodeStencil(cx, buffer, compilationInfos.get(), cursorIndex);
|
||||
if (res != JS::TranscodeResult_Ok) {
|
||||
return res;
|
||||
}
|
||||
|
||||
UniquePtr<XDRIncrementalEncoderBase> xdrEncoder;
|
||||
if (!compilationInfos.get().initial.input.source()->xdrEncodeStencils(
|
||||
cx, compilationInfos.get(), xdrEncoder)) {
|
||||
return JS::TranscodeResult_Throw;
|
||||
}
|
||||
|
||||
frontend::CompilationGCOutput gcOutput(cx);
|
||||
if (!frontend::InstantiateStencils(cx, compilationInfos.get(), gcOutput)) {
|
||||
return JS::TranscodeResult_Throw;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(gcOutput.script);
|
||||
gcOutput.script->scriptSource()->setIncrementalEncoder(xdrEncoder.release());
|
||||
|
||||
scriptp.set(gcOutput.script);
|
||||
|
||||
return JS::TranscodeResult_Ok;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API bool JS::FinishIncrementalEncoding(JSContext* cx,
|
||||
JS::HandleScript script,
|
||||
TranscodeBuffer& buffer) {
|
||||
if (!script) {
|
||||
return false;
|
||||
}
|
||||
if (!script->scriptSource()->xdrFinalizeEncoder(buffer)) {
|
||||
if (!script->scriptSource()->xdrFinalizeEncoder(cx, buffer)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
|
|
@ -122,7 +122,7 @@
|
|||
#include "js/MemoryFunctions.h"
|
||||
#include "js/Modules.h" // JS::GetModulePrivate, JS::SetModule{DynamicImport,Metadata,Resolve}Hook, JS::SetModulePrivate
|
||||
#include "js/Object.h" // JS::GetClass, JS::GetCompartment, JS::GetReservedSlot, JS::SetReservedSlot
|
||||
#include "js/OffThreadScriptCompilation.h" // JS::SetUseOffThreadParseGlobal
|
||||
#include "js/OffThreadScriptCompilation.h" // JS::SetUseOffThreadParseGlobal, js::UseOffThreadParseGlobal
|
||||
#include "js/Printf.h"
|
||||
#include "js/PropertySpec.h"
|
||||
#include "js/Realm.h"
|
||||
|
@ -1910,9 +1910,16 @@ static void my_LargeAllocFailCallback() {
|
|||
|
||||
static const uint32_t CacheEntry_SOURCE = 0;
|
||||
static const uint32_t CacheEntry_BYTECODE = 1;
|
||||
static const uint32_t CacheEntry_KIND = 2;
|
||||
|
||||
enum class BytecodeCacheKind : uint32_t {
|
||||
Undefined = 0,
|
||||
Script,
|
||||
Stencil,
|
||||
};
|
||||
|
||||
static const JSClass CacheEntry_class = {"CacheEntryObject",
|
||||
JSCLASS_HAS_RESERVED_SLOTS(2)};
|
||||
JSCLASS_HAS_RESERVED_SLOTS(3)};
|
||||
|
||||
static bool CacheEntry(JSContext* cx, unsigned argc, JS::Value* vp) {
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
@ -1930,6 +1937,8 @@ static bool CacheEntry(JSContext* cx, unsigned argc, JS::Value* vp) {
|
|||
|
||||
JS::SetReservedSlot(obj, CacheEntry_SOURCE, args[0]);
|
||||
JS::SetReservedSlot(obj, CacheEntry_BYTECODE, UndefinedValue());
|
||||
JS::SetReservedSlot(obj, CacheEntry_KIND,
|
||||
Int32Value(int32_t(BytecodeCacheKind::Undefined)));
|
||||
args.rval().setObject(*obj);
|
||||
return true;
|
||||
}
|
||||
|
@ -1950,6 +1959,18 @@ static JSString* CacheEntry_getSource(JSContext* cx, HandleObject cache) {
|
|||
return v.toString();
|
||||
}
|
||||
|
||||
static BytecodeCacheKind CacheEntry_getKind(JSContext* cx, HandleObject cache) {
|
||||
MOZ_ASSERT(CacheEntry_isCacheEntry(cache));
|
||||
Value v = JS::GetReservedSlot(cache, CacheEntry_KIND);
|
||||
return BytecodeCacheKind(v.toInt32());
|
||||
}
|
||||
|
||||
static void CacheEntry_setKind(JSContext* cx, HandleObject cache,
|
||||
BytecodeCacheKind kind) {
|
||||
MOZ_ASSERT(CacheEntry_isCacheEntry(cache));
|
||||
JS::SetReservedSlot(cache, CacheEntry_KIND, Int32Value(int32_t(kind)));
|
||||
}
|
||||
|
||||
static uint8_t* CacheEntry_getBytecode(JSContext* cx, HandleObject cache,
|
||||
uint32_t* length) {
|
||||
MOZ_ASSERT(CacheEntry_isCacheEntry(cache));
|
||||
|
@ -2210,6 +2231,8 @@ static bool Evaluate(JSContext* cx, unsigned argc, Value* vp) {
|
|||
|
||||
JS::TranscodeBuffer loadBuffer;
|
||||
JS::TranscodeBuffer saveBuffer;
|
||||
BytecodeCacheKind loadCacheKind = BytecodeCacheKind::Undefined;
|
||||
BytecodeCacheKind saveCacheKind = BytecodeCacheKind::Undefined;
|
||||
|
||||
if (loadBytecode) {
|
||||
uint32_t loadLength = 0;
|
||||
|
@ -2222,6 +2245,7 @@ static bool Evaluate(JSContext* cx, unsigned argc, Value* vp) {
|
|||
JS_ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
loadCacheKind = CacheEntry_getKind(cx, cacheEntry);
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -2232,14 +2256,49 @@ static bool Evaluate(JSContext* cx, unsigned argc, Value* vp) {
|
|||
if (loadBytecode) {
|
||||
JS::TranscodeResult rv;
|
||||
if (saveIncrementalBytecode) {
|
||||
rv = JS::DecodeScriptAndStartIncrementalEncoding(cx, loadBuffer,
|
||||
&script);
|
||||
} else {
|
||||
rv = JS::DecodeScript(cx, loadBuffer, &script);
|
||||
if (js::UseOffThreadParseGlobal()) {
|
||||
if (CacheEntry_getKind(cx, cacheEntry) !=
|
||||
BytecodeCacheKind::Script) {
|
||||
// NOTE: This shouldn't happen unless the cache is used across
|
||||
// processes with different --no-off-thread-parse-global option.
|
||||
JS_ReportErrorASCII(
|
||||
cx,
|
||||
"if both loadBytecode and saveIncrementalBytecode are set "
|
||||
"and --no-off-thread-parse-global isn't used, bytecode "
|
||||
"should be saved with saveBytecode");
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (CacheEntry_getKind(cx, cacheEntry) !=
|
||||
BytecodeCacheKind::Stencil) {
|
||||
// This can happen.
|
||||
JS_ReportErrorASCII(
|
||||
cx,
|
||||
"if both loadBytecode and saveIncrementalBytecode are set "
|
||||
"and --no-off-thread-parse-global is used, bytecode should "
|
||||
"be saved with saveIncrementalBytecode");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
rv = JS::DecodeScriptAndStartIncrementalEncoding(cx, loadBuffer,
|
||||
options, &script);
|
||||
if (!ConvertTranscodeResultToJSException(cx, rv)) {
|
||||
return false;
|
||||
}
|
||||
} else if (loadCacheKind == BytecodeCacheKind::Script) {
|
||||
rv = JS::DecodeScript(cx, loadBuffer, &script);
|
||||
if (!ConvertTranscodeResultToJSException(cx, rv)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
MOZ_ASSERT(loadCacheKind == BytecodeCacheKind::Stencil);
|
||||
MOZ_ASSERT(!js::UseOffThreadParseGlobal());
|
||||
rv = JS::DecodeScriptMaybeStencil(cx, loadBuffer, options, &script);
|
||||
if (!ConvertTranscodeResultToJSException(cx, rv)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
mozilla::Range<const char16_t> chars = codeChars.twoByteRange();
|
||||
JS::SourceText<char16_t> srcBuf;
|
||||
|
@ -2254,14 +2313,16 @@ static bool Evaluate(JSContext* cx, unsigned argc, Value* vp) {
|
|||
|
||||
if (saveIncrementalBytecode) {
|
||||
script = JS::CompileAndStartIncrementalEncoding(cx, options, srcBuf);
|
||||
} else {
|
||||
script = JS::Compile(cx, options, srcBuf);
|
||||
}
|
||||
}
|
||||
|
||||
if (!script) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
script = JS::Compile(cx, options, srcBuf);
|
||||
if (!script) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (displayURL && !script->scriptSource()->hasDisplayURL()) {
|
||||
|
@ -2302,6 +2363,7 @@ static bool Evaluate(JSContext* cx, unsigned argc, Value* vp) {
|
|||
if (!ConvertTranscodeResultToJSException(cx, rv)) {
|
||||
return false;
|
||||
}
|
||||
saveCacheKind = BytecodeCacheKind::Script;
|
||||
}
|
||||
|
||||
// Serialize the encoded bytecode, recorded before the execution, into a
|
||||
|
@ -2310,6 +2372,11 @@ static bool Evaluate(JSContext* cx, unsigned argc, Value* vp) {
|
|||
if (!FinishIncrementalEncoding(cx, script, saveBuffer)) {
|
||||
return false;
|
||||
}
|
||||
if (js::UseOffThreadParseGlobal()) {
|
||||
saveCacheKind = BytecodeCacheKind::Script;
|
||||
} else {
|
||||
saveCacheKind = BytecodeCacheKind::Stencil;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2347,6 +2414,8 @@ static bool Evaluate(JSContext* cx, unsigned argc, Value* vp) {
|
|||
js_free(saveData);
|
||||
return false;
|
||||
}
|
||||
MOZ_ASSERT(saveCacheKind != BytecodeCacheKind::Undefined);
|
||||
CacheEntry_setKind(cx, cacheEntry, saveCacheKind);
|
||||
}
|
||||
|
||||
return JS_WrapValue(cx, args.rval());
|
||||
|
@ -5756,6 +5825,10 @@ static bool OffThreadDecodeScript(JSContext* cx, unsigned argc, Value* vp) {
|
|||
CompileOptions options(cx);
|
||||
options.setIntroductionType("js shell offThreadDecodeScript")
|
||||
.setFileAndLine("<string>", 1);
|
||||
// NOTE: If --no-off-thread-parse-global is used, input can be either script
|
||||
// for saveBytecode, or stencil for saveIncrementalBytecode.
|
||||
options.useOffThreadParseGlobal =
|
||||
CacheEntry_getKind(cx, cacheEntry) == BytecodeCacheKind::Script;
|
||||
|
||||
if (args.length() >= 2) {
|
||||
if (args[1].isPrimitive()) {
|
||||
|
@ -8503,8 +8576,18 @@ static const JSFunctionSpecWithHelp shell_functions[] = {
|
|||
" saveBytecode: if true, and if the source is a CacheEntryObject,\n"
|
||||
" the bytecode would be encoded and saved into the cache entry after\n"
|
||||
" the script execution.\n"
|
||||
" assertEqBytecode: if true, and if both loadBytecode and saveBytecode are \n"
|
||||
" true, then the loaded bytecode and the encoded bytecode are compared.\n"
|
||||
" The encoded bytecode's kind is 'script'\n"
|
||||
" saveIncrementalBytecode: if true, and if the source is a\n"
|
||||
" CacheEntryObject, the bytecode would be incrementally encoded and\n"
|
||||
" saved into the cache entry.\n"
|
||||
" If --no-off-thread-parse-global is used, the encoded bytecode's\n"
|
||||
" kind is 'stencil'. If not, the encoded bytecode's kind is 'script'\n"
|
||||
" If both loadBytecode and saveIncrementalBytecode are set,\n"
|
||||
" and --no-off-thread-parse-global is used, the input bytecode's\n"
|
||||
" kind should be 'stencil'."
|
||||
" assertEqBytecode: if true, and if both loadBytecode and either\n"
|
||||
" saveBytecode or saveIncrementalBytecode is true, then the loaded\n"
|
||||
" bytecode and the encoded bytecode are compared.\n"
|
||||
" and an assertion is raised if they differ.\n"
|
||||
" envChainObject: object to put on the scope chain, with its fields added\n"
|
||||
" as var bindings, akin to how elements are added to the environment in\n"
|
||||
|
|
|
@ -84,14 +84,53 @@ template <typename Unit>
|
|||
static JSScript* CompileSourceBufferAndStartIncrementalEncoding(
|
||||
JSContext* cx, const ReadOnlyCompileOptions& options,
|
||||
SourceText<Unit>& srcBuf) {
|
||||
Rooted<JSScript*> script(cx, CompileSourceBuffer(cx, options, srcBuf));
|
||||
ScopeKind scopeKind =
|
||||
options.nonSyntacticScope ? ScopeKind::NonSyntactic : ScopeKind::Global;
|
||||
|
||||
MOZ_ASSERT(!cx->zone()->isAtomsZone());
|
||||
AssertHeapIsIdle();
|
||||
CHECK_THREAD(cx);
|
||||
|
||||
Rooted<frontend::CompilationInfo> compilationInfo(
|
||||
cx, frontend::CompilationInfo(cx, options));
|
||||
if (!compilationInfo.get().input.initForGlobal(cx)) {
|
||||
return nullptr;
|
||||
}
|
||||
if (!frontend::CompileGlobalScriptToStencil(cx, compilationInfo.get(), srcBuf,
|
||||
scopeKind)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
UniquePtr<XDRIncrementalEncoderBase> xdrEncoder;
|
||||
MOZ_ASSERT(options.useOffThreadParseGlobal == js::UseOffThreadParseGlobal());
|
||||
if (!js::UseOffThreadParseGlobal()) {
|
||||
if (!compilationInfo.get().input.source()->xdrEncodeInitialStencil(
|
||||
cx, compilationInfo.get(), xdrEncoder)) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
frontend::CompilationGCOutput gcOutput(cx);
|
||||
if (!frontend::InstantiateStencils(cx, compilationInfo.get(), gcOutput)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(gcOutput.script);
|
||||
if (!js::UseOffThreadParseGlobal()) {
|
||||
gcOutput.script->scriptSource()->setIncrementalEncoder(
|
||||
xdrEncoder.release());
|
||||
}
|
||||
|
||||
Rooted<JSScript*> script(cx, gcOutput.script);
|
||||
if (!script) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (js::UseOffThreadParseGlobal()) {
|
||||
if (!script->scriptSource()->xdrEncodeTopLevel(cx, script)) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return script;
|
||||
}
|
||||
|
|
|
@ -45,6 +45,7 @@ class IonFreeTask;
|
|||
|
||||
namespace frontend {
|
||||
struct CompilationInfo;
|
||||
struct CompilationInfoVector;
|
||||
} // namespace frontend
|
||||
|
||||
namespace wasm {
|
||||
|
@ -524,6 +525,9 @@ struct ParseTask : public mozilla::LinkedListElement<ParseTask>,
|
|||
// Holds the CompilationInfo generated for the script compilation.
|
||||
UniquePtr<frontend::CompilationInfo> compilationInfo_;
|
||||
|
||||
// Holds the CompilationInfoVector generated by decoding task.
|
||||
UniquePtr<frontend::CompilationInfoVector> compilationInfos_;
|
||||
|
||||
// Any errors or warnings produced during compilation. These are reported
|
||||
// when finishing the script.
|
||||
Vector<UniquePtr<CompileError>, 0, SystemAllocPolicy> errors;
|
||||
|
|
|
@ -589,6 +589,9 @@ void ParseTask::trace(JSTracer* trc) {
|
|||
if (compilationInfo_) {
|
||||
compilationInfo_->trace(trc);
|
||||
}
|
||||
if (compilationInfos_) {
|
||||
compilationInfos_->trace(trc);
|
||||
}
|
||||
}
|
||||
|
||||
size_t ParseTask::sizeOfExcludingThis(
|
||||
|
@ -688,12 +691,17 @@ void ScriptParseTask<Unit>::parse(JSContext* cx) {
|
|||
}
|
||||
|
||||
bool ParseTask::instantiateStencils(JSContext* cx) {
|
||||
if (!compilationInfo_) {
|
||||
if (!compilationInfo_ && !compilationInfos_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
frontend::CompilationGCOutput gcOutput(cx);
|
||||
bool result = frontend::InstantiateStencils(cx, *compilationInfo_, gcOutput);
|
||||
bool result;
|
||||
if (compilationInfo_) {
|
||||
result = frontend::InstantiateStencils(cx, *compilationInfo_, gcOutput);
|
||||
} else {
|
||||
result = frontend::InstantiateStencils(cx, *compilationInfos_, gcOutput);
|
||||
}
|
||||
|
||||
// Whatever happens to the top-level script compilation (even if it fails),
|
||||
// we must finish initializing the SSO. This is because there may be valid
|
||||
|
@ -756,6 +764,33 @@ void ScriptDecodeTask::parse(JSContext* cx) {
|
|||
RootedScript resultScript(cx);
|
||||
Rooted<ScriptSourceObject*> sourceObject(cx);
|
||||
|
||||
if (!options.useOffThreadParseGlobal) {
|
||||
// The buffer contains stencil.
|
||||
Rooted<UniquePtr<frontend::CompilationInfoVector>> compilationInfos(
|
||||
cx, js_new<frontend::CompilationInfoVector>(cx, options));
|
||||
if (!compilationInfos) {
|
||||
ReportOutOfMemory(cx);
|
||||
return;
|
||||
}
|
||||
|
||||
XDRStencilDecoder decoder(
|
||||
cx, &compilationInfos.get()->initial.input.options, range,
|
||||
compilationInfos.get()->initial.stencil.parserAtoms);
|
||||
if (!compilationInfos.get()->initial.input.initForGlobal(cx)) {
|
||||
return;
|
||||
}
|
||||
|
||||
XDRResult res = decoder.codeStencils(*compilationInfos);
|
||||
if (!res.isOk()) {
|
||||
return;
|
||||
}
|
||||
|
||||
compilationInfos_ = std::move(compilationInfos.get());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// The buffer contains JSScript.
|
||||
Rooted<UniquePtr<XDROffThreadDecoder>> decoder(
|
||||
cx,
|
||||
js::MakeUnique<XDROffThreadDecoder>(
|
||||
|
@ -999,7 +1034,6 @@ static bool QueueOffThreadParseTask(JSContext* cx, UniquePtr<ParseTask> task) {
|
|||
AutoLockHelperThreadState lock;
|
||||
|
||||
bool needsParseGlobal = task->options.useOffThreadParseGlobal ||
|
||||
(task->kind == ParseTaskKind::ScriptDecode) ||
|
||||
(task->kind == ParseTaskKind::MultiScriptsDecode);
|
||||
bool mustWait =
|
||||
needsParseGlobal && OffThreadParsingMustWaitForGC(cx->runtime());
|
||||
|
@ -1038,9 +1072,8 @@ static bool StartOffThreadParseTask(JSContext* cx, UniquePtr<ParseTask> task,
|
|||
gc::AutoSuppressNurseryCellAlloc noNurseryAlloc(cx);
|
||||
AutoSuppressAllocationMetadataBuilder suppressMetadata(cx);
|
||||
|
||||
// FIXME: XDR currently requires the parse global.
|
||||
bool forceParseGlobal = (task->kind == ParseTaskKind::ScriptDecode) ||
|
||||
(task->kind == ParseTaskKind::MultiScriptsDecode);
|
||||
// FIXME: XDR for ScriptPreloader currently requires the parse global.
|
||||
bool forceParseGlobal = (task->kind == ParseTaskKind::MultiScriptsDecode);
|
||||
|
||||
JSObject* global = nullptr;
|
||||
if (options.useOffThreadParseGlobal || forceParseGlobal) {
|
||||
|
@ -2009,6 +2042,16 @@ JSScript* GlobalHelperThreadState::finishSingleParseTask(
|
|||
|
||||
if (parseTask->compilationInfo_.get() &&
|
||||
!parseTask->options.useOffThreadParseGlobal) {
|
||||
UniquePtr<XDRIncrementalEncoderBase> xdrEncoder;
|
||||
|
||||
if (startEncoding == StartEncoding::Yes) {
|
||||
auto compilationInfo = parseTask->compilationInfo_.get();
|
||||
if (!compilationInfo->input.source()->xdrEncodeInitialStencil(
|
||||
cx, *compilationInfo, xdrEncoder)) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (!parseTask->instantiateStencils(cx)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -2016,6 +2059,33 @@ JSScript* GlobalHelperThreadState::finishSingleParseTask(
|
|||
MOZ_RELEASE_ASSERT(parseTask->scripts.length() == 1);
|
||||
|
||||
script = parseTask->scripts[0];
|
||||
|
||||
if (startEncoding == StartEncoding::Yes) {
|
||||
script->scriptSource()->setIncrementalEncoder(xdrEncoder.release());
|
||||
}
|
||||
} else if (parseTask->compilationInfos_.get() &&
|
||||
!parseTask->options.useOffThreadParseGlobal) {
|
||||
UniquePtr<XDRIncrementalEncoderBase> xdrEncoder;
|
||||
|
||||
if (startEncoding == StartEncoding::Yes) {
|
||||
auto compilationInfos = parseTask->compilationInfos_.get();
|
||||
if (!compilationInfos->initial.input.source()->xdrEncodeStencils(
|
||||
cx, *compilationInfos, xdrEncoder)) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (!parseTask->instantiateStencils(cx)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MOZ_RELEASE_ASSERT(parseTask->scripts.length() == 1);
|
||||
|
||||
script = parseTask->scripts[0];
|
||||
|
||||
if (startEncoding == StartEncoding::Yes) {
|
||||
script->scriptSource()->setIncrementalEncoder(xdrEncoder.release());
|
||||
}
|
||||
} else {
|
||||
MOZ_RELEASE_ASSERT(parseTask->scripts.length() <= 1);
|
||||
|
||||
|
@ -2047,11 +2117,13 @@ JSScript* GlobalHelperThreadState::finishSingleParseTask(
|
|||
}
|
||||
}
|
||||
|
||||
if (parseTask->options.useOffThreadParseGlobal) {
|
||||
if (startEncoding == StartEncoding::Yes) {
|
||||
if (!script->scriptSource()->xdrEncodeTopLevel(cx, script)) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return script;
|
||||
}
|
||||
|
|
|
@ -1597,7 +1597,13 @@ bool DelazifyCanonicalScriptedFunctionImpl(JSContext* cx, HandleFunction fun,
|
|||
return false;
|
||||
}
|
||||
|
||||
// TODO: encode stencil here.
|
||||
if (!js::UseOffThreadParseGlobal()) {
|
||||
if (ss->hasEncoder()) {
|
||||
if (!ss->xdrEncodeFunctionStencil(cx, compilationInfo.get().stencil)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!frontend::InstantiateStencilsForDelazify(cx, compilationInfo.get())) {
|
||||
// The frontend shouldn't fail after linking the function and the
|
||||
|
@ -1608,14 +1614,16 @@ bool DelazifyCanonicalScriptedFunctionImpl(JSContext* cx, HandleFunction fun,
|
|||
}
|
||||
}
|
||||
|
||||
if (js::UseOffThreadParseGlobal()) {
|
||||
// XDR the newly delazified function.
|
||||
if (ss->hasEncoder()) {
|
||||
RootedScriptSourceObject sourceObject(cx,
|
||||
fun->nonLazyScript()->sourceObject());
|
||||
RootedScriptSourceObject sourceObject(
|
||||
cx, fun->nonLazyScript()->sourceObject());
|
||||
if (!ss->xdrEncodeFunction(cx, fun, sourceObject)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
|
||||
#include "frontend/BytecodeCompiler.h"
|
||||
#include "frontend/BytecodeEmitter.h"
|
||||
#include "frontend/CompilationInfo.h" // frontend::CompilationStencil
|
||||
#include "frontend/SharedContext.h"
|
||||
#include "frontend/SourceNotes.h" // SrcNote, SrcNoteType, SrcNoteIterator
|
||||
#include "gc/FreeOp.h"
|
||||
|
@ -2229,7 +2230,7 @@ template <typename Unit>
|
|||
MOZ_MUST_USE bool ScriptSource::setUncompressedSourceHelper(
|
||||
JSContext* cx, EntryUnits<Unit>&& source, size_t length,
|
||||
SourceRetrievable retrievable) {
|
||||
auto& cache = cx->zone()->runtimeFromAnyThread()->sharedImmutableStrings();
|
||||
auto& cache = cx->runtime()->sharedImmutableStrings();
|
||||
|
||||
auto uniqueChars = SourceTypeTraits<Unit>::toCacheable(std::move(source));
|
||||
auto deduped = cache.getOrCreate(std::move(uniqueChars), length);
|
||||
|
@ -2333,7 +2334,7 @@ MOZ_MUST_USE bool ScriptSource::initializeWithUnretrievableCompressedSource(
|
|||
MOZ_ASSERT(data.is<Missing>(), "shouldn't be double-initializing");
|
||||
MOZ_ASSERT(compressed != nullptr);
|
||||
|
||||
auto& cache = cx->zone()->runtimeFromAnyThread()->sharedImmutableStrings();
|
||||
auto& cache = cx->runtime()->sharedImmutableStrings();
|
||||
auto deduped = cache.getOrCreate(std::move(compressed), rawLength);
|
||||
if (!deduped) {
|
||||
ReportOutOfMemory(cx);
|
||||
|
@ -2675,6 +2676,58 @@ bool ScriptSource::xdrEncodeTopLevel(JSContext* cx, HandleScript script) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool ScriptSource::xdrEncodeInitialStencil(
|
||||
JSContext* cx, frontend::CompilationInfo& compilationInfo,
|
||||
UniquePtr<XDRIncrementalEncoderBase>& xdrEncoder) {
|
||||
// Encoding failures are reported by the xdrFinalizeEncoder function.
|
||||
if (containsAsmJS()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
xdrEncoder = js::MakeUnique<XDRIncrementalStencilEncoder>(cx);
|
||||
if (!xdrEncoder) {
|
||||
ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto failureCase = mozilla::MakeScopeExit([&] { xdrEncoder.reset(nullptr); });
|
||||
|
||||
XDRResult res = xdrEncoder->codeStencil(compilationInfo);
|
||||
if (res.isErr()) {
|
||||
// On encoding failure, let failureCase destroy encoder and return true
|
||||
// to avoid failing any currently executing script.
|
||||
if (res.unwrapErr() & JS::TranscodeResult_Failure) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
failureCase.release();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ScriptSource::xdrEncodeStencils(
|
||||
JSContext* cx, frontend::CompilationInfoVector& compilationInfos,
|
||||
UniquePtr<XDRIncrementalEncoderBase>& xdrEncoder) {
|
||||
if (!xdrEncodeInitialStencil(cx, compilationInfos.initial, xdrEncoder)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto& delazification : compilationInfos.delazifications) {
|
||||
if (!xdrEncodeFunctionStencilWith(cx, delazification.stencil, xdrEncoder)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ScriptSource::setIncrementalEncoder(
|
||||
XDRIncrementalEncoderBase* xdrEncoder) {
|
||||
xdrEncoder_.reset(xdrEncoder);
|
||||
}
|
||||
|
||||
bool ScriptSource::xdrEncodeFunction(JSContext* cx, HandleFunction fun,
|
||||
HandleScriptSourceObject sourceObject) {
|
||||
MOZ_ASSERT(sourceObject->source() == this);
|
||||
|
@ -2697,8 +2750,35 @@ bool ScriptSource::xdrEncodeFunction(JSContext* cx, HandleFunction fun,
|
|||
return true;
|
||||
}
|
||||
|
||||
bool ScriptSource::xdrFinalizeEncoder(JS::TranscodeBuffer& buffer) {
|
||||
bool ScriptSource::xdrEncodeFunctionStencil(
|
||||
JSContext* cx, frontend::CompilationStencil& stencil) {
|
||||
MOZ_ASSERT(hasEncoder());
|
||||
return xdrEncodeFunctionStencilWith(cx, stencil, xdrEncoder_);
|
||||
}
|
||||
|
||||
bool ScriptSource::xdrEncodeFunctionStencilWith(
|
||||
JSContext* cx, frontend::CompilationStencil& stencil,
|
||||
UniquePtr<XDRIncrementalEncoderBase>& xdrEncoder) {
|
||||
auto failureCase = mozilla::MakeScopeExit([&] { xdrEncoder.reset(nullptr); });
|
||||
|
||||
XDRResult res = xdrEncoder->codeFunctionStencil(stencil);
|
||||
if (res.isErr()) {
|
||||
// On encoding failure, let failureCase destroy encoder and return true
|
||||
// to avoid failing any currently executing script.
|
||||
if (res.unwrapErr() & JS::TranscodeResult_Failure) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
failureCase.release();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ScriptSource::xdrFinalizeEncoder(JSContext* cx,
|
||||
JS::TranscodeBuffer& buffer) {
|
||||
if (!hasEncoder()) {
|
||||
JS_ReportErrorASCII(cx, "XDR encoding failure");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -77,6 +77,7 @@ class DebugScript;
|
|||
|
||||
namespace frontend {
|
||||
struct CompilationInfo;
|
||||
struct CompilationStencil;
|
||||
struct CompilationGCOutput;
|
||||
class ScriptStencil;
|
||||
} // namespace frontend
|
||||
|
@ -544,7 +545,7 @@ class ScriptSource {
|
|||
// function should be recorded before their first execution.
|
||||
// This value is logically owned by the canonical ScriptSourceObject, and
|
||||
// will be released in the canonical SSO's finalizer.
|
||||
UniquePtr<XDRIncrementalEncoder> xdrEncoder_ = nullptr;
|
||||
UniquePtr<XDRIncrementalEncoderBase> xdrEncoder_ = nullptr;
|
||||
|
||||
// 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
|
||||
|
@ -1016,6 +1017,26 @@ class ScriptSource {
|
|||
// successfully.
|
||||
bool xdrEncodeTopLevel(JSContext* cx, HandleScript script);
|
||||
|
||||
// Create a new XDR encoder, and encode the stencil for the initial
|
||||
// compilation. The created XDR encoder isn't stored into `xdrEncoder_`
|
||||
// field. Caller is responsible for calling `setIncrementalEncoder` after
|
||||
// instantiating stencil (so, corresponding canonical ScriptSourceObject
|
||||
// gets created).
|
||||
bool xdrEncodeInitialStencil(
|
||||
JSContext* cx, frontend::CompilationInfo& compilationInfo,
|
||||
UniquePtr<XDRIncrementalEncoderBase>& xdrEncoder);
|
||||
|
||||
// Create a new XDR encoder, and encode the stencils.
|
||||
// The created XDR encoder isn't stored into `xdrEncoder_` field.
|
||||
// Caller is responsible for calling `setIncrementalEncoder` after
|
||||
// instantiating stencil (so, corresponding canonical ScriptSourceObject
|
||||
// gets created).
|
||||
bool xdrEncodeStencils(JSContext* cx,
|
||||
frontend::CompilationInfoVector& compilationInfos,
|
||||
UniquePtr<XDRIncrementalEncoderBase>& xdrEncoder);
|
||||
|
||||
void setIncrementalEncoder(XDRIncrementalEncoderBase* xdrEncoder);
|
||||
|
||||
// Encode a delazified JSFunction. In case of errors, the XDR encoder is
|
||||
// freed and the |buffer| provided as argument to |xdrEncodeTopLevel| is
|
||||
// considered undefined.
|
||||
|
@ -1025,10 +1046,23 @@ class ScriptSource {
|
|||
bool xdrEncodeFunction(JSContext* cx, HandleFunction fun,
|
||||
HandleScriptSourceObject sourceObject);
|
||||
|
||||
// Encode a delazified function's stencil. In case of errors, the XDR
|
||||
// encoder is freed.
|
||||
bool xdrEncodeFunctionStencil(JSContext* cx,
|
||||
frontend::CompilationStencil& stencil);
|
||||
|
||||
private:
|
||||
// Encode a delazified function's stencil. In case of errors, the passed
|
||||
// XDR encoder is freed.
|
||||
bool xdrEncodeFunctionStencilWith(
|
||||
JSContext* cx, frontend::CompilationStencil& stencil,
|
||||
UniquePtr<XDRIncrementalEncoderBase>& xdrEncoder);
|
||||
|
||||
public:
|
||||
// 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(JS::TranscodeBuffer& buffer);
|
||||
bool xdrFinalizeEncoder(JSContext* cx, JS::TranscodeBuffer& buffer);
|
||||
|
||||
private:
|
||||
template <typename Unit,
|
||||
|
|
|
@ -181,7 +181,7 @@ JS_PUBLIC_API bool JS::GetScriptTranscodingBuildId(
|
|||
// Note: the buildId returned here is also used for the bytecode cache MIME
|
||||
// type so use plain ASCII characters.
|
||||
|
||||
if (!buildId->reserve(buildId->length() + 4)) {
|
||||
if (!buildId->reserve(buildId->length() + 5)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -196,6 +196,10 @@ JS_PUBLIC_API bool JS::GetScriptTranscodingBuildId(
|
|||
// copy-on-write arrays).
|
||||
buildId->infallibleAppend(IsTypeInferenceEnabled() ? '1' : '0');
|
||||
|
||||
// If off-thread parse global isn't used for single script decoding,
|
||||
// we use stencil XDR instead of JSScript XDR.
|
||||
buildId->infallibleAppend(js::UseOffThreadParseGlobal() ? '1' : '0');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче