--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -134,31 +134,35 @@ static const size_t gMaxStackSize = 128
static const double MAX_TIMEOUT_INTERVAL = 1800.0;
#ifdef NIGHTLY_BUILD
# define SHARED_MEMORY_DEFAULT 1
#else
# define SHARED_MEMORY_DEFAULT 0
#endif
+#ifdef SPIDERMONKEY_PROMISE
using JobQueue = GCVector<JSObject*, 0, SystemAllocPolicy>;
+#endif // SPIDERMONKEY_PROMISE
// Per-runtime shell state.
struct ShellRuntime
{
explicit ShellRuntime(JSRuntime* rt);
bool isWorker;
double timeoutInterval;
Atomic<bool> serviceInterrupt;
Atomic<bool> haveInterruptFunc;
JS::PersistentRootedValue interruptFunc;
bool lastWarningEnabled;
JS::PersistentRootedValue lastWarning;
+#ifdef SPIDERMONKEY_PROMISE
JS::PersistentRooted<JobQueue> jobQueue;
+#endif // SPIDERMONKEY_PROMISE
/*
* Watchdog thread state.
*/
PRLock* watchdogLock;
PRCondVar* watchdogWakeup;
PRThread* watchdogThread;
bool watchdogHasTimeout;
@@ -615,16 +619,17 @@ RunModule(JSContext* cx, const char* fil
RootedValue value(cx);
if (!JS_CallFunction(cx, loaderObj, importFun, args, &value)) {
sr->exitCode = EXITCODE_RUNTIME_ERROR;
return;
}
}
+#ifdef SPIDERMONKEY_PROMISE
static bool
ShellEnqueuePromiseJobCallback(JSContext* cx, JS::HandleObject job, void* data)
{
ShellRuntime* sr = GetShellRuntime(cx);
MOZ_ASSERT(job);
return sr->jobQueue.append(job);
}
@@ -656,16 +661,17 @@ DrainJobQueue(JSContext* cx, unsigned ar
{
CallArgs args = CallArgsFromVp(argc, vp);
if (!DrainJobQueue(cx))
return false;
args.rval().setUndefined();
return true;
}
+#endif // SPIDERMONKEY_PROMISE
static bool
EvalAndPrint(JSContext* cx, const char* bytes, size_t length,
int lineno, bool compileOnly)
{
// Eval.
JS::CompileOptions options(cx);
options.setIntroductionType("js shell interactive")
@@ -754,17 +760,19 @@ ReadEvalPrintLoop(JSContext* cx, FILE* i
if (JS::ForceLexicalInitialization(cx, globalLexical) && gErrFile->isOpen()) {
fputs("Warning: According to the standard, after the above exception,\n"
"Warning: the global bindings should be permanently uninitialized.\n"
"Warning: We have non-standard-ly initialized them to `undefined`"
"for you.\nWarning: This nicety only happens in the JS shell.\n",
stderr);
}
+#ifdef SPIDERMONKEY_PROMISE
DrainJobQueue(cx);
+#endif // SPIDERMONKEY_PROMISE
} while (!hitEOF && !sr->quitting);
if (gOutFile->isOpen())
fprintf(gOutFile->fp, "\n");
}
enum FileKind
@@ -907,16 +915,17 @@ CreateMappedArrayBuffer(JSContext* cx, u
RootedObject obj(cx, JS_NewMappedArrayBufferWithContents(cx, size, contents));
if (!obj)
return false;
args.rval().setObject(*obj);
return true;
}
+#ifdef SPIDERMONKEY_PROMISE
static bool
AddPromiseReactions(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
if (args.length() != 3) {
JS_ReportErrorNumber(cx, my_GetErrorMessage, nullptr,
args.length() < 3 ? JSSMSG_NOT_ENOUGH_ARGS : JSSMSG_TOO_MANY_ARGS,
@@ -945,16 +954,17 @@ AddPromiseReactions(JSContext* cx, unsig
if (!onResolve || !onResolve->is<JSFunction>() || !onReject || !onReject->is<JSFunction>()) {
JS_ReportErrorNumber(cx, my_GetErrorMessage, nullptr,
JSSMSG_INVALID_ARGS, "addPromiseReactions");
return false;
}
return JS::AddPromiseReactions(cx, promise, onResolve, onReject);
}
+#endif // SPIDERMONKEY_PROMISE
static bool
Options(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
JS::RuntimeOptions oldRuntimeOptions = JS::RuntimeOptionsRef(cx);
for (unsigned i = 0; i < args.length(); i++) {
@@ -2907,18 +2917,20 @@ WorkerMain(void* arg)
JSContext* cx = NewContext(rt);
if (!cx) {
JS_DestroyRuntime(rt);
js_delete(input);
return;
}
+#ifdef SPIDERMONKEY_PROMISE
sr->jobQueue.init(cx, JobQueue(SystemAllocPolicy()));
JS::SetEnqueuePromiseJobCallback(rt, ShellEnqueuePromiseJobCallback);
+#endif // SPIDERMONKEY_PROMISE
JS::SetLargeAllocationFailureCallback(rt, my_LargeAllocFailCallback, (void*)cx);
do {
JSAutoRequest ar(cx);
JS::CompartmentOptions compartmentOptions;
SetStandardCompartmentOptions(compartmentOptions);
@@ -2936,18 +2948,20 @@ WorkerMain(void* arg)
if (!JS::Compile(cx, options, input->chars, input->length, &script))
break;
RootedValue result(cx);
JS_ExecuteScript(cx, script, &result);
} while (0);
JS::SetLargeAllocationFailureCallback(rt, nullptr, nullptr);
+#ifdef SPIDERMONKEY_PROMISE
JS::SetEnqueuePromiseJobCallback(rt, nullptr);
sr->jobQueue.reset();
+#endif // SPIDERMONKEY_PROMISE
DestroyContext(cx, false);
KillWatchdog(rt);
JS_DestroyRuntime(rt);
js_delete(input);
@@ -5520,19 +5534,21 @@ static const JSFunctionSpecWithHelp shel
" principals of ~0 subsumes all other principals. The absence of a\n"
" principal is treated as if its bits were 0xffff, for subsumption\n"
" purposes. If this property is omitted, supply no principal."),
JS_FN_HELP("createMappedArrayBuffer", CreateMappedArrayBuffer, 1, 0,
"createMappedArrayBuffer(filename, [offset, [size]])",
" Create an array buffer that mmaps the given file."),
+#ifdef SPIDERMONKEY_PROMISE
JS_FN_HELP("addPromiseReactions", AddPromiseReactions, 3, 0,
"addPromiseReactions(promise, onResolve, onReject)",
" Calls the JS::AddPromiseReactions JSAPI function with the given arguments."),
+#endif // SPIDERMONKEY_PROMISE
JS_FN_HELP("getMaxArgs", GetMaxArgs, 0, 0,
"getMaxArgs()",
" Return the maximum number of supported args for a call."),
JS_FN_HELP("objectEmulatingUndefined", ObjectEmulatingUndefined, 0, 0,
"objectEmulatingUndefined()",
" Return a new object obj for which typeof obj === \"undefined\", obj == null\n"
@@ -5597,20 +5613,22 @@ static const JSFunctionSpecWithHelp shel
"{ eval }: Apply JS::Evaluate to |params.eval|.\n"
"\n"
"The return value is an array of strings, with one element for each\n"
"JavaScript invocation that occurred as a result of the given\n"
"operation. Each element is the name of the function invoked, or the\n"
"string 'eval:FILENAME' if the code was invoked by 'eval' or something\n"
"similar.\n"),
+#ifdef SPIDERMONKEY_PROMISE
JS_FN_HELP("drainJobQueue", DrainJobQueue, 0, 0,
"drainJobQueue()",
"Take jobs from the shell's job queue in FIFO order and run them until the\n"
"queue is empty.\n"),
+#endif // SPIDERMONKEY_PROMISE
JS_FS_HELP_END
};
static const JSFunctionSpecWithHelp fuzzing_unsafe_functions[] = {
JS_FN_HELP("clone", Clone, 1, 0,
"clone(fun[, scope])",
" Clone function object."),
@@ -6710,17 +6728,19 @@ ProcessArgs(JSContext* cx, OptionParser*
/* The |script| argument is processed after all options. */
if (const char* path = op->getStringArg("script")) {
Process(cx, path, false);
if (sr->exitCode)
return sr->exitCode;
}
+#ifdef SPIDERMONKEY_PROMISE
DrainJobQueue(cx);
+#endif // SPIDERMONKEY_PROMISE
if (op->getBoolOption('i'))
Process(cx, nullptr, true);
return sr->exitCode ? sr->exitCode : EXIT_SUCCESS;
}
static bool
@@ -7384,18 +7404,20 @@ main(int argc, char** argv, char** envp)
if (!InitWatchdog(rt))
return 1;
cx = NewContext(rt);
if (!cx)
return 1;
+#ifdef SPIDERMONKEY_PROMISE
sr->jobQueue.init(cx, JobQueue(SystemAllocPolicy()));
JS::SetEnqueuePromiseJobCallback(rt, ShellEnqueuePromiseJobCallback);
+#endif // SPIDERMONKEY_PROMISE
JS_SetGCParameter(rt, JSGC_MODE, JSGC_MODE_INCREMENTAL);
JS::SetLargeAllocationFailureCallback(rt, my_LargeAllocFailCallback, (void*)cx);
// Set some parameters to allow incremental GC in low memory conditions,
// as is done for the browser, except in more-deterministic builds or when
// disabled by command line options.
@@ -7413,18 +7435,20 @@ main(int argc, char** argv, char** envp)
#ifdef DEBUG
if (OOM_printAllocationCount)
printf("OOM max count: %" PRIu64 "\n", js::oom::counter);
#endif
JS::SetLargeAllocationFailureCallback(rt, nullptr, nullptr);
+#ifdef SPIDERMONKEY_PROMISE
JS::SetEnqueuePromiseJobCallback(rt, nullptr);
sr->jobQueue.reset();
+#endif // SPIDERMONKEY_PROMISE
DestroyContext(cx, true);
KillWatchdog(rt);
KillWorkerThreads();
DestructSharedArrayBufferMailbox();