Bug 1285134 part 2 - Rename ShellRuntime to ShellContext. r=efaust
authorJan de Mooij <jdemooij@mozilla.com>
Mon, 18 Jul 2016 14:36:43 +0200
changeset 305325 d8fb8e2d81a0bcd9d75703916c8e0593dac12d3c
parent 305324 2fb342547aa8c02298f38714058411a651ea4b90
child 305326 895a11230f50a35a7dc626f6cdca22018f772547
push id79553
push userjandemooij@gmail.com
push dateMon, 18 Jul 2016 12:40:11 +0000
treeherdermozilla-inbound@d8fb8e2d81a0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersefaust
bugs1285134
milestone50.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1285134 part 2 - Rename ShellRuntime to ShellContext. r=efaust
js/src/shell/js.cpp
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -146,20 +146,20 @@ static const TimeDuration MAX_TIMEOUT_IN
 #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);
+// Per-context shell state.
+struct ShellContext
+{
+    explicit ShellContext(JSContext* cx);
 
     bool isWorker;
     double timeoutInterval;
     double startTime;
     Atomic<bool> serviceInterrupt;
     Atomic<bool> haveInterruptFunc;
     JS::PersistentRootedValue interruptFunc;
     bool lastWarningEnabled;
@@ -234,23 +234,23 @@ static bool OOM_printAllocationCount = f
 // Shell state this is only accessed on the main thread.
 bool jsCachingEnabled = false;
 mozilla::Atomic<bool> jsCacheOpened(false);
 
 static bool
 SetTimeoutValue(JSContext* cx, double t);
 
 static void
-KillWatchdog(JSRuntime *rt);
-
-static bool
-ScheduleWatchdog(JSRuntime* rt, double t);
+KillWatchdog(JSContext* cx);
+
+static bool
+ScheduleWatchdog(JSContext* cx, double t);
 
 static void
-CancelExecution(JSRuntime* rt);
+CancelExecution(JSContext* cx);
 
 static JSObject*
 NewGlobalObject(JSContext* cx, JS::CompartmentOptions& options,
                 JSPrincipals* principals);
 
 /*
  * A toy principals type for the shell.
  *
@@ -312,41 +312,40 @@ ShellPrincipals ShellPrincipals::fullyTr
 
 #ifdef EDITLINE
 extern "C" {
 extern JS_EXPORT_API(char*) readline(const char* prompt);
 extern JS_EXPORT_API(void)   add_history(char* line);
 } // extern "C"
 #endif
 
-ShellRuntime::ShellRuntime(JSRuntime* rt)
+ShellContext::ShellContext(JSContext* cx)
   : isWorker(false),
     timeoutInterval(-1.0),
     startTime(PRMJ_Now()),
     serviceInterrupt(false),
     haveInterruptFunc(false),
-    interruptFunc(rt, NullValue()),
+    interruptFunc(cx, NullValue()),
     lastWarningEnabled(false),
-    lastWarning(rt, NullValue()),
+    lastWarning(cx, NullValue()),
 #ifdef SPIDERMONKEY_PROMISE
-    promiseRejectionTrackerCallback(rt, NullValue()),
+    promiseRejectionTrackerCallback(cx, NullValue()),
 #endif // SPIDERMONKEY_PROMISE
     exitCode(0),
     quitting(false),
     readLineBufPos(0),
     spsProfilingStackSize(0)
 {}
 
-static ShellRuntime*
-GetShellRuntime(JSRuntime *rt)
-{
-    JSContext* cx = JS_GetContext(rt);
-    ShellRuntime* sr = static_cast<ShellRuntime*>(JS_GetContextPrivate(cx));
-    MOZ_ASSERT(sr);
-    return sr;
+static ShellContext*
+GetShellContext(JSContext* cx)
+{
+    ShellContext* sc = static_cast<ShellContext*>(JS_GetContextPrivate(cx));
+    MOZ_ASSERT(sc);
+    return sc;
 }
 
 static char*
 GetLine(FILE* file, const char * prompt)
 {
 #ifdef EDITLINE
     /*
      * Use readline only if file is stdin, because there's no way to specify
@@ -412,59 +411,59 @@ GetLine(FILE* file, const char * prompt)
         current = buffer + len;
     } while (true);
     return nullptr;
 }
 
 static bool
 ShellInterruptCallback(JSContext* cx)
 {
-    ShellRuntime* sr = GetShellRuntime(cx);
-    if (!sr->serviceInterrupt)
+    ShellContext* sc = GetShellContext(cx);
+    if (!sc->serviceInterrupt)
         return true;
 
     // Reset serviceInterrupt. CancelExecution or InterruptIf will set it to
     // true to distinguish watchdog or user triggered interrupts.
     // Do this first to prevent other interrupts that may occur while the
     // user-supplied callback is executing from re-entering the handler.
-    sr->serviceInterrupt = false;
+    sc->serviceInterrupt = false;
 
     bool result;
-    if (sr->haveInterruptFunc) {
+    if (sc->haveInterruptFunc) {
         bool wasAlreadyThrowing = cx->isExceptionPending();
         JS::AutoSaveExceptionState savedExc(cx);
-        JSAutoCompartment ac(cx, &sr->interruptFunc.toObject());
+        JSAutoCompartment ac(cx, &sc->interruptFunc.toObject());
         RootedValue rval(cx);
 
         // Report any exceptions thrown by the JS interrupt callback, but do
         // *not* keep it on the cx. The interrupt handler is invoked at points
         // that are not expected to throw catchable exceptions, like at
         // JSOP_RETRVAL.
         //
         // If the interrupted JS code was already throwing, any exceptions
         // thrown by the interrupt handler are silently swallowed.
         {
             Maybe<AutoReportException> are;
             if (!wasAlreadyThrowing)
                 are.emplace(cx);
-            result = JS_CallFunctionValue(cx, nullptr, sr->interruptFunc,
+            result = JS_CallFunctionValue(cx, nullptr, sc->interruptFunc,
                                           JS::HandleValueArray::empty(), &rval);
         }
         savedExc.restore();
 
         if (rval.isBoolean())
             result = rval.toBoolean();
         else
             result = false;
     } else {
         result = false;
     }
 
-    if (!result && sr->exitCode == 0)
-        sr->exitCode = EXITCODE_TIMEOUT;
+    if (!result && sc->exitCode == 0)
+        sc->exitCode = EXITCODE_TIMEOUT;
 
     return result;
 }
 
 /*
  * Some UTF-8 files, notably those written using Notepad, have a Unicode
  * Byte-Order-Mark (BOM) as their first character. This is useless (byte-order
  * is meaningless for UTF-8) but causes a syntax error unless we skip it.
@@ -634,45 +633,45 @@ ShellGetIncumbentGlobalCallback(JSContex
 {
     return JS::CurrentGlobalOrNull(cx);
 }
 
 static bool
 ShellEnqueuePromiseJobCallback(JSContext* cx, JS::HandleObject job, JS::HandleObject allocationSite,
                                JS::HandleObject incumbentGlobal, void* data)
 {
-    ShellRuntime* sr = GetShellRuntime(cx);
+    ShellContext* sc = GetShellContext(cx);
     MOZ_ASSERT(job);
-    return sr->jobQueue.append(job);
+    return sc->jobQueue.append(job);
 }
 #endif // SPIDERMONKEY_PROMISE
 
 static bool
 DrainJobQueue(JSContext* cx)
 {
 #ifdef SPIDERMONKEY_PROMISE
-    ShellRuntime* sr = GetShellRuntime(cx);
-    if (sr->quitting)
+    ShellContext* sc = GetShellContext(cx);
+    if (sc->quitting)
         return true;
     RootedObject job(cx);
     JS::HandleValueArray args(JS::HandleValueArray::empty());
     RootedValue rval(cx);
     // Execute jobs in a loop until we've reached the end of the queue.
     // Since executing a job can trigger enqueuing of additional jobs,
     // it's crucial to re-check the queue length during each iteration.
-    for (size_t i = 0; i < sr->jobQueue.length(); i++) {
-        job = sr->jobQueue[i];
+    for (size_t i = 0; i < sc->jobQueue.length(); i++) {
+        job = sc->jobQueue[i];
         AutoCompartment ac(cx, job);
         {
             AutoReportException are(cx);
             JS::Call(cx, UndefinedHandleValue, job, args, &rval);
         }
-        sr->jobQueue[i].set(nullptr);
-    }
-    sr->jobQueue.clear();
+        sc->jobQueue[i].set(nullptr);
+    }
+    sc->jobQueue.clear();
 #endif // SPIDERMONKEY_PROMISE
     return true;
 }
 
 static bool
 DrainJobQueue(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
@@ -683,17 +682,17 @@ DrainJobQueue(JSContext* cx, unsigned ar
     return true;
 }
 
 #ifdef SPIDERMONKEY_PROMISE
 static void
 ForwardingPromiseRejectionTrackerCallback(JSContext* cx, JS::HandleObject promise,
                                           PromiseRejectionHandlingState state, void* data)
 {
-    RootedValue callback(cx, GetShellRuntime(cx)->promiseRejectionTrackerCallback);
+    RootedValue callback(cx, GetShellContext(cx)->promiseRejectionTrackerCallback);
     if (callback.isNull()) {
         return;
     }
 
     FixedInvokeArgs<2> args(cx);
     args[0].setObject(*promise);
     args[1].setInt32(static_cast<int32_t>(state));
 
@@ -711,17 +710,17 @@ SetPromiseRejectionTrackerCallback(JSCon
 #ifdef SPIDERMONKEY_PROMISE
     if (!IsCallable(args.get(0))) {
         JS_ReportError(cx,
                        "setPromiseRejectionTrackerCallback expects a function as its sole "
                        "argument");
         return false;
     }
 
-    GetShellRuntime(cx)->promiseRejectionTrackerCallback = args[0];
+    GetShellContext(cx)->promiseRejectionTrackerCallback = args[0];
     JS::SetPromiseRejectionTrackerCallback(cx, ForwardingPromiseRejectionTrackerCallback);
 
 #endif // SPIDERMONKEY_PROMISE
     args.rval().setUndefined();
     return true;
 }
 
 static bool
@@ -757,51 +756,51 @@ EvalAndPrint(JSContext* cx, const char* 
         JS_free(cx, utf8chars);
     }
     return true;
 }
 
 static MOZ_MUST_USE bool
 ReadEvalPrintLoop(JSContext* cx, FILE* in, bool compileOnly)
 {
-    ShellRuntime* sr = GetShellRuntime(cx);
+    ShellContext* sc = GetShellContext(cx);
     int lineno = 1;
     bool hitEOF = false;
 
     do {
         /*
          * Accumulate lines until we get a 'compilable unit' - one that either
          * generates an error (before running out of source) or that compiles
          * cleanly.  This should be whenever we get a complete statement that
          * coincides with the end of a line.
          */
         int startline = lineno;
         typedef Vector<char, 32> CharBuffer;
         RootedObject globalLexical(cx, &cx->global()->lexicalScope());
         CharBuffer buffer(cx);
         do {
-            ScheduleWatchdog(cx->runtime(), -1);
-            sr->serviceInterrupt = false;
+            ScheduleWatchdog(cx, -1);
+            sc->serviceInterrupt = false;
             errno = 0;
 
             char* line = GetLine(in, startline == lineno ? "js> " : "");
             if (!line) {
                 if (errno) {
                     JS_ReportError(cx, strerror(errno));
                     return false;
                 }
                 hitEOF = true;
                 break;
             }
 
             if (!buffer.append(line, strlen(line)) || !buffer.append('\n'))
                 return false;
 
             lineno++;
-            if (!ScheduleWatchdog(cx->runtime(), sr->timeoutInterval)) {
+            if (!ScheduleWatchdog(cx, sc->timeoutInterval)) {
                 hitEOF = true;
                 break;
             }
         } while (!JS_BufferIsCompilableUnit(cx, cx->global(), buffer.begin(), buffer.length()));
 
         if (hitEOF && buffer.empty())
             break;
 
@@ -820,17 +819,17 @@ ReadEvalPrintLoop(JSContext* cx, FILE* i
                   "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);
         }
 
         DrainJobQueue(cx);
 
-    } while (!hitEOF && !sr->quitting);
+    } while (!hitEOF && !sc->quitting);
 
     if (gOutFile->isOpen())
         fprintf(gOutFile->fp, "\n");
 
     return true;
 }
 
 enum FileKind
@@ -1713,25 +1712,25 @@ ReadLine(JSContext* cx, unsigned argc, V
 /*
  * function readlineBuf()
  * Provides a hook for scripts to emulate readline() using a string object.
  */
 static bool
 ReadLineBuf(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
-    ShellRuntime* sr = GetShellRuntime(cx);
+    ShellContext* sc = GetShellContext(cx);
 
     if (!args.length()) {
-        if (!sr->readLineBuf) {
+        if (!sc->readLineBuf) {
             JS_ReportError(cx, "No source buffer set. You must initially call readlineBuf with an argument.");
             return false;
         }
 
-        char* currentBuf = sr->readLineBuf.get() + sr->readLineBufPos;
+        char* currentBuf = sc->readLineBuf.get() + sc->readLineBufPos;
         size_t buflen = strlen(currentBuf);
 
         if (!buflen) {
             args.rval().setNull();
             return true;
         }
 
         size_t len = 0;
@@ -1741,36 +1740,36 @@ ReadLineBuf(JSContext* cx, unsigned argc
             len++;
         }
 
         JSString* str = JS_NewStringCopyN(cx, currentBuf, len);
         if (!str)
             return false;
 
         if (currentBuf[len] == '\0')
-            sr->readLineBufPos += len;
+            sc->readLineBufPos += len;
         else
-            sr->readLineBufPos += len + 1;
+            sc->readLineBufPos += len + 1;
 
         args.rval().setString(str);
         return true;
     }
 
     if (args.length() == 1) {
-        if (sr->readLineBuf)
-            sr->readLineBuf.reset();
+        if (sc->readLineBuf)
+            sc->readLineBuf.reset();
 
         RootedString str(cx, JS::ToString(cx, args[0]));
         if (!str)
             return false;
-        sr->readLineBuf = UniqueChars(JS_EncodeStringToUTF8(cx, str));
-        if (!sr->readLineBuf)
+        sc->readLineBuf = UniqueChars(JS_EncodeStringToUTF8(cx, str));
+        if (!sc->readLineBuf)
             return false;
 
-        sr->readLineBufPos = 0;
+        sc->readLineBufPos = 0;
         return true;
     }
 
     JS_ReportError(cx, "Must specify at most one argument");
     return false;
 }
 
 static bool
@@ -1849,17 +1848,17 @@ PrintErr(JSContext* cx, unsigned argc, V
 }
 
 static bool
 Help(JSContext* cx, unsigned argc, Value* vp);
 
 static bool
 Quit(JSContext* cx, unsigned argc, Value* vp)
 {
-    ShellRuntime* sr = GetShellRuntime(cx);
+    ShellContext* sc = GetShellContext(cx);
 
 #ifdef JS_MORE_DETERMINISTIC
     // Print a message to stderr in more-deterministic builds to help jsfunfuzz
     // find uncatchable-exception bugs.
     fprintf(stderr, "quit called\n");
 #endif
 
     CallArgs args = CallArgsFromVp(argc, vp);
@@ -1872,18 +1871,18 @@ Quit(JSContext* cx, unsigned argc, Value
     // POSIX platforms, the exit code is 8-bit and negative values can also
     // result in an exit code >= 128. We restrict the value to range [0, 127] to
     // avoid false positives.
     if (code < 0 || code >= 128) {
         JS_ReportError(cx, "quit exit code should be in range 0-127");
         return false;
     }
 
-    sr->exitCode = code;
-    sr->quitting = true;
+    sc->exitCode = code;
+    sc->quitting = true;
     return false;
 }
 
 static bool
 StartTimingMutator(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     if (args.length() > 0) {
@@ -2943,41 +2942,41 @@ WorkerMain(void* arg)
     WorkerInput* input = (WorkerInput*) arg;
 
     JSRuntime* rt = JS_NewRuntime(8L * 1024L * 1024L, 2L * 1024L * 1024L, input->runtime);
     if (!rt) {
         js_delete(input);
         return;
     }
 
-    UniquePtr<ShellRuntime> sr = MakeUnique<ShellRuntime>(rt);
-    if (!sr) {
+    JSContext* cx = JS_GetContext(rt);
+
+    UniquePtr<ShellContext> sc = MakeUnique<ShellContext>(cx);
+    if (!sc) {
         JS_DestroyRuntime(rt);
         js_delete(input);
         return;
     }
 
-    JSContext* cx = JS_GetContext(rt);
-
-    sr->isWorker = true;
-    JS_SetContextPrivate(cx, sr.get());
+    sc->isWorker = true;
+    JS_SetContextPrivate(cx, sc.get());
     JS_SetFutexCanWait(cx);
     JS::SetWarningReporter(cx, WarningReporter);
     js::SetPreserveWrapperCallback(cx, DummyPreserveWrapperCallback);
     JS_InitDestroyPrincipalsCallback(cx, ShellPrincipals::destroy);
     SetWorkerContextOptions(cx);
 
     if (!JS::InitSelfHostedCode(cx)) {
         JS_DestroyRuntime(rt);
         js_delete(input);
         return;
     }
 
 #ifdef SPIDERMONKEY_PROMISE
-    sr->jobQueue.init(cx, JobQueue(SystemAllocPolicy()));
+    sc->jobQueue.init(cx, JobQueue(SystemAllocPolicy()));
     JS::SetEnqueuePromiseJobCallback(cx, ShellEnqueuePromiseJobCallback);
     JS::SetGetIncumbentGlobalCallback(cx, ShellGetIncumbentGlobalCallback);
 #endif // SPIDERMONKEY_PROMISE
 
     EnvironmentPreparer environmentPreparer(cx);
 
     JS::SetLargeAllocationFailureCallback(cx, my_LargeAllocFailCallback, (void*)cx);
 
@@ -3004,20 +3003,20 @@ WorkerMain(void* arg)
         JS_ExecuteScript(cx, script, &result);
     } while (0);
 
     JS::SetLargeAllocationFailureCallback(cx, nullptr, nullptr);
 
 #ifdef SPIDERMONKEY_PROMISE
     JS::SetGetIncumbentGlobalCallback(cx, nullptr);
     JS::SetEnqueuePromiseJobCallback(cx, nullptr);
-    sr->jobQueue.reset();
+    sc->jobQueue.reset();
 #endif // SPIDERMONKEY_PROMISE
 
-    KillWatchdog(rt);
+    KillWatchdog(cx);
 
     JS_DestroyRuntime(rt);
 
     js_delete(input);
 }
 
 // Workers can spawn other workers, so we need a lock to access workerThreads.
 static Mutex* workerThreadsLock = nullptr;
@@ -3112,17 +3111,17 @@ ShapeOf(JSContext* cx, unsigned argc, JS
     JSObject* obj = &args[0].toObject();
     args.rval().set(JS_NumberValue(double(uintptr_t(obj->maybeShape()) >> 3)));
     return true;
 }
 
 static bool
 Sleep_fn(JSContext* cx, unsigned argc, Value* vp)
 {
-    ShellRuntime* sr = GetShellRuntime(cx);
+    ShellContext* sc = GetShellContext(cx);
     CallArgs args = CallArgsFromVp(argc, vp);
 
     TimeDuration duration = TimeDuration::FromSeconds(0.0);
     if (args.length() > 0) {
         double t_secs;
         if (!ToNumber(cx, args[0], &t_secs))
             return false;
         if (mozilla::IsNaN(t_secs)) {
@@ -3132,113 +3131,113 @@ Sleep_fn(JSContext* cx, unsigned argc, V
 
         duration = TimeDuration::FromSeconds(Max(0.0, t_secs));
         if (duration > MAX_TIMEOUT_INTERVAL) {
             JS_ReportError(cx, "Excessive sleep interval");
             return false;
         }
     }
     {
-        LockGuard<Mutex> guard(sr->watchdogLock);
+        LockGuard<Mutex> guard(sc->watchdogLock);
         TimeStamp toWakeup = TimeStamp::Now() + duration;
         for (;;) {
-            sr->sleepWakeup.wait_for(guard, duration);
-            if (sr->serviceInterrupt)
+            sc->sleepWakeup.wait_for(guard, duration);
+            if (sc->serviceInterrupt)
                 break;
             auto now = TimeStamp::Now();
             if (now >= toWakeup)
                 break;
             duration = toWakeup - now;
         }
     }
     args.rval().setUndefined();
-    return !sr->serviceInterrupt;
+    return !sc->serviceInterrupt;
 }
 
 static void
-KillWatchdog(JSRuntime* rt)
-{
-    ShellRuntime* sr = GetShellRuntime(rt);
+KillWatchdog(JSContext* cx)
+{
+    ShellContext* sc = GetShellContext(cx);
     Maybe<Thread> thread;
 
     {
-        LockGuard<Mutex> guard(sr->watchdogLock);
-        Swap(sr->watchdogThread, thread);
+        LockGuard<Mutex> guard(sc->watchdogLock);
+        Swap(sc->watchdogThread, thread);
         if (thread) {
             // The watchdog thread becoming Nothing is its signal to exit.
-            sr->watchdogWakeup.notify_one();
+            sc->watchdogWakeup.notify_one();
         }
     }
     if (thread)
         thread->join();
 
-    MOZ_ASSERT(!sr->watchdogThread);
+    MOZ_ASSERT(!sc->watchdogThread);
 }
 
 static void
-WatchdogMain(JSRuntime* rt)
+WatchdogMain(JSContext* cx)
 {
     ThisThread::SetName("JS Watchdog");
 
-    ShellRuntime* sr = GetShellRuntime(rt);
-
-    LockGuard<Mutex> guard(sr->watchdogLock);
-    while (sr->watchdogThread) {
+    ShellContext* sc = GetShellContext(cx);
+
+    LockGuard<Mutex> guard(sc->watchdogLock);
+    while (sc->watchdogThread) {
         auto now = TimeStamp::Now();
-        if (sr->watchdogTimeout && now >= sr->watchdogTimeout.value()) {
+        if (sc->watchdogTimeout && now >= sc->watchdogTimeout.value()) {
             /*
              * The timeout has just expired. Request an interrupt callback
              * outside the lock.
              */
-            sr->watchdogTimeout = Nothing();
+            sc->watchdogTimeout = Nothing();
             {
                 UnlockGuard<Mutex> unlock(guard);
-                CancelExecution(rt);
+                CancelExecution(cx);
             }
 
             /* Wake up any threads doing sleep. */
-            sr->sleepWakeup.notify_all();
+            sc->sleepWakeup.notify_all();
         } else {
-            if (sr->watchdogTimeout) {
+            if (sc->watchdogTimeout) {
                 /*
                  * Time hasn't expired yet. Simulate an interrupt callback
                  * which doesn't abort execution.
                  */
-                JS_RequestInterruptCallback(rt);
+                JS_RequestInterruptCallback(cx->runtime());
             }
 
-            TimeDuration sleepDuration = sr->watchdogTimeout
+            TimeDuration sleepDuration = sc->watchdogTimeout
                                          ? TimeDuration::FromSeconds(0.1)
                                          : TimeDuration::Forever();
-            sr->watchdogWakeup.wait_for(guard, sleepDuration);
+            sc->watchdogWakeup.wait_for(guard, sleepDuration);
         }
     }
 }
 
 static bool
-ScheduleWatchdog(JSRuntime* rt, double t)
-{
-    ShellRuntime* sr = GetShellRuntime(rt);
+ScheduleWatchdog(JSContext* cx, double t)
+{
+    ShellContext* sc = GetShellContext(cx);
 
     if (t <= 0) {
-        LockGuard<Mutex> guard(sr->watchdogLock);
-        sr->watchdogTimeout = Nothing();
+        LockGuard<Mutex> guard(sc->watchdogLock);
+        sc->watchdogTimeout = Nothing();
         return true;
     }
 
     auto interval = TimeDuration::FromSeconds(t);
     auto timeout = TimeStamp::Now() + interval;
-    LockGuard<Mutex> guard(sr->watchdogLock);
-    if (!sr->watchdogThread) {
-        MOZ_ASSERT(!sr->watchdogTimeout);
-        sr->watchdogThread.emplace(WatchdogMain, rt);
-    } else if (!sr->watchdogTimeout || timeout < sr->watchdogTimeout.value()) {
-        sr->watchdogWakeup.notify_one();
-    }
-    sr->watchdogTimeout = Some(timeout);
+    LockGuard<Mutex> guard(sc->watchdogLock);
+    if (!sc->watchdogThread) {
+        MOZ_ASSERT(!sc->watchdogTimeout);
+        sc->watchdogThread.emplace(WatchdogMain, cx);
+    } else if (!sc->watchdogTimeout || timeout < sc->watchdogTimeout.value()) {
+        sc->watchdogWakeup.notify_one();
+    }
+    sc->watchdogTimeout = Some(timeout);
     return true;
 }
 
 static void
 KillWorkerThreads()
 {
     MOZ_ASSERT_IF(!CanUseExtraThreads(), workerThreads.empty());
 
@@ -3261,55 +3260,55 @@ KillWorkerThreads()
         PR_JoinThread(thread);
     }
 
     js_delete(workerThreadsLock);
     workerThreadsLock = nullptr;
 }
 
 static void
-CancelExecution(JSRuntime* rt)
-{
-    ShellRuntime* sr = GetShellRuntime(rt);
-    sr->serviceInterrupt = true;
-    JS_RequestInterruptCallback(rt);
-
-    if (sr->haveInterruptFunc) {
+CancelExecution(JSContext* cx)
+{
+    ShellContext* sc = GetShellContext(cx);
+    sc->serviceInterrupt = true;
+    JS_RequestInterruptCallback(cx->runtime());
+
+    if (sc->haveInterruptFunc) {
         static const char msg[] = "Script runs for too long, terminating.\n";
         fputs(msg, stderr);
     }
 }
 
 static bool
 SetTimeoutValue(JSContext* cx, double t)
 {
     if (mozilla::IsNaN(t)) {
         JS_ReportError(cx, "timeout is not a number");
         return false;
     }
     if (TimeDuration::FromSeconds(t) > MAX_TIMEOUT_INTERVAL) {
         JS_ReportError(cx, "Excessive timeout value");
         return false;
     }
-    GetShellRuntime(cx)->timeoutInterval = t;
-    if (!ScheduleWatchdog(cx->runtime(), t)) {
+    GetShellContext(cx)->timeoutInterval = t;
+    if (!ScheduleWatchdog(cx, t)) {
         JS_ReportError(cx, "Failed to create the watchdog");
         return false;
     }
     return true;
 }
 
 static bool
 Timeout(JSContext* cx, unsigned argc, Value* vp)
 {
-    ShellRuntime* sr = GetShellRuntime(cx);
+    ShellContext* sc = GetShellContext(cx);
     CallArgs args = CallArgsFromVp(argc, vp);
 
     if (args.length() == 0) {
-        args.rval().setNumber(sr->timeoutInterval);
+        args.rval().setNumber(sc->timeoutInterval);
         return true;
     }
 
     if (args.length() > 2) {
         JS_ReportError(cx, "Wrong number of arguments");
         return false;
     }
 
@@ -3318,18 +3317,18 @@ Timeout(JSContext* cx, unsigned argc, Va
         return false;
 
     if (args.length() > 1) {
         RootedValue value(cx, args[1]);
         if (!value.isObject() || !value.toObject().is<JSFunction>()) {
             JS_ReportError(cx, "Second argument must be a timeout function");
             return false;
         }
-        sr->interruptFunc = value;
-        sr->haveInterruptFunc = true;
+        sc->interruptFunc = value;
+        sc->haveInterruptFunc = true;
     }
 
     args.rval().setUndefined();
     return SetTimeoutValue(cx, t);
 }
 
 static bool
 InterruptIf(JSContext* cx, unsigned argc, Value* vp)
@@ -3337,34 +3336,34 @@ InterruptIf(JSContext* cx, unsigned argc
     CallArgs args = CallArgsFromVp(argc, vp);
 
     if (args.length() != 1) {
         JS_ReportError(cx, "Wrong number of arguments");
         return false;
     }
 
     if (ToBoolean(args[0])) {
-        GetShellRuntime(cx)->serviceInterrupt = true;
+        GetShellContext(cx)->serviceInterrupt = true;
         JS_RequestInterruptCallback(cx->runtime());
     }
 
     args.rval().setUndefined();
     return true;
 }
 
 static bool
 InvokeInterruptCallbackWrapper(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     if (args.length() != 1) {
         JS_ReportError(cx, "Wrong number of arguments");
         return false;
     }
 
-    GetShellRuntime(cx)->serviceInterrupt = true;
+    GetShellContext(cx)->serviceInterrupt = true;
     JS_RequestInterruptCallback(cx->runtime());
     bool interruptRv = CheckForInterrupt(cx);
 
     // The interrupt handler could have set a pending exception. Since we call
     // back into JS, don't have it see the pending exception. If we have an
     // uncatchable exception that's not propagating a debug mode forced
     // return, return.
     if (!interruptRv && !cx->isExceptionPending() && !cx->isPropagatingForcedReturn())
@@ -3394,79 +3393,79 @@ SetInterruptCallback(JSContext* cx, unsi
         return false;
     }
 
     RootedValue value(cx, args[0]);
     if (!value.isObject() || !value.toObject().is<JSFunction>()) {
         JS_ReportError(cx, "Argument must be a function");
         return false;
     }
-    GetShellRuntime(cx)->interruptFunc = value;
-    GetShellRuntime(cx)->haveInterruptFunc = true;
+    GetShellContext(cx)->interruptFunc = value;
+    GetShellContext(cx)->haveInterruptFunc = true;
 
     args.rval().setUndefined();
     return true;
 }
 
 static bool
 EnableLastWarning(JSContext* cx, unsigned argc, Value* vp)
 {
-    ShellRuntime* sr = GetShellRuntime(cx);
+    ShellContext* sc = GetShellContext(cx);
     CallArgs args = CallArgsFromVp(argc, vp);
 
-    sr->lastWarningEnabled = true;
-    sr->lastWarning.setNull();
+    sc->lastWarningEnabled = true;
+    sc->lastWarning.setNull();
 
     args.rval().setUndefined();
     return true;
 }
 
 static bool
 DisableLastWarning(JSContext* cx, unsigned argc, Value* vp)
 {
-    ShellRuntime* sr = GetShellRuntime(cx);
+    ShellContext* sc = GetShellContext(cx);
     CallArgs args = CallArgsFromVp(argc, vp);
 
-    sr->lastWarningEnabled = false;
-    sr->lastWarning.setNull();
+    sc->lastWarningEnabled = false;
+    sc->lastWarning.setNull();
 
     args.rval().setUndefined();
     return true;
 }
 
 static bool
 GetLastWarning(JSContext* cx, unsigned argc, Value* vp)
 {
-    ShellRuntime* sr = GetShellRuntime(cx);
+    ShellContext* sc = GetShellContext(cx);
     CallArgs args = CallArgsFromVp(argc, vp);
 
-    if (!sr->lastWarningEnabled) {
+    if (!sc->lastWarningEnabled) {
         JS_ReportError(cx, "Call enableLastWarning first.");
         return false;
     }
 
-    if (!JS_WrapValue(cx, &sr->lastWarning))
-        return false;
-
-    args.rval().set(sr->lastWarning);
+    if (!JS_WrapValue(cx, &sc->lastWarning))
+        return false;
+
+    args.rval().set(sc->lastWarning);
     return true;
 }
 
 static bool
 ClearLastWarning(JSContext* cx, unsigned argc, Value* vp)
 {
-    ShellRuntime* sr = GetShellRuntime(cx);
+    ShellContext* sc = GetShellContext(cx);
     CallArgs args = CallArgsFromVp(argc, vp);
 
-    if (!sr->lastWarningEnabled) {
+    if (!sc->lastWarningEnabled) {
         JS_ReportError(cx, "Call enableLastWarning first.");
         return false;
     }
 
-    sr->lastWarning.setNull();
+    sc->lastWarning.setNull();
 
     args.rval().setUndefined();
     return true;
 }
 
 #ifdef DEBUG
 static bool
 StackDump(JSContext* cx, unsigned argc, Value* vp)
@@ -3507,17 +3506,17 @@ StackPointerInfo(JSContext* cx, unsigned
 }
 
 
 static bool
 Elapsed(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     if (args.length() == 0) {
-        double d = PRMJ_Now() - GetShellRuntime(cx)->startTime;
+        double d = PRMJ_Now() - GetShellContext(cx)->startTime;
         args.rval().setDouble(d);
         return true;
     }
     JS_ReportError(cx, "Wrong number of arguments");
     return false;
 }
 
 static bool
@@ -4491,17 +4490,17 @@ IsCachingEnabled(JSContext* cx, unsigned
     args.rval().setBoolean(jsCachingEnabled && jsCacheAsmJSPath != nullptr);
     return true;
 }
 
 static bool
 SetCachingEnabled(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
-    if (GetShellRuntime(cx)->isWorker) {
+    if (GetShellContext(cx)->isWorker) {
         JS_ReportError(cx, "Caching is not supported in workers");
         return false;
     }
 
     jsCachingEnabled = ToBoolean(args.get(0));
     args.rval().setUndefined();
     return true;
 }
@@ -4634,56 +4633,56 @@ IsLatin1(JSContext* cx, unsigned argc, V
     return true;
 }
 
 static bool
 EnableSPSProfiling(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
-    ShellRuntime* sr = GetShellRuntime(cx);
+    ShellContext* sc = GetShellContext(cx);
 
     // Disable before re-enabling; see the assertion in |SPSProfiler::setProfilingStack|.
     if (cx->runtime()->spsProfiler.installed())
         cx->runtime()->spsProfiler.enable(false);
 
-    SetRuntimeProfilingStack(cx->runtime(), sr->spsProfilingStack, &sr->spsProfilingStackSize,
-                             ShellRuntime::SpsProfilingMaxStackSize);
+    SetRuntimeProfilingStack(cx->runtime(), sc->spsProfilingStack, &sc->spsProfilingStackSize,
+                             ShellContext::SpsProfilingMaxStackSize);
     cx->runtime()->spsProfiler.enableSlowAssertions(false);
     cx->runtime()->spsProfiler.enable(true);
 
     args.rval().setUndefined();
     return true;
 }
 
 static bool
 EnableSPSProfilingWithSlowAssertions(JSContext* cx, unsigned argc, Value* vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     args.rval().setUndefined();
 
-    ShellRuntime* sr = GetShellRuntime(cx);
+    ShellContext* sc = GetShellContext(cx);
 
     if (cx->runtime()->spsProfiler.enabled()) {
         // If profiling already enabled with slow assertions disabled,
         // this is a no-op.
         if (cx->runtime()->spsProfiler.slowAssertionsEnabled())
             return true;
 
         // Slow assertions are off.  Disable profiling before re-enabling
         // with slow assertions on.
         cx->runtime()->spsProfiler.enable(false);
     }
 
     // Disable before re-enabling; see the assertion in |SPSProfiler::setProfilingStack|.
     if (cx->runtime()->spsProfiler.installed())
         cx->runtime()->spsProfiler.enable(false);
 
-    SetRuntimeProfilingStack(cx->runtime(), sr->spsProfilingStack, &sr->spsProfilingStackSize,
-                             ShellRuntime::SpsProfilingMaxStackSize);
+    SetRuntimeProfilingStack(cx->runtime(), sc->spsProfilingStack, &sc->spsProfilingStackSize,
+                             ShellContext::SpsProfilingMaxStackSize);
     cx->runtime()->spsProfiler.enableSlowAssertions(true);
     cx->runtime()->spsProfiler.enable(true);
 
     return true;
 }
 
 static bool
 DisableSPSProfiling(JSContext* cx, unsigned argc, Value* vp)
@@ -5978,17 +5977,17 @@ CreateLastWarningObject(JSContext* cx, J
     RootedValue linenoVal(cx, Int32Value(report->lineno));
     if (!DefineProperty(cx, warningObj, cx->names().lineNumber, linenoVal))
         return false;
 
     RootedValue columnVal(cx, Int32Value(report->column));
     if (!DefineProperty(cx, warningObj, cx->names().columnNumber, columnVal))
         return false;
 
-    GetShellRuntime(cx)->lastWarning.setObject(*warningObj);
+    GetShellContext(cx)->lastWarning.setObject(*warningObj);
     return true;
 }
 
 static FILE*
 ErrorFilePointer()
 {
     if (gErrFile->isOpen())
         return gErrFile->fp;
@@ -6040,17 +6039,17 @@ js::shell::AutoReportException::~AutoRep
         return;
 
     // Get exception object before printing and clearing exception.
     RootedValue exn(cx);
     (void) JS_GetPendingException(cx, &exn);
 
     JS_ClearPendingException(cx);
 
-    ShellRuntime* sr = GetShellRuntime(cx);
+    ShellContext* sc = GetShellContext(cx);
     js::ErrorReport report(cx);
     if (!report.init(cx, exn, js::ErrorReport::WithSideEffects)) {
         fprintf(stderr, "out of memory initializing ErrorReport\n");
         JS_ClearPendingException(cx);
         return;
     }
 
     MOZ_ASSERT(!JSREPORT_IS_WARNING(report.report()->flags));
@@ -6061,33 +6060,33 @@ js::shell::AutoReportException::~AutoRep
     {
         JS::AutoSaveExceptionState savedExc(cx);
         if (!PrintStackTrace(cx, exn))
             fputs("(Unable to print stack trace)\n", fp);
         savedExc.restore();
     }
 
     if (report.report()->errorNumber == JSMSG_OUT_OF_MEMORY)
-        sr->exitCode = EXITCODE_OUT_OF_MEMORY;
+        sc->exitCode = EXITCODE_OUT_OF_MEMORY;
     else
-        sr->exitCode = EXITCODE_RUNTIME_ERROR;
+        sc->exitCode = EXITCODE_RUNTIME_ERROR;
 
     JS_ClearPendingException(cx);
 }
 
 void
 js::shell::WarningReporter(JSContext* cx, const char* message, JSErrorReport* report)
 {
-    ShellRuntime* sr = GetShellRuntime(cx);
+    ShellContext* sc = GetShellContext(cx);
     FILE* fp = ErrorFilePointer();
 
     MOZ_ASSERT(report);
     MOZ_ASSERT(JSREPORT_IS_WARNING(report->flags));
 
-    if (sr->lastWarningEnabled) {
+    if (sc->lastWarningEnabled) {
         JS::AutoSaveExceptionState savedExc(cx);
         if (!CreateLastWarningObject(cx, report)) {
             fputs("Unhandled error happened while creating last warning object.\n", fp);
             fflush(fp);
         }
         savedExc.restore();
     }
 
@@ -6728,17 +6727,17 @@ OptionFailure(const char* option, const 
 {
     fprintf(stderr, "Unrecognized option for %s: %s\n", option, str);
     return false;
 }
 
 static MOZ_MUST_USE bool
 ProcessArgs(JSContext* cx, OptionParser* op)
 {
-    ShellRuntime* sr = GetShellRuntime(cx);
+    ShellContext* sc = GetShellContext(cx);
 
     if (op->getBoolOption('s'))
         JS::ContextOptionsRef(cx).toggleExtraWarnings();
 
     /* |scriptArgs| gets bound on the global before any code is run. */
     if (!BindScriptArgs(cx, op))
         return false;
 
@@ -6773,28 +6772,28 @@ ProcessArgs(JSContext* cx, OptionParser*
         } else if (ccArgno < fpArgno && ccArgno < mpArgno) {
             const char* code = codeChunks.front();
             RootedValue rval(cx);
             JS::CompileOptions opts(cx);
             opts.setFileAndLine("-e", 1);
             if (!JS::Evaluate(cx, opts, code, strlen(code), &rval))
                 return false;
             codeChunks.popFront();
-            if (sr->quitting)
+            if (sc->quitting)
                 break;
         } else {
             MOZ_ASSERT(mpArgno < fpArgno && mpArgno < ccArgno);
             char* path = modulePaths.front();
             if (!Process(cx, path, false, FileModule))
                 return false;
             modulePaths.popFront();
         }
     }
 
-    if (sr->quitting)
+    if (sc->quitting)
         return false;
 
     /* The |script| argument is processed after all options. */
     if (const char* path = op->getStringArg("script")) {
         if (!Process(cx, path, false))
             return false;
     }
 
@@ -7134,26 +7133,26 @@ Shell(JSContext* cx, OptionParser* op, c
     JS::CompartmentOptions options;
     SetStandardCompartmentOptions(options);
     RootedObject glob(cx, NewGlobalObject(cx, options, nullptr));
     if (!glob)
         return 1;
 
     JSAutoCompartment ac(cx, glob);
 
-    ShellRuntime* sr = GetShellRuntime(cx);
+    ShellContext* sc = GetShellContext(cx);
     int result = EXIT_SUCCESS;
     {
         AutoReportException are(cx);
-        if (!ProcessArgs(cx, op) && !sr->quitting)
+        if (!ProcessArgs(cx, op) && !sc->quitting)
             result = EXITCODE_RUNTIME_ERROR;
     }
 
-    if (sr->exitCode)
-        result = sr->exitCode;
+    if (sc->exitCode)
+        result = sc->exitCode;
 
     if (enableDisassemblyDumps)
         js::DumpCompartmentPCCounts(cx);
 
     if (!op->getBoolOption("no-js-cache-per-process")) {
         if (jsCacheAsmJSPath) {
             unlink(jsCacheAsmJSPath);
             JS_free(cx, const_cast<char*>(jsCacheAsmJSPath));
@@ -7453,23 +7452,23 @@ main(int argc, char** argv, char** envp)
     size_t nurseryBytes = JS::DefaultNurseryBytes;
     nurseryBytes = op.getIntOption("nursery-size") * 1024L * 1024L;
 
     /* Use the same parameters as the browser in xpcjsruntime.cpp. */
     JSRuntime* rt = JS_NewRuntime(JS::DefaultHeapMaxBytes, nurseryBytes);
     if (!rt)
         return 1;
 
-    UniquePtr<ShellRuntime> sr = MakeUnique<ShellRuntime>(rt);
-    if (!sr)
+    JSContext* cx = JS_GetContext(rt);
+
+    UniquePtr<ShellContext> sc = MakeUnique<ShellContext>(cx);
+    if (!sc)
         return 1;
 
-    JSContext* cx = JS_GetContext(rt);
-
-    JS_SetContextPrivate(cx, sr.get());
+    JS_SetContextPrivate(cx, sc.get());
     // Waiting is allowed on the shell's main thread, for now.
     JS_SetFutexCanWait(cx);
     JS::SetWarningReporter(cx, WarningReporter);
     if (!SetContextOptions(cx, op))
         return 1;
 
     JS_SetGCParameter(cx, JSGC_MAX_BYTES, 0xffffffff);
 
@@ -7488,17 +7487,17 @@ main(int argc, char** argv, char** envp)
     JS_SetNativeStackQuota(cx, gMaxStackSize);
 
     JS::dbg::SetDebuggerMallocSizeOf(cx, moz_malloc_size_of);
 
     if (!JS::InitSelfHostedCode(cx))
         return 1;
 
 #ifdef SPIDERMONKEY_PROMISE
-    sr->jobQueue.init(cx, JobQueue(SystemAllocPolicy()));
+    sc->jobQueue.init(cx, JobQueue(SystemAllocPolicy()));
     JS::SetEnqueuePromiseJobCallback(cx, ShellEnqueuePromiseJobCallback);
     JS::SetGetIncumbentGlobalCallback(cx, ShellGetIncumbentGlobalCallback);
 #endif // SPIDERMONKEY_PROMISE
 
     EnvironmentPreparer environmentPreparer(cx);
 
     JS_SetGCParameter(cx, JSGC_MODE, JSGC_MODE_INCREMENTAL);
 
@@ -7524,20 +7523,20 @@ main(int argc, char** argv, char** envp)
         printf("OOM max count: %" PRIu64 "\n", js::oom::counter);
 #endif
 
     JS::SetLargeAllocationFailureCallback(cx, nullptr, nullptr);
 
 #ifdef SPIDERMONKEY_PROMISE
     JS::SetGetIncumbentGlobalCallback(cx, nullptr);
     JS::SetEnqueuePromiseJobCallback(cx, nullptr);
-    sr->jobQueue.reset();
+    sc->jobQueue.reset();
 #endif // SPIDERMONKEY_PROMISE
 
-    KillWatchdog(rt);
+    KillWatchdog(cx);
 
     KillWorkerThreads();
 
     DestructSharedArrayBufferMailbox();
 
     JS_DestroyRuntime(rt);
     JS_ShutDown();
     return result;