Bug 1686572 - Return JS::OffThreadToken* from off-thread script compile. r=arai

Instead of using both an optional out-param and a boolean return value, we
can simply return the token directly. This is less error-prone and requires
no change to callers that did not use the out-param.

Differential Revision: https://phabricator.services.mozilla.com/D101654
This commit is contained in:
Ted Campbell 2021-01-14 00:51:13 +00:00
parent 3591b6e8cb
commit a8e1541ef9
6 changed files with 129 additions and 170 deletions

View File

@ -2449,22 +2449,22 @@ nsresult ScriptLoader::AttemptAsyncScriptCompile(ScriptLoadRequest* aRequest,
nsresult rv = GetScriptSource(cx, aRequest, &maybeSource);
NS_ENSURE_SUCCESS(rv, rv);
if (maybeSource.constructed<SourceText<char16_t>>()
? !JS::CompileOffThreadModule(
aRequest->mOffThreadToken =
maybeSource.constructed<SourceText<char16_t>>()
? JS::CompileOffThreadModule(
cx, options, maybeSource.ref<SourceText<char16_t>>(),
OffThreadScriptLoaderCallback, static_cast<void*>(runnable),
&aRequest->mOffThreadToken)
: !JS::CompileOffThreadModule(
OffThreadScriptLoaderCallback, static_cast<void*>(runnable))
: JS::CompileOffThreadModule(
cx, options, maybeSource.ref<SourceText<Utf8Unit>>(),
OffThreadScriptLoaderCallback, static_cast<void*>(runnable),
&aRequest->mOffThreadToken)) {
OffThreadScriptLoaderCallback, static_cast<void*>(runnable));
if (!aRequest->mOffThreadToken) {
return NS_ERROR_OUT_OF_MEMORY;
}
} else if (aRequest->IsBytecode()) {
if (!JS::DecodeOffThreadScript(
cx, options, aRequest->mScriptBytecode, aRequest->mBytecodeOffset,
OffThreadScriptLoaderCallback, static_cast<void*>(runnable),
&aRequest->mOffThreadToken)) {
aRequest->mOffThreadToken = JS::DecodeOffThreadScript(
cx, options, aRequest->mScriptBytecode, aRequest->mBytecodeOffset,
OffThreadScriptLoaderCallback, static_cast<void*>(runnable));
if (!aRequest->mOffThreadToken) {
return NS_ERROR_OUT_OF_MEMORY;
}
} else {
@ -2473,15 +2473,15 @@ nsresult ScriptLoader::AttemptAsyncScriptCompile(ScriptLoadRequest* aRequest,
nsresult rv = GetScriptSource(cx, aRequest, &maybeSource);
NS_ENSURE_SUCCESS(rv, rv);
if (maybeSource.constructed<SourceText<char16_t>>()
? !JS::CompileOffThread(
aRequest->mOffThreadToken =
maybeSource.constructed<SourceText<char16_t>>()
? JS::CompileOffThread(
cx, options, maybeSource.ref<SourceText<char16_t>>(),
OffThreadScriptLoaderCallback, static_cast<void*>(runnable),
&aRequest->mOffThreadToken)
: !JS::CompileOffThread(
OffThreadScriptLoaderCallback, static_cast<void*>(runnable))
: JS::CompileOffThread(
cx, options, maybeSource.ref<SourceText<Utf8Unit>>(),
OffThreadScriptLoaderCallback, static_cast<void*>(runnable),
&aRequest->mOffThreadToken)) {
OffThreadScriptLoaderCallback, static_cast<void*>(runnable));
if (!aRequest->mOffThreadToken) {
return NS_ERROR_OUT_OF_MEMORY;
}
}

View File

@ -60,19 +60,19 @@ using OffThreadCompileCallback = void (*)(OffThreadToken* token,
extern JS_PUBLIC_API bool CanCompileOffThread(
JSContext* cx, const ReadOnlyCompileOptions& options, size_t length);
extern JS_PUBLIC_API bool CompileOffThread(
extern JS_PUBLIC_API OffThreadToken* CompileOffThread(
JSContext* cx, const ReadOnlyCompileOptions& options,
SourceText<char16_t>& srcBuf, OffThreadCompileCallback callback,
void* callbackData, OffThreadToken** tokenOut = nullptr);
void* callbackData);
// NOTE: Unlike for the normal sync compilation functions, this function NEVER
// INFLATES TO UTF-16. Therefore, it is ALWAYS invoking experimental
// UTF-8 support. Inflate to UTF-16 yourself and use the other overload
// if you're unable to take a risk using unstable functionality.
extern JS_PUBLIC_API bool CompileOffThread(
extern JS_PUBLIC_API OffThreadToken* CompileOffThread(
JSContext* cx, const ReadOnlyCompileOptions& options,
SourceText<mozilla::Utf8Unit>& srcBuf, OffThreadCompileCallback callback,
void* callbackData, OffThreadToken** tokenOut = nullptr);
void* callbackData);
// Finish the off-thread parse/decode task and return the script. Return the
// script on success, or return null on failure (usually with an error reported)
@ -94,19 +94,19 @@ extern JS_PUBLIC_API JSScript* FinishOffThreadScriptAndStartIncrementalEncoding(
extern JS_PUBLIC_API void CancelOffThreadScript(JSContext* cx,
OffThreadToken* token);
extern JS_PUBLIC_API bool CompileOffThreadModule(
extern JS_PUBLIC_API OffThreadToken* CompileOffThreadModule(
JSContext* cx, const ReadOnlyCompileOptions& options,
SourceText<char16_t>& srcBuf, OffThreadCompileCallback callback,
void* callbackData, OffThreadToken** tokenOut = nullptr);
void* callbackData);
// NOTE: Unlike for the normal sync compilation functions, this function NEVER
// INFLATES TO UTF-16. Therefore, it is ALWAYS invoking experimental
// UTF-8 support. Inflate to UTF-16 yourself and use the other overload
// if you're unable to take a risk using unstable functionality.
extern JS_PUBLIC_API bool CompileOffThreadModule(
extern JS_PUBLIC_API OffThreadToken* CompileOffThreadModule(
JSContext* cx, const ReadOnlyCompileOptions& options,
SourceText<mozilla::Utf8Unit>& srcBuf, OffThreadCompileCallback callback,
void* callbackData, OffThreadToken** tokenOut = nullptr);
void* callbackData);
extern JS_PUBLIC_API JSObject* FinishOffThreadModule(JSContext* cx,
OffThreadToken* token);
@ -128,22 +128,20 @@ extern JS_PUBLIC_API bool CanDecodeOffThread(
// (This should be handled while encoding).
//
// `buffer` should be alive until the end of `FinishOffThreadScriptDecoder`.
extern JS_PUBLIC_API bool DecodeOffThreadScript(
extern JS_PUBLIC_API OffThreadToken* DecodeOffThreadScript(
JSContext* cx, const ReadOnlyCompileOptions& options,
mozilla::Vector<uint8_t>& buffer /* TranscodeBuffer& */, size_t cursor,
OffThreadCompileCallback callback, void* callbackData,
OffThreadToken** tokenOut = nullptr);
OffThreadCompileCallback callback, void* callbackData);
// The start of `range` should be meet IsTranscodingBytecodeAligned and
// AlignTranscodingBytecodeOffset.
// (This should be handled while encoding).
//
// `range` should be alive until the end of `FinishOffThreadScriptDecoder`.
extern JS_PUBLIC_API bool DecodeOffThreadScript(
extern JS_PUBLIC_API OffThreadToken* DecodeOffThreadScript(
JSContext* cx, const ReadOnlyCompileOptions& options,
const mozilla::Range<uint8_t>& range /* TranscodeRange& */,
OffThreadCompileCallback callback, void* callbackData,
OffThreadToken** tokenOut = nullptr);
OffThreadCompileCallback callback, void* callbackData);
extern JS_PUBLIC_API JSScript* FinishOffThreadScriptDecoder(
JSContext* cx, OffThreadToken* token);
@ -152,7 +150,7 @@ extern JS_PUBLIC_API void CancelOffThreadScriptDecoder(JSContext* cx,
OffThreadToken* token);
// Decode multiple JSScript from the sources.
extern JS_PUBLIC_API bool DecodeMultiOffThreadScripts(
extern JS_PUBLIC_API OffThreadToken* DecodeMultiOffThreadScripts(
JSContext* cx, const ReadOnlyCompileOptions& options,
mozilla::Vector<TranscodeSource>& sources,
OffThreadCompileCallback callback, void* callbackData);

View File

@ -507,12 +507,12 @@ BEGIN_TEST(testScriptSourceCompression_offThread) {
js::Monitor monitor(js::mutexid::ShellOffThreadState);
JS::CompileOptions options(cx);
JS::OffThreadToken* token = nullptr;
JS::OffThreadToken* token;
// Force off-thread even though if this is a small file.
options.forceAsync = true;
CHECK(JS::CompileOffThread(cx, options, source, callback, &monitor, &token));
CHECK(token = JS::CompileOffThread(cx, options, source, callback, &monitor));
{
// Finish any active GC in case it is blocking off-thread work.

View File

@ -1099,11 +1099,9 @@ bool GlobalHelperThreadState::submitTask(
return true;
}
static bool StartOffThreadParseTask(JSContext* cx, UniquePtr<ParseTask> task,
const ReadOnlyCompileOptions& options,
JS::OffThreadToken** tokenOut = nullptr) {
MOZ_ASSERT_IF(tokenOut, *tokenOut == nullptr);
static JS::OffThreadToken* StartOffThreadParseTask(
JSContext* cx, UniquePtr<ParseTask> task,
const ReadOnlyCompileOptions& options) {
// Suppress GC so that calls below do not trigger a new incremental GC
// which could require barriers on the atoms zone.
gc::AutoSuppressGC nogc(cx);
@ -1114,7 +1112,7 @@ static bool StartOffThreadParseTask(JSContext* cx, UniquePtr<ParseTask> task,
if (options.useOffThreadParseGlobal) {
global = CreateGlobalForOffThreadParse(cx, nogc);
if (!global) {
return false;
return nullptr;
}
}
@ -1125,119 +1123,105 @@ static bool StartOffThreadParseTask(JSContext* cx, UniquePtr<ParseTask> task,
AutoSetCreatedForHelperThread createdForHelper(global);
if (!task->init(cx, options, global)) {
return false;
return nullptr;
}
JS::OffThreadToken* token = task.get();
if (!QueueOffThreadParseTask(cx, std::move(task))) {
return false;
}
// Return an opaque pointer to caller so that it may query/cancel the task
// before the callback is fired.
if (tokenOut) {
*tokenOut = token;
return nullptr;
}
createdForHelper.forget();
return true;
// Return an opaque pointer to caller so that it may query/cancel the task
// before the callback is fired.
return token;
}
template <typename Unit>
static bool StartOffThreadParseScriptInternal(
static JS::OffThreadToken* StartOffThreadParseScriptInternal(
JSContext* cx, const ReadOnlyCompileOptions& options,
JS::SourceText<Unit>& srcBuf, JS::OffThreadCompileCallback callback,
void* callbackData, JS::OffThreadToken** tokenOut) {
void* callbackData) {
auto task = cx->make_unique<ScriptParseTask<Unit>>(cx, srcBuf, callback,
callbackData);
if (!task) {
return false;
return nullptr;
}
return StartOffThreadParseTask(cx, std::move(task), options, tokenOut);
return StartOffThreadParseTask(cx, std::move(task), options);
}
bool js::StartOffThreadParseScript(JSContext* cx,
const ReadOnlyCompileOptions& options,
JS::SourceText<char16_t>& srcBuf,
JS::OffThreadCompileCallback callback,
void* callbackData,
JS::OffThreadToken** tokenOut) {
JS::OffThreadToken* js::StartOffThreadParseScript(
JSContext* cx, const ReadOnlyCompileOptions& options,
JS::SourceText<char16_t>& srcBuf, JS::OffThreadCompileCallback callback,
void* callbackData) {
return StartOffThreadParseScriptInternal(cx, options, srcBuf, callback,
callbackData, tokenOut);
callbackData);
}
bool js::StartOffThreadParseScript(JSContext* cx,
const ReadOnlyCompileOptions& options,
JS::SourceText<Utf8Unit>& srcBuf,
JS::OffThreadCompileCallback callback,
void* callbackData,
JS::OffThreadToken** tokenOut) {
JS::OffThreadToken* js::StartOffThreadParseScript(
JSContext* cx, const ReadOnlyCompileOptions& options,
JS::SourceText<Utf8Unit>& srcBuf, JS::OffThreadCompileCallback callback,
void* callbackData) {
return StartOffThreadParseScriptInternal(cx, options, srcBuf, callback,
callbackData, tokenOut);
callbackData);
}
template <typename Unit>
static bool StartOffThreadParseModuleInternal(
static JS::OffThreadToken* StartOffThreadParseModuleInternal(
JSContext* cx, const ReadOnlyCompileOptions& options,
JS::SourceText<Unit>& srcBuf, JS::OffThreadCompileCallback callback,
void* callbackData, JS::OffThreadToken** tokenOut) {
void* callbackData) {
auto task = cx->make_unique<ModuleParseTask<Unit>>(cx, srcBuf, callback,
callbackData);
if (!task) {
return false;
return nullptr;
}
return StartOffThreadParseTask(cx, std::move(task), options, tokenOut);
return StartOffThreadParseTask(cx, std::move(task), options);
}
bool js::StartOffThreadParseModule(JSContext* cx,
const ReadOnlyCompileOptions& options,
JS::SourceText<char16_t>& srcBuf,
JS::OffThreadCompileCallback callback,
void* callbackData,
JS::OffThreadToken** tokenOut) {
JS::OffThreadToken* js::StartOffThreadParseModule(
JSContext* cx, const ReadOnlyCompileOptions& options,
JS::SourceText<char16_t>& srcBuf, JS::OffThreadCompileCallback callback,
void* callbackData) {
return StartOffThreadParseModuleInternal(cx, options, srcBuf, callback,
callbackData, tokenOut);
callbackData);
}
bool js::StartOffThreadParseModule(JSContext* cx,
const ReadOnlyCompileOptions& options,
JS::SourceText<Utf8Unit>& srcBuf,
JS::OffThreadCompileCallback callback,
void* callbackData,
JS::OffThreadToken** tokenOut) {
JS::OffThreadToken* js::StartOffThreadParseModule(
JSContext* cx, const ReadOnlyCompileOptions& options,
JS::SourceText<Utf8Unit>& srcBuf, JS::OffThreadCompileCallback callback,
void* callbackData) {
return StartOffThreadParseModuleInternal(cx, options, srcBuf, callback,
callbackData, tokenOut);
callbackData);
}
bool js::StartOffThreadDecodeScript(JSContext* cx,
const ReadOnlyCompileOptions& options,
const JS::TranscodeRange& range,
JS::OffThreadCompileCallback callback,
void* callbackData,
JS::OffThreadToken** tokenOut) {
JS::OffThreadToken* js::StartOffThreadDecodeScript(
JSContext* cx, const ReadOnlyCompileOptions& options,
const JS::TranscodeRange& range, JS::OffThreadCompileCallback callback,
void* callbackData) {
// XDR data must be Stencil format, or a parse-global must be available.
MOZ_RELEASE_ASSERT(options.useStencilXDR || options.useOffThreadParseGlobal);
auto task =
cx->make_unique<ScriptDecodeTask>(cx, range, callback, callbackData);
if (!task) {
return false;
return nullptr;
}
return StartOffThreadParseTask(cx, std::move(task), options, tokenOut);
return StartOffThreadParseTask(cx, std::move(task), options);
}
bool js::StartOffThreadDecodeMultiScripts(JSContext* cx,
const ReadOnlyCompileOptions& options,
JS::TranscodeSources& sources,
JS::OffThreadCompileCallback callback,
void* callbackData) {
JS::OffThreadToken* js::StartOffThreadDecodeMultiScripts(
JSContext* cx, const ReadOnlyCompileOptions& options,
JS::TranscodeSources& sources, JS::OffThreadCompileCallback callback,
void* callbackData) {
auto task = cx->make_unique<MultiScriptsDecodeTask>(cx, sources, callback,
callbackData);
if (!task) {
return false;
return nullptr;
}
// NOTE: All uses of DecodeMulti are currently generated by non-incremental

View File

@ -189,44 +189,33 @@ void CancelOffThreadParses(JSRuntime* runtime);
* Start a parse/emit cycle for a stream of source. The characters must stay
* alive until the compilation finishes.
*/
bool StartOffThreadParseScript(JSContext* cx,
const JS::ReadOnlyCompileOptions& options,
JS::SourceText<char16_t>& srcBuf,
JS::OffThreadCompileCallback callback,
void* callbackData,
JS::OffThreadToken** tokenOut);
bool StartOffThreadParseScript(JSContext* cx,
const JS::ReadOnlyCompileOptions& options,
JS::SourceText<mozilla::Utf8Unit>& srcBuf,
JS::OffThreadCompileCallback callback,
void* callbackData,
JS::OffThreadToken** tokenOut);
JS::OffThreadToken* StartOffThreadParseScript(
JSContext* cx, const JS::ReadOnlyCompileOptions& options,
JS::SourceText<char16_t>& srcBuf, JS::OffThreadCompileCallback callback,
void* callbackData);
JS::OffThreadToken* StartOffThreadParseScript(
JSContext* cx, const JS::ReadOnlyCompileOptions& options,
JS::SourceText<mozilla::Utf8Unit>& srcBuf,
JS::OffThreadCompileCallback callback, void* callbackData);
bool StartOffThreadParseModule(JSContext* cx,
const JS::ReadOnlyCompileOptions& options,
JS::SourceText<char16_t>& srcBuf,
JS::OffThreadCompileCallback callback,
void* callbackData,
JS::OffThreadToken** tokenOut);
bool StartOffThreadParseModule(JSContext* cx,
const JS::ReadOnlyCompileOptions& options,
JS::SourceText<mozilla::Utf8Unit>& srcBuf,
JS::OffThreadCompileCallback callback,
void* callbackData,
JS::OffThreadToken** tokenOut);
JS::OffThreadToken* StartOffThreadParseModule(
JSContext* cx, const JS::ReadOnlyCompileOptions& options,
JS::SourceText<char16_t>& srcBuf, JS::OffThreadCompileCallback callback,
void* callbackData);
JS::OffThreadToken* StartOffThreadParseModule(
JSContext* cx, const JS::ReadOnlyCompileOptions& options,
JS::SourceText<mozilla::Utf8Unit>& srcBuf,
JS::OffThreadCompileCallback callback, void* callbackData);
bool StartOffThreadDecodeScript(JSContext* cx,
const JS::ReadOnlyCompileOptions& options,
const JS::TranscodeRange& range,
JS::OffThreadCompileCallback callback,
void* callbackData,
JS::OffThreadToken** tokenOut);
JS::OffThreadToken* StartOffThreadDecodeScript(
JSContext* cx, const JS::ReadOnlyCompileOptions& options,
const JS::TranscodeRange& range, JS::OffThreadCompileCallback callback,
void* callbackData);
bool StartOffThreadDecodeMultiScripts(JSContext* cx,
const JS::ReadOnlyCompileOptions& options,
JS::TranscodeSources& sources,
JS::OffThreadCompileCallback callback,
void* callbackData);
JS::OffThreadToken* StartOffThreadDecodeMultiScripts(
JSContext* cx, const JS::ReadOnlyCompileOptions& options,
JS::TranscodeSources& sources, JS::OffThreadCompileCallback callback,
void* callbackData);
/*
* Called at the end of GC to enqueue any Parse tasks that were waiting on an

View File

@ -71,26 +71,20 @@ JS_PUBLIC_API bool JS::CanCompileOffThread(
return CanDoOffThread(cx, options, length, OffThread::Compile);
}
JS_PUBLIC_API bool JS::CompileOffThread(JSContext* cx,
const ReadOnlyCompileOptions& options,
JS::SourceText<char16_t>& srcBuf,
OffThreadCompileCallback callback,
void* callbackData,
OffThreadToken** tokenOut) {
JS_PUBLIC_API JS::OffThreadToken* JS::CompileOffThread(
JSContext* cx, const ReadOnlyCompileOptions& options,
JS::SourceText<char16_t>& srcBuf, OffThreadCompileCallback callback,
void* callbackData) {
MOZ_ASSERT(CanCompileOffThread(cx, options, srcBuf.length()));
return StartOffThreadParseScript(cx, options, srcBuf, callback, callbackData,
tokenOut);
return StartOffThreadParseScript(cx, options, srcBuf, callback, callbackData);
}
JS_PUBLIC_API bool JS::CompileOffThread(JSContext* cx,
const ReadOnlyCompileOptions& options,
JS::SourceText<Utf8Unit>& srcBuf,
OffThreadCompileCallback callback,
void* callbackData,
OffThreadToken** tokenOut) {
JS_PUBLIC_API JS::OffThreadToken* JS::CompileOffThread(
JSContext* cx, const ReadOnlyCompileOptions& options,
JS::SourceText<Utf8Unit>& srcBuf, OffThreadCompileCallback callback,
void* callbackData) {
MOZ_ASSERT(CanCompileOffThread(cx, options, srcBuf.length()));
return StartOffThreadParseScript(cx, options, srcBuf, callback, callbackData,
tokenOut);
return StartOffThreadParseScript(cx, options, srcBuf, callback, callbackData);
}
JS_PUBLIC_API JSScript* JS::FinishOffThreadScript(JSContext* cx,
@ -116,22 +110,20 @@ JS_PUBLIC_API void JS::CancelOffThreadScript(JSContext* cx,
token);
}
JS_PUBLIC_API bool JS::CompileOffThreadModule(
JS_PUBLIC_API JS::OffThreadToken* JS::CompileOffThreadModule(
JSContext* cx, const ReadOnlyCompileOptions& options,
JS::SourceText<char16_t>& srcBuf, OffThreadCompileCallback callback,
void* callbackData, OffThreadToken** tokenOut) {
void* callbackData) {
MOZ_ASSERT(CanCompileOffThread(cx, options, srcBuf.length()));
return StartOffThreadParseModule(cx, options, srcBuf, callback, callbackData,
tokenOut);
return StartOffThreadParseModule(cx, options, srcBuf, callback, callbackData);
}
JS_PUBLIC_API bool JS::CompileOffThreadModule(
JS_PUBLIC_API JS::OffThreadToken* JS::CompileOffThreadModule(
JSContext* cx, const ReadOnlyCompileOptions& options,
JS::SourceText<Utf8Unit>& srcBuf, OffThreadCompileCallback callback,
void* callbackData, OffThreadToken** tokenOut) {
void* callbackData) {
MOZ_ASSERT(CanCompileOffThread(cx, options, srcBuf.length()));
return StartOffThreadParseModule(cx, options, srcBuf, callback, callbackData,
tokenOut);
return StartOffThreadParseModule(cx, options, srcBuf, callback, callbackData);
}
JS_PUBLIC_API JSObject* JS::FinishOffThreadModule(JSContext* cx,
@ -155,25 +147,21 @@ JS_PUBLIC_API bool JS::CanDecodeOffThread(JSContext* cx,
return CanDoOffThread(cx, options, length, OffThread::Decode);
}
JS_PUBLIC_API bool JS::DecodeOffThreadScript(
JS_PUBLIC_API JS::OffThreadToken* JS::DecodeOffThreadScript(
JSContext* cx, const ReadOnlyCompileOptions& options,
mozilla::Vector<uint8_t>& buffer /* TranscodeBuffer& */, size_t cursor,
OffThreadCompileCallback callback, void* callbackData,
OffThreadToken** tokenOut) {
OffThreadCompileCallback callback, void* callbackData) {
JS::TranscodeRange range(buffer.begin() + cursor, buffer.length() - cursor);
MOZ_ASSERT(CanDecodeOffThread(cx, options, range.length()));
return StartOffThreadDecodeScript(cx, options, range, callback, callbackData,
tokenOut);
return StartOffThreadDecodeScript(cx, options, range, callback, callbackData);
}
JS_PUBLIC_API bool JS::DecodeOffThreadScript(
JS_PUBLIC_API JS::OffThreadToken* JS::DecodeOffThreadScript(
JSContext* cx, const ReadOnlyCompileOptions& options,
const mozilla::Range<uint8_t>& range /* TranscodeRange& */,
OffThreadCompileCallback callback, void* callbackData,
OffThreadToken** tokenOut) {
OffThreadCompileCallback callback, void* callbackData) {
MOZ_ASSERT(CanDecodeOffThread(cx, options, range.length()));
return StartOffThreadDecodeScript(cx, options, range, callback, callbackData,
tokenOut);
return StartOffThreadDecodeScript(cx, options, range, callback, callbackData);
}
JS_PUBLIC_API JSScript* JS::FinishOffThreadScriptDecoder(
@ -191,7 +179,7 @@ JS_PUBLIC_API void JS::CancelOffThreadScriptDecoder(JSContext* cx,
ParseTaskKind::ScriptDecode, token);
}
JS_PUBLIC_API bool JS::DecodeMultiOffThreadScripts(
JS_PUBLIC_API JS::OffThreadToken* JS::DecodeMultiOffThreadScripts(
JSContext* cx, const ReadOnlyCompileOptions& options,
TranscodeSources& sources, OffThreadCompileCallback callback,
void* callbackData) {