Bug 1279295 - Create the runtime's JSContext when we create the runtime. r=luke
authorJan de Mooij <jdemooij@mozilla.com>
Wed, 22 Jun 2016 09:47:52 +0200
changeset 344439 0ca871e39a20d94c5c8948beb41867d679f3709e
parent 344438 e3c00a0692367cc1ea6cf6f40813abfaa74eba8a
child 344440 d56d7039aee08a36f9dc0a9bb4b1ffafd16baa5f
push id1230
push userjlund@mozilla.com
push dateMon, 31 Oct 2016 18:13:35 +0000
treeherdermozilla-release@5e06e3766db2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersluke
bugs1279295
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 1279295 - Create the runtime's JSContext when we create the runtime. r=luke
devtools/shared/heapsnapshot/tests/gtest/DevTools.h
dom/indexedDB/ActorsParent.cpp
dom/workers/RuntimeService.cpp
js/src/ctypes/CTypes.cpp
js/src/gc/RootMarking.cpp
js/src/gdb/gdb-tests.cpp
js/src/jsapi-tests/tests.cpp
js/src/jsapi-tests/tests.h
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jscntxt.cpp
js/src/jscntxt.h
js/src/shell/js.cpp
js/src/vm/Runtime.cpp
js/src/vm/Runtime.h
js/xpconnect/src/XPCComponents.cpp
js/xpconnect/src/XPCJSContextStack.cpp
js/xpconnect/src/XPCJSRuntime.cpp
netwerk/base/ProxyAutoConfig.cpp
xpcom/glue/tests/gtest/TestGCPostBarriers.cpp
--- a/devtools/shared/heapsnapshot/tests/gtest/DevTools.h
+++ b/devtools/shared/heapsnapshot/tests/gtest/DevTools.h
@@ -44,17 +44,17 @@ struct DevTools : public ::testing::Test
   virtual void SetUp() {
     MOZ_ASSERT(!_initialized);
 
     rt = getRuntime();
     if (!rt)
       return;
 
     MOZ_RELEASE_ASSERT(!cx);
-    MOZ_RELEASE_ASSERT(JS_ContextIterator(rt, &cx));
+    cx = JS_GetContext(rt);
 
     JS_BeginRequest(cx);
 
     global.init(rt, createGlobal());
     if (!global)
       return;
     JS_EnterCompartment(cx, global);
 
--- a/dom/indexedDB/ActorsParent.cpp
+++ b/dom/indexedDB/ActorsParent.cpp
@@ -7903,20 +7903,16 @@ protected:
   {
     MOZ_COUNT_CTOR(NormalJSRuntime);
   }
 
   ~NormalJSRuntime()
   {
     MOZ_COUNT_DTOR(NormalJSRuntime);
 
-    if (mContext) {
-      JS_DestroyContext(mContext);
-    }
-
     if (mRuntime) {
       JS_DestroyRuntime(mRuntime);
     }
   }
 
   bool
   Init();
 };
@@ -24153,18 +24149,18 @@ NormalJSRuntime::Init()
   mRuntime = JS_NewRuntime(kRuntimeHeapSize);
   if (NS_WARN_IF(!mRuntime)) {
     return false;
   }
 
   // Not setting this will cause JS_CHECK_RECURSION to report false positives.
   JS_SetNativeStackQuota(mRuntime, 128 * sizeof(size_t) * 1024);
 
-  mContext = JS_NewContext(mRuntime, 0);
-  if (NS_WARN_IF(!mContext)) {
+  mContext = JS_GetContext(mRuntime);
+  if (NS_WARN_IF(!JS::InitSelfHostedCode(mContext))) {
     return false;
   }
 
   JSAutoRequest ar(mContext);
 
   JS::CompartmentOptions options;
   mGlobal = JS_NewGlobalObject(mContext, &sGlobalClass, nullptr,
                                JS::FireOnNewGlobalHook, options);
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -743,17 +743,17 @@ private:
 
   WorkerThreadRuntimePrivate(const WorkerThreadRuntimePrivate&) = delete;
 
   WorkerThreadRuntimePrivate&
   operator=(const WorkerThreadRuntimePrivate&) = delete;
 };
 
 JSContext*
-CreateJSContextForWorker(WorkerPrivate* aWorkerPrivate, JSRuntime* aRuntime)
+InitJSContextForWorker(WorkerPrivate* aWorkerPrivate, JSRuntime* aRuntime)
 {
   aWorkerPrivate->AssertIsOnWorkerThread();
   NS_ASSERTION(!aWorkerPrivate->GetJSContext(), "Already has a context!");
 
   JSSettings settings;
   aWorkerPrivate->CopyJSSettings(settings);
 
   JS::RuntimeOptionsRef(aRuntime) = settings.runtimeOptions;
@@ -781,19 +781,19 @@ CreateJSContextForWorker(WorkerPrivate* 
   static const JS::AsmJSCacheOps asmJSCacheOps = {
     AsmJSCacheOpenEntryForRead,
     asmjscache::CloseEntryForRead,
     AsmJSCacheOpenEntryForWrite,
     asmjscache::CloseEntryForWrite
   };
   JS::SetAsmJSCacheOps(aRuntime, &asmJSCacheOps);
 
-  JSContext* workerCx = JS_NewContext(aRuntime, 0);
-  if (!workerCx) {
-    NS_WARNING("Could not create new context!");
+  JSContext* workerCx = JS_GetContext(aRuntime);
+  if (!JS::InitSelfHostedCode(workerCx)) {
+    NS_WARNING("Could not init self-hosted code!");
     return nullptr;
   }
 
   JS_SetInterruptCallback(aRuntime, InterruptCallback);
 
   js::SetCTypesActivityCallback(aRuntime, CTypesActivityCallback);
 
 #ifdef JS_GC_ZEAL
@@ -840,17 +840,17 @@ static const JSWrapObjectCallbacks WrapO
   Wrap,
   nullptr,
 };
 
 class WorkerJSRuntime : public mozilla::CycleCollectedJSRuntime
 {
 public:
   // The heap size passed here doesn't matter, we will change it later in the
-  // call to JS_SetGCParameter inside CreateJSContextForWorker.
+  // call to JS_SetGCParameter inside InitJSContextForWorker.
   explicit WorkerJSRuntime(WorkerPrivate* aWorkerPrivate)
     : mWorkerPrivate(aWorkerPrivate)
   {
     MOZ_ASSERT(aWorkerPrivate);
   }
 
   ~WorkerJSRuntime()
   {
@@ -2568,17 +2568,17 @@ WorkerThreadPrimaryRunnable::Run()
     WorkerJSRuntime runtime(mWorkerPrivate);
     nsresult rv = runtime.Initialize(mParentRuntime);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
     JSRuntime* rt = runtime.Runtime();
 
-    JSContext* cx = CreateJSContextForWorker(mWorkerPrivate, rt);
+    JSContext* cx = InitJSContextForWorker(mWorkerPrivate, rt);
     if (!cx) {
       // XXX need to fire an error at parent.
       NS_ERROR("Failed to create runtime and context!");
       return NS_ERROR_FAILURE;
     }
 
     {
 #ifdef MOZ_ENABLE_PROFILER_SPS
@@ -2609,19 +2609,19 @@ WorkerThreadPrimaryRunnable::Run()
 
     // There may still be runnables on the debugger event queue that hold a
     // strong reference to the debugger global scope. These runnables are not
     // visible to the cycle collector, so we need to make sure to clear the
     // debugger event queue before we try to destroy the context. If we don't,
     // the garbage collector will crash.
     mWorkerPrivate->ClearDebuggerEventQueue();
 
-    // Destroy the main context. This will unroot the main worker global and GC,
+    // Perform a full GC. This will collect the main worker global and CC,
     // which should break all cycles that touch JS.
-    JS_DestroyContext(cx);
+    JS_GC(JS_GetRuntime(cx));
 
     // Before shutting down the cycle collector we need to do one more pass
     // through the event loop to clean up any C++ objects that need deferred
     // cleanup.
     mWorkerPrivate->ClearMainEventQueue(WorkerPrivate::WorkerRan);
 
     // Now WorkerJSRuntime goes out of scope and its destructor will shut
     // down the cycle collector. This breaks any remaining cycles and collects
--- a/js/src/ctypes/CTypes.cpp
+++ b/js/src/ctypes/CTypes.cpp
@@ -7400,21 +7400,18 @@ CClosure::ClosureStub(ffi_cif* cif, void
   MOZ_ASSERT(args);
   MOZ_ASSERT(userData);
 
   // Retrieve the essentials from our closure object.
   ArgClosure argClosure(cif, result, args, static_cast<ClosureInfo*>(userData));
   JSRuntime* rt = argClosure.cinfo->rt;
   RootedObject fun(rt, argClosure.cinfo->jsfnObj);
 
-  // Arbitrarily choose a cx in which to run this code. This is bad, as
-  // JSContexts are stateful and have options. The hope is to eliminate
-  // JSContexts (see bug 650361).
-  js::PrepareScriptEnvironmentAndInvoke(rt->contextList.getFirst(), fun,
-                                        argClosure);
+  JSContext* cx = JS_GetContext(rt);
+  js::PrepareScriptEnvironmentAndInvoke(cx, fun, argClosure);
 }
 
 bool CClosure::ArgClosure::operator()(JSContext* cx)
 {
   // Let the runtime callback know that we are about to call into JS again. The end callback will
   // fire automatically when we exit this function.
   js::AutoCTypesActivityCallback autoCallback(cx, js::CTYPES_CALLBACK_BEGIN,
                                               js::CTYPES_CALLBACK_END);
--- a/js/src/gc/RootMarking.cpp
+++ b/js/src/gc/RootMarking.cpp
@@ -218,28 +218,30 @@ AutoGCRooter::trace(JSTracer* trc)
     MOZ_ASSERT(tag_ >= 0);
     if (Value* vp = static_cast<AutoArrayRooter*>(this)->array)
         TraceRootRange(trc, tag_, vp, "JS::AutoArrayRooter.array");
 }
 
 /* static */ void
 AutoGCRooter::traceAll(JSTracer* trc)
 {
-    for (ContextIter cx(trc->runtime()); !cx.done(); cx.next())
-        traceAllInContext(&*cx, trc);
+    if (JSContext* cx = trc->runtime()->maybeContextFromMainThread())
+        traceAllInContext(cx, trc);
 }
 
 /* static */ void
 AutoGCRooter::traceAllWrappers(JSTracer* trc)
 {
-    for (ContextIter cx(trc->runtime()); !cx.done(); cx.next()) {
-        for (AutoGCRooter* gcr = cx->roots.autoGCRooters_; gcr; gcr = gcr->down) {
-            if (gcr->tag_ == WRAPVECTOR || gcr->tag_ == WRAPPER)
-                gcr->trace(trc);
-        }
+    JSContext* cx = trc->runtime()->maybeContextFromMainThread();
+    if (!cx)
+        return;
+
+    for (AutoGCRooter* gcr = cx->roots.autoGCRooters_; gcr; gcr = gcr->down) {
+        if (gcr->tag_ == WRAPVECTOR || gcr->tag_ == WRAPPER)
+            gcr->trace(trc);
     }
 }
 
 void
 StackShape::trace(JSTracer* trc)
 {
     if (base)
         TraceRoot(trc, &base, "StackShape base");
@@ -313,18 +315,18 @@ js::gc::GCRuntime::markRuntime(JSTracer*
             MarkWellKnownSymbols(trc);
             jit::JitRuntime::Mark(trc, lock);
         }
     }
 
     if (rt->isHeapMinorCollecting())
         jit::JitRuntime::MarkJitcodeGlobalTableUnconditionally(trc);
 
-    for (ContextIter acx(rt); !acx.done(); acx.next())
-        acx->mark(trc);
+    if (JSContext* cx = rt->maybeContextFromMainThread())
+        cx->mark(trc);
 
     for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next())
         c->traceRoots(trc, traceOrMark);
 
     MarkInterpreterActivations(rt, trc);
 
     jit::MarkJitActivations(rt, trc);
 
--- a/js/src/gdb/gdb-tests.cpp
+++ b/js/src/gdb/gdb-tests.cpp
@@ -66,17 +66,18 @@ GDBFragment* GDBFragment::allFragments =
 int
 main(int argc, const char** argv)
 {
     if (!JS_Init()) return 1;
     JSRuntime* runtime = checkPtr(JS_NewRuntime(1024 * 1024));
     JS_SetGCParameter(runtime, JSGC_MAX_BYTES, 0xffffffff);
     JS_SetNativeStackQuota(runtime, 5000000);
 
-    JSContext* cx = checkPtr(JS_NewContext(runtime, 8192));
+    JSContext* cx = JS_GetContext(runtime);
+    checkBool(JS::InitSelfHostedCode(cx));
     JS::SetWarningReporter(runtime, reportWarning);
 
     JSAutoRequest ar(cx);
 
     /* Create the global object. */
     JS::CompartmentOptions options;
     options.behaviors().setVersion(JSVERSION_LATEST);
 
--- a/js/src/jsapi-tests/tests.cpp
+++ b/js/src/jsapi-tests/tests.cpp
@@ -13,18 +13,18 @@
 
 JSAPITest* JSAPITest::list;
 
 bool JSAPITest::init()
 {
     rt = createRuntime();
     if (!rt)
         return false;
-    cx = createContext();
-    if (!cx)
+    cx = JS_GetContext(rt);
+    if (!JS::InitSelfHostedCode(cx))
         return false;
     JS_BeginRequest(cx);
     global.init(rt);
     createGlobal();
     if (!global)
         return false;
     JS_EnterCompartment(cx, global);
     return true;
@@ -37,17 +37,16 @@ void JSAPITest::uninit()
         oldCompartment = nullptr;
     }
     if (global) {
         JS_LeaveCompartment(cx, nullptr);
         global = nullptr;
     }
     if (cx) {
         JS_EndRequest(cx);
-        JS_DestroyContext(cx);
         cx = nullptr;
     }
     if (rt) {
         destroyRuntime();
         rt = nullptr;
     }
 }
 
--- a/js/src/jsapi-tests/tests.h
+++ b/js/src/jsapi-tests/tests.h
@@ -306,20 +306,16 @@ class JSAPITest
         MOZ_RELEASE_ASSERT(JSREPORT_IS_WARNING(report->flags));
 
         fprintf(stderr, "%s:%u:%s\n",
                 report->filename ? report->filename : "<no filename>",
                 (unsigned int) report->lineno,
                 message);
     }
 
-    virtual JSContext* createContext() {
-        return JS_NewContext(rt, 8192);
-    }
-
     virtual const JSClass * getGlobalClass() {
         return basicGlobalClass();
     }
 
     virtual JSObject * createGlobal(JSPrincipals* principals = nullptr);
 };
 
 #define BEGIN_TEST(testname)                                            \
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -296,17 +296,17 @@ JS_PUBLIC_API(Value)
 JS_GetEmptyStringValue(JSContext* cx)
 {
     return StringValue(cx->runtime()->emptyString);
 }
 
 JS_PUBLIC_API(JSString*)
 JS_GetEmptyString(JSRuntime* rt)
 {
-    MOZ_ASSERT(rt->hasContexts());
+    MOZ_ASSERT(rt->emptyString);
     return rt->emptyString;
 }
 
 namespace js {
 
 void
 AssertHeapIsIdle(JSRuntime* rt)
 {
@@ -558,36 +558,16 @@ JS_BeginRequest(JSContext* cx)
 JS_PUBLIC_API(void)
 JS_EndRequest(JSContext* cx)
 {
     MOZ_ASSERT(cx->outstandingRequests != 0);
     cx->outstandingRequests--;
     StopRequest(cx);
 }
 
-JS_PUBLIC_API(JSContext*)
-JS_NewContext(JSRuntime* rt, size_t stackChunkSize)
-{
-    return NewContext(rt, stackChunkSize);
-}
-
-JS_PUBLIC_API(void)
-JS_DestroyContext(JSContext* cx)
-{
-    MOZ_ASSERT(!cx->compartment());
-    DestroyContext(cx, DCM_FORCE_GC);
-}
-
-JS_PUBLIC_API(void)
-JS_DestroyContextNoGC(JSContext* cx)
-{
-    MOZ_ASSERT(!cx->compartment());
-    DestroyContext(cx, DCM_NO_GC);
-}
-
 JS_PUBLIC_API(void*)
 JS_GetContextPrivate(JSContext* cx)
 {
     return cx->data;
 }
 
 JS_PUBLIC_API(void)
 JS_SetContextPrivate(JSContext* cx, void* data)
@@ -608,31 +588,28 @@ JS_SetSecondContextPrivate(JSContext* cx
 }
 
 JS_PUBLIC_API(JSRuntime*)
 JS_GetRuntime(JSContext* cx)
 {
     return cx->runtime();
 }
 
+JS_PUBLIC_API(JSContext*)
+JS_GetContext(JSRuntime* rt)
+{
+    return rt->contextFromMainThread();
+}
+
 JS_PUBLIC_API(JSRuntime*)
 JS_GetParentRuntime(JSRuntime* rt)
 {
     return rt->parentRuntime ? rt->parentRuntime : rt;
 }
 
-JS_PUBLIC_API(JSContext*)
-JS_ContextIterator(JSRuntime* rt, JSContext** iterp)
-{
-    JSContext* cx = *iterp;
-    cx = cx ? cx->getNext() : rt->contextList.getFirst();
-    *iterp = cx;
-    return cx;
-}
-
 JS_PUBLIC_API(JSVersion)
 JS_GetVersion(JSContext* cx)
 {
     return VersionNumber(cx->findVersion());
 }
 
 JS_PUBLIC_API(void)
 JS_SetVersionForCompartment(JSCompartment* compartment, JSVersion version)
@@ -688,16 +665,40 @@ JS::RuntimeOptionsRef(JSRuntime* rt)
 }
 
 JS_PUBLIC_API(JS::RuntimeOptions&)
 JS::RuntimeOptionsRef(JSContext* cx)
 {
     return cx->runtime()->options();
 }
 
+JS_PUBLIC_API(bool)
+JS::InitSelfHostedCode(JSContext* cx)
+{
+    MOZ_RELEASE_ASSERT(!cx->runtime()->hasInitializedSelfHosting(),
+                       "JS::InitSelfHostedCode() called more than once");
+
+    JSRuntime* rt = cx->runtime();
+
+    JSAutoRequest ar(cx);
+    if (!rt->initializeAtoms(cx))
+        return false;
+
+    if (!cx->cycleDetectorSet.init())
+        return false;
+
+    if (!rt->initSelfHosting(cx))
+        return false;
+
+    if (!rt->parentRuntime && !rt->transformToPermanentAtoms(cx))
+        return false;
+
+    return true;
+}
+
 JS_PUBLIC_API(const char*)
 JS_GetImplementationVersion(void)
 {
     return "JavaScript-C" MOZILLA_VERSION;
 }
 
 JS_PUBLIC_API(void)
 JS_SetDestroyCompartmentCallback(JSRuntime* rt, JSDestroyCompartmentCallback callback)
@@ -1049,28 +1050,26 @@ static const JSStdName builtin_property_
     { 0, JSProto_LIMIT }
 };
 
 #undef EAGER_ATOM
 
 JS_PUBLIC_API(bool)
 JS_ResolveStandardClass(JSContext* cx, HandleObject obj, HandleId id, bool* resolved)
 {
-    JSRuntime* rt;
     const JSStdName* stdnm;
 
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, id);
 
     Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>());
     *resolved = false;
 
-    rt = cx->runtime();
-    if (!rt->hasContexts() || !JSID_IS_ATOM(id))
+    if (!JSID_IS_ATOM(id))
         return true;
 
     /* Check whether we're resolving 'undefined', and define it if so. */
     JSAtom* idAtom = JSID_TO_ATOM(id);
     JSAtom* undefinedAtom = cx->names().undefined;
     if (idAtom == undefinedAtom) {
         *resolved = true;
         return DefineProperty(cx, global, id, UndefinedHandleValue, nullptr, nullptr,
@@ -1873,16 +1872,19 @@ JS::CompartmentBehaviorsRef(JSContext* c
     return cx->compartment()->behaviors();
 }
 
 JS_PUBLIC_API(JSObject*)
 JS_NewGlobalObject(JSContext* cx, const JSClass* clasp, JSPrincipals* principals,
                    JS::OnNewGlobalHookOption hookOption,
                    const JS::CompartmentOptions& options)
 {
+    MOZ_RELEASE_ASSERT(cx->runtime()->hasInitializedSelfHosting(),
+                       "Must call JS::InitSelfHostedCode() before creating a global");
+
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
 
     return GlobalObject::new_(cx, Valueify(clasp), principals, hookOption, options);
 }
 
 JS_PUBLIC_API(void)
 JS_GlobalObjectTraceHook(JSTracer* trc, JSObject* global)
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -1036,42 +1036,37 @@ class MOZ_RAII JSAutoRequest
 
 #if 0
   private:
     static void* operator new(size_t) CPP_THROW_NEW { return 0; }
     static void operator delete(void*, size_t) { }
 #endif
 };
 
-extern JS_PUBLIC_API(JSContext*)
-JS_NewContext(JSRuntime* rt, size_t stackChunkSize);
-
-extern JS_PUBLIC_API(void)
-JS_DestroyContext(JSContext* cx);
-
-extern JS_PUBLIC_API(void)
-JS_DestroyContextNoGC(JSContext* cx);
-
 extern JS_PUBLIC_API(void*)
 JS_GetContextPrivate(JSContext* cx);
 
 extern JS_PUBLIC_API(void)
 JS_SetContextPrivate(JSContext* cx, void* data);
 
 extern JS_PUBLIC_API(void*)
 JS_GetSecondContextPrivate(JSContext* cx);
 
 extern JS_PUBLIC_API(void)
 JS_SetSecondContextPrivate(JSContext* cx, void* data);
 
 extern JS_PUBLIC_API(JSRuntime*)
 JS_GetRuntime(JSContext* cx);
 
+/**
+ * Returns the runtime's JSContext. The plan is to expose a single type to the
+ * API, so this function will likely be removed soon.
+ */
 extern JS_PUBLIC_API(JSContext*)
-JS_ContextIterator(JSRuntime* rt, JSContext** iterp);
+JS_GetContext(JSRuntime* rt);
 
 extern JS_PUBLIC_API(JSVersion)
 JS_GetVersion(JSContext* cx);
 
 /**
  * Mutate the version on the compartment. This is generally discouraged, but
  * necessary to support the version mutation in the js and xpc shell command
  * set.
@@ -1248,16 +1243,24 @@ class JS_PUBLIC_API(RuntimeOptions) {
 };
 
 JS_PUBLIC_API(RuntimeOptions&)
 RuntimeOptionsRef(JSRuntime* rt);
 
 JS_PUBLIC_API(RuntimeOptions&)
 RuntimeOptionsRef(JSContext* cx);
 
+/**
+ * Initialize the runtime's self-hosted code. Embeddings should call this
+ * exactly once per runtime/context, before the first JS_NewGlobalObject
+ * call.
+ */
+JS_PUBLIC_API(bool)
+InitSelfHostedCode(JSContext* cx);
+
 } /* namespace JS */
 
 extern JS_PUBLIC_API(const char*)
 JS_GetImplementationVersion(void);
 
 extern JS_PUBLIC_API(void)
 JS_SetDestroyCompartmentCallback(JSRuntime* rt, JSDestroyCompartmentCallback callback);
 
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -83,94 +83,48 @@ js::AutoCycleDetector::~AutoCycleDetecto
 void
 js::TraceCycleDetectionSet(JSTracer* trc, AutoCycleDetector::Set& set)
 {
     for (AutoCycleDetector::Set::Enum e(set); !e.empty(); e.popFront())
         TraceRoot(trc, &e.mutableFront(), "cycle detector table entry");
 }
 
 JSContext*
-js::NewContext(JSRuntime* rt, size_t stackChunkSize)
+js::NewContext(JSRuntime* rt)
 {
+    MOZ_ASSERT(!rt->maybeContextFromMainThread());
+
     JS_AbortIfWrongThread(rt);
 
-    MOZ_RELEASE_ASSERT(!rt->haveCreatedContext,
-                       "There must be at most 1 JSContext per runtime");
-
     JSContext* cx = js_new<JSContext>(rt);
     if (!cx)
         return nullptr;
 
-    if (!cx->cycleDetectorSet.init()) {
-        js_delete(cx);
-        return nullptr;
-    }
-
-    /*
-     * Here the GC lock is still held after js_InitContextThreadAndLockGC took it and
-     * the GC is not running on another thread.
-     */
-    rt->contextList.insertBack(cx);
-
-    /*
-     * If cx is the first context on this runtime, initialize well-known atoms,
-     * keywords, numbers, strings and self-hosted scripts. If one of these
-     * steps should fail, the runtime will be left in a partially initialized
-     * state, with zeroes and nulls stored in the default-initialized remainder
-     * of the struct.
-     */
-    if (!rt->haveCreatedContext) {
-        JS_BeginRequest(cx);
-        bool ok = rt->initializeAtoms(cx);
-        if (ok)
-            ok = rt->initSelfHosting(cx);
-
-        if (ok && !rt->parentRuntime)
-            ok = rt->transformToPermanentAtoms(cx);
-
-        JS_EndRequest(cx);
-
-        if (!ok) {
-            DestroyContext(cx, DCM_NEW_FAILED);
-            return nullptr;
-        }
-
-        rt->haveCreatedContext = true;
-    }
-
     return cx;
 }
 
 void
-js::DestroyContext(JSContext* cx, DestroyContextMode mode)
+js::DestroyContext(JSContext* cx)
 {
     JSRuntime* rt = cx->runtime();
     JS_AbortIfWrongThread(rt);
 
     if (cx->outstandingRequests != 0)
         MOZ_CRASH("Attempted to destroy a context while it is in a request.");
 
     cx->roots.checkNoGCRooters();
     cx->roots.finishPersistentRoots();
 
-    cx->remove();
-    bool last = !rt->hasContexts();
-    if (last) {
-        /*
-         * Dump remaining type inference results while we still have a context.
-         * This printing depends on atoms still existing.
-         */
-        for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next())
-            PrintTypes(cx, c, false);
-    }
-    if (mode == DCM_FORCE_GC) {
-        MOZ_ASSERT(!rt->isHeapBusy());
-        JS::PrepareForFullGC(rt);
-        rt->gc.gc(GC_NORMAL, JS::gcreason::DESTROY_CONTEXT);
-    }
+    /*
+     * Dump remaining type inference results while we still have a context.
+     * This printing depends on atoms still existing.
+     */
+    for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next())
+        PrintTypes(cx, c, false);
+
     js_delete_poison(cx);
 }
 
 void
 RootLists::checkNoGCRooters() {
 #ifdef DEBUG
     for (auto const& stackRootPtr : stackRoots_) {
         MOZ_ASSERT(stackRootPtr == nullptr);
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -290,18 +290,17 @@ class ExclusiveContext : public ContextF
     void addPendingOverRecursed();
     void addPendingOutOfMemory();
 };
 
 void ReportOverRecursed(JSContext* cx, unsigned errorNumber);
 
 } /* namespace js */
 
-struct JSContext : public js::ExclusiveContext,
-                   public mozilla::LinkedListElement<JSContext>
+struct JSContext : public js::ExclusiveContext
 {
     explicit JSContext(JSRuntime* rt);
     ~JSContext();
 
     JSRuntime* runtime() const { return runtime_; }
     js::PerThreadData& mainThread() const { return runtime()->mainThread; }
 
     static size_t offsetOfRuntime() {
@@ -487,65 +486,24 @@ struct MOZ_RAII AutoResolving {
     HandleObject        object;
     HandleId            id;
     Kind                const kind;
     AutoResolving*      const link;
     MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
 };
 
 /*
- * Enumerate all contexts in a runtime.
- */
-class ContextIter
-{
-    JSContext* iter;
-
-  public:
-    explicit ContextIter(JSRuntime* rt) {
-        iter = rt->contextList.getFirst();
-    }
-
-    bool done() const {
-        return !iter;
-    }
-
-    void next() {
-        MOZ_ASSERT(!done());
-        iter = iter->getNext();
-    }
-
-    JSContext* get() const {
-        MOZ_ASSERT(!done());
-        return iter;
-    }
-
-    operator JSContext*() const {
-        return get();
-    }
-
-    JSContext* operator ->() const {
-        return get();
-    }
-};
-
-/*
  * Create and destroy functions for JSContext, which is manually allocated
  * and exclusively owned.
  */
 extern JSContext*
-NewContext(JSRuntime* rt, size_t stackChunkSize);
-
-enum DestroyContextMode {
-    DCM_NO_GC,
-    DCM_FORCE_GC,
-    DCM_NEW_FAILED
-};
+NewContext(JSRuntime* rt);
 
 extern void
-DestroyContext(JSContext* cx, DestroyContextMode mode);
+DestroyContext(JSContext* cx);
 
 enum ErrorArgumentsType {
     ArgumentsAreUnicode,
     ArgumentsAreASCII
 };
 
 /*
  * Loads and returns a self-hosted function by name. For performance, define
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -153,16 +153,17 @@ using JobQueue = GCVector<JSObject*, 0, 
 
 // Per-runtime shell state.
 struct ShellRuntime
 {
     explicit ShellRuntime(JSRuntime* rt);
 
     bool isWorker;
     double timeoutInterval;
+    double startTime;
     Atomic<bool> serviceInterrupt;
     Atomic<bool> haveInterruptFunc;
     JS::PersistentRootedValue interruptFunc;
     bool lastWarningEnabled;
     JS::PersistentRootedValue lastWarning;
 #ifdef SPIDERMONKEY_PROMISE
     JS::PersistentRootedValue promiseRejectionTrackerCallback;
     JS::PersistentRooted<JobQueue> jobQueue;
@@ -237,22 +238,16 @@ static void
 KillWatchdog(JSRuntime *rt);
 
 static bool
 ScheduleWatchdog(JSRuntime* rt, double t);
 
 static void
 CancelExecution(JSRuntime* rt);
 
-static JSContext*
-NewContext(JSRuntime* rt);
-
-static void
-DestroyContext(JSContext* cx, bool withGC);
-
 static JSObject*
 NewGlobalObject(JSContext* cx, JS::CompartmentOptions& options,
                 JSPrincipals* principals);
 
 /*
  * A toy principals type for the shell.
  *
  * In the shell, a principal is simply a 32-bit mask: P subsumes Q if the
@@ -316,16 +311,17 @@ 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)
   : isWorker(false),
     timeoutInterval(-1.0),
+    startTime(PRMJ_Now()),
     serviceInterrupt(false),
     haveInterruptFunc(false),
     interruptFunc(rt, NullValue()),
     lastWarningEnabled(false),
     lastWarning(rt, NullValue()),
 #ifdef SPIDERMONKEY_PROMISE
     promiseRejectionTrackerCallback(rt, NullValue()),
 #endif // SPIDERMONKEY_PROMISE
@@ -413,42 +409,16 @@ GetLine(FILE* file, const char * prompt)
             }
             buffer = tmp;
         }
         current = buffer + len;
     } while (true);
     return nullptr;
 }
 
-/* State to store as JSContext private. */
-struct JSShellContextData {
-    /* Creation timestamp, used by the elapsed() shell builtin. */
-    int64_t startTime;
-};
-
-static JSShellContextData*
-NewContextData()
-{
-    JSShellContextData* data = (JSShellContextData*)
-                               js_calloc(sizeof(JSShellContextData), 1);
-    if (!data)
-        return nullptr;
-    data->startTime = PRMJ_Now();
-    return data;
-}
-
-static inline JSShellContextData*
-GetContextData(JSContext* cx)
-{
-    JSShellContextData* data = (JSShellContextData*) JS_GetContextPrivate(cx);
-
-    MOZ_ASSERT(data);
-    return data;
-}
-
 static bool
 ShellInterruptCallback(JSContext* cx)
 {
     ShellRuntime* sr = GetShellRuntime(cx);
     if (!sr->serviceInterrupt)
         return true;
 
     // Reset serviceInterrupt. CancelExecution or InterruptIf will set it to
@@ -2975,18 +2945,18 @@ WorkerMain(void* arg)
 
     sr->isWorker = true;
     JS_SetRuntimePrivate(rt, sr.get());
     JS_SetFutexCanWait(rt);
     JS::SetWarningReporter(rt, WarningReporter);
     JS_InitDestroyPrincipalsCallback(rt, ShellPrincipals::destroy);
     SetWorkerRuntimeOptions(rt);
 
-    JSContext* cx = NewContext(rt);
-    if (!cx) {
+    JSContext* cx = JS_GetContext(rt);
+    if (!JS::InitSelfHostedCode(cx)) {
         JS_DestroyRuntime(rt);
         js_delete(input);
         return;
     }
 
 #ifdef SPIDERMONKEY_PROMISE
     sr->jobQueue.init(cx, JobQueue(SystemAllocPolicy()));
     JS::SetEnqueuePromiseJobCallback(rt, ShellEnqueuePromiseJobCallback);
@@ -3021,18 +2991,16 @@ WorkerMain(void* arg)
 
     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);
 }
 
 // Workers can spawn other workers, so we need a lock to access workerThreads.
@@ -3517,20 +3485,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 = 0.0;
-        JSShellContextData* data = GetContextData(cx);
-        if (data)
-            d = PRMJ_Now() - data->startTime;
+        double d = PRMJ_Now() - GetShellRuntime(cx)->startTime;
         args.rval().setDouble(d);
         return true;
     }
     JS_ReportError(cx, "Wrong number of arguments");
     return false;
 }
 
 static bool
@@ -5519,17 +5484,17 @@ static const JSFunctionSpecWithHelp shel
 "  Returns an object that represents the last warning."),
 
     JS_FN_HELP("clearLastWarning", ClearLastWarning, 0, 0,
 "clearLastWarning()",
 "  Clear the last warning."),
 
     JS_FN_HELP("elapsed", Elapsed, 0, 0,
 "elapsed()",
-"  Execution time elapsed for the current context."),
+"  Execution time elapsed for the current thread."),
 
     JS_FN_HELP("decompileFunction", DecompileFunction, 1, 0,
 "decompileFunction(func)",
 "  Decompile a function."),
 
     JS_FN_HELP("decompileThis", DecompileThisScript, 0, 0,
 "decompileThis()",
 "  Decompile the currently executing script."),
@@ -6528,45 +6493,16 @@ ShellBuildId(JS::BuildIdCharVector* buil
 
 static const JS::AsmJSCacheOps asmJSCacheOps = {
     ShellOpenAsmJSCacheEntryForRead,
     ShellCloseAsmJSCacheEntryForRead,
     ShellOpenAsmJSCacheEntryForWrite,
     ShellCloseAsmJSCacheEntryForWrite
 };
 
-static JSContext*
-NewContext(JSRuntime* rt)
-{
-    JSContext* cx = JS_NewContext(rt, gStackChunkSize);
-    if (!cx)
-        return nullptr;
-
-    JSShellContextData* data = NewContextData();
-    if (!data) {
-        DestroyContext(cx, false);
-        return nullptr;
-    }
-
-    JS_SetContextPrivate(cx, data);
-    return cx;
-}
-
-static void
-DestroyContext(JSContext* cx, bool withGC)
-{
-    // Don't use GetContextData as |data| could be a nullptr in the case of
-    // destroying a context precisely because we couldn't create its private
-    // data.
-    JSShellContextData* data = (JSShellContextData*) JS_GetContextPrivate(cx);
-    JS_SetContextPrivate(cx, nullptr);
-    js_free(data);
-    withGC ? JS_DestroyContext(cx) : JS_DestroyContextNoGC(cx);
-}
-
 static JSObject*
 NewGlobalObject(JSContext* cx, JS::CompartmentOptions& options,
                 JSPrincipals* principals)
 {
     RootedObject glob(cx, JS_NewGlobalObject(cx, &global_class, principals,
                                              JS::DontFireOnNewGlobalHook, options));
     if (!glob)
         return nullptr;
@@ -7178,18 +7114,16 @@ PreInit()
 int
 main(int argc, char** argv, char** envp)
 {
     PreInit();
 
     sArgc = argc;
     sArgv = argv;
 
-    JSRuntime* rt;
-    JSContext* cx;
     int result;
 
 #ifdef HAVE_SETLOCALE
     setlocale(LC_ALL, "");
 #endif
 
     // Special-case stdout and stderr. We bump their refcounts to prevent them
     // from getting closed and then having some printf fail somewhere.
@@ -7433,17 +7367,17 @@ main(int argc, char** argv, char** envp)
     int32_t threadCount = op.getIntOption("thread-count");
     if (threadCount >= 0)
         SetFakeCPUCount(threadCount);
 
     size_t nurseryBytes = JS::DefaultNurseryBytes;
     nurseryBytes = op.getIntOption("nursery-size") * 1024L * 1024L;
 
     /* Use the same parameters as the browser in xpcjsruntime.cpp. */
-    rt = JS_NewRuntime(JS::DefaultHeapMaxBytes, nurseryBytes);
+    JSRuntime* rt = JS_NewRuntime(JS::DefaultHeapMaxBytes, nurseryBytes);
     if (!rt)
         return 1;
 
     UniquePtr<ShellRuntime> sr = MakeUnique<ShellRuntime>(rt);
     if (!sr)
         return 1;
 
     JS_SetRuntimePrivate(rt, sr.get());
@@ -7469,18 +7403,18 @@ main(int argc, char** argv, char** envp)
 
     JS_SetNativeStackQuota(rt, gMaxStackSize);
 
     JS::dbg::SetDebuggerMallocSizeOf(rt, moz_malloc_size_of);
 
     if (!offThreadState.init())
         return 1;
 
-    cx = NewContext(rt);
-    if (!cx)
+    JSContext* cx = JS_GetContext(rt);
+    if (!JS::InitSelfHostedCode(cx))
         return 1;
 
 #ifdef SPIDERMONKEY_PROMISE
     sr->jobQueue.init(cx, JobQueue(SystemAllocPolicy()));
     JS::SetEnqueuePromiseJobCallback(rt, ShellEnqueuePromiseJobCallback);
 #endif // SPIDERMONKEY_PROMISE
 
     EnvironmentPreparer environmentPreparer(cx);
@@ -7511,18 +7445,16 @@ main(int argc, char** argv, char** envp)
 
     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();
 
     JS_DestroyRuntime(rt);
     JS_ShutDown();
--- a/js/src/vm/Runtime.cpp
+++ b/js/src/vm/Runtime.cpp
@@ -167,16 +167,17 @@ JSRuntime::JSRuntime(JSRuntime* parentRu
     numExclusiveThreads(0),
     numCompartments(0),
     localeCallbacks(nullptr),
     defaultLocale(nullptr),
     defaultVersion_(JSVERSION_DEFAULT),
     ownerThread_(nullptr),
     ownerThreadNative_(0),
     tempLifoAlloc(TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE),
+    context_(nullptr),
     jitRuntime_(nullptr),
     selfHostingGlobal_(nullptr),
     nativeStackBase(GetNativeStackBase()),
     destroyCompartmentCallback(nullptr),
     sizeOfIncludingThisCompartmentCallback(nullptr),
     destroyZoneCallback(nullptr),
     sweepZoneCallback(nullptr),
     compartmentNameCallback(nullptr),
@@ -200,17 +201,16 @@ JSRuntime::JSRuntime(JSRuntime* parentRu
     emptyString(nullptr),
     spsProfiler(thisFromCtor()),
     profilingScripts(false),
     suppressProfilerSampling(false),
     hadOutOfMemory(false),
 #ifdef DEBUG
     handlingInitFailure(false),
 #endif
-    haveCreatedContext(false),
     allowRelazificationForTesting(false),
     data(nullptr),
     signalHandlersInstalled_(false),
     canUseSignalHandlers_(false),
     defaultFreeOp_(thisFromCtor()),
     debuggerMutations(0),
     securityCallbacks(&NullSecurityCallbacks),
     DOMcallbacks(nullptr),
@@ -364,21 +364,30 @@ JSRuntime::init(uint32_t maxbytes, uint3
         return false;
 
     if (!parentRuntime) {
         sharedImmutableStrings_ = js::SharedImmutableStringsCache::Create();
         if (!sharedImmutableStrings_)
             return false;
     }
 
+    context_ = NewContext(this);
+    if (!context_)
+        return false;
+
     return true;
 }
 
 JSRuntime::~JSRuntime()
 {
+    if (context_) {
+        DestroyContext(context_);
+        context_ = nullptr;
+    }
+
     MOZ_ASSERT(!isHeapBusy());
     MOZ_ASSERT(childRuntimeCount == 0);
 
     fx.destroyInstance();
 
     if (gcInitialized) {
         /* Free source hook early, as its destructor may want to delete roots. */
         sourceHook = nullptr;
@@ -440,32 +449,16 @@ JSRuntime::~JSRuntime()
     AutoLockForExclusiveAccess lock(this);
 
     /*
      * Even though all objects in the compartment are dead, we may have keep
      * some filenames around because of gcKeepAtoms.
      */
     FreeScriptData(this, lock);
 
-#ifdef DEBUG
-    /* Don't hurt everyone in leaky ol' Mozilla with a fatal MOZ_ASSERT! */
-    if (hasContexts()) {
-        unsigned cxcount = 0;
-        for (ContextIter acx(this); !acx.done(); acx.next()) {
-            fprintf(stderr,
-"JS API usage error: found live context at %p\n",
-                    (void*) acx.get());
-            cxcount++;
-        }
-        fprintf(stderr,
-"JS API usage error: %u context%s left in runtime upon JS_DestroyRuntime.\n",
-                cxcount, (cxcount == 1) ? "" : "s");
-    }
-#endif
-
 #if !EXPOSE_INTL_API
     FinishRuntimeNumberState(this);
 #endif
 
     gc.finish();
     atomsCompartment_ = nullptr;
 
     js_free(defaultLocale);
@@ -531,18 +524,17 @@ JSRuntime::addSizeOfIncludingThis(mozill
     rtSizes->atomsTable += atoms(lock).sizeOfIncludingThis(mallocSizeOf);
 
     if (!parentRuntime) {
         rtSizes->atomsTable += mallocSizeOf(staticStrings);
         rtSizes->atomsTable += mallocSizeOf(commonNames);
         rtSizes->atomsTable += permanentAtoms->sizeOfIncludingThis(mallocSizeOf);
     }
 
-    for (ContextIter acx(this); !acx.done(); acx.next())
-        rtSizes->contexts += acx->sizeOfIncludingThis(mallocSizeOf);
+    rtSizes->contexts += context_->sizeOfIncludingThis(mallocSizeOf);
 
     rtSizes->temporary += tempLifoAlloc.sizeOfExcludingThis(mallocSizeOf);
 
     rtSizes->interpreterStack += interpreterStack_.sizeOfExcludingThis(mallocSizeOf);
 
     rtSizes->mathCache += mathCache_ ? mathCache_->sizeOfIncludingThis(mallocSizeOf) : 0;
 
     if (sharedImmutableStrings_) {
--- a/js/src/vm/Runtime.h
+++ b/js/src/vm/Runtime.h
@@ -1013,16 +1013,18 @@ struct JSRuntime : public JS::shadow::Ru
         return ownerThreadNative_;
     }
 
     /* Temporary arena pool used while compiling and decompiling. */
     static const size_t TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE = 4 * 1024;
     js::LifoAlloc tempLifoAlloc;
 
   private:
+    JSContext* context_;
+
     js::jit::JitRuntime* jitRuntime_;
 
     /*
      * Self-hosting state cloned on demand into other compartments. Shared with the parent
      * runtime if there is one.
      */
     js::NativeObject* selfHostingGlobal_;
 
@@ -1047,24 +1049,40 @@ struct JSRuntime : public JS::shadow::Ru
     }
     bool hasJitRuntime() const {
         return !!jitRuntime_;
     }
     js::InterpreterStack& interpreterStack() {
         return interpreterStack_;
     }
 
+    // The runtime's context can be nullptr only while we're initializing or
+    // destroying the runtime.
+    JSContext* maybeContextFromMainThread() {
+        MOZ_ASSERT(CurrentThreadCanAccessRuntime(this));
+        return context_;
+    }
+    JSContext* contextFromMainThread() {
+        JSContext* cx = maybeContextFromMainThread();
+        MOZ_ASSERT(cx);
+        return cx;
+    }
+
     bool enqueuePromiseJob(JSContext* cx, js::HandleFunction job, js::HandleObject promise);
     void addUnhandledRejectedPromise(JSContext* cx, js::HandleObject promise);
     void removeUnhandledRejectedPromise(JSContext* cx, js::HandleObject promise);
 
     //-------------------------------------------------------------------------
     // Self-hosting support
     //-------------------------------------------------------------------------
 
+    bool hasInitializedSelfHosting() const {
+        return selfHostingGlobal_;
+    }
+
     bool initSelfHosting(JSContext* cx);
     void finishSelfHosting();
     void markSelfHostingGlobal(JSTracer* trc);
     bool isSelfHostingGlobal(JSObject* global) {
         return global == selfHostingGlobal_;
     }
     bool isSelfHostingCompartment(JSCompartment* comp) const;
     bool isSelfHostingZone(const JS::Zone* zone) const;
@@ -1169,30 +1187,23 @@ struct JSRuntime : public JS::shadow::Ru
 #endif
 
     /* Strong references on scripts held for PCCount profiling API. */
     JS::PersistentRooted<js::ScriptAndCountsVector>* scriptAndCountsVector;
 
     /* Code coverage output. */
     js::coverage::LCovRuntime lcovOutput;
 
-    /* Well-known numbers held for use by this runtime's contexts. */
+    /* Well-known numbers. */
     const js::Value     NaNValue;
     const js::Value     negativeInfinityValue;
     const js::Value     positiveInfinityValue;
 
     js::PropertyName*   emptyString;
 
-    /* List of active contexts sharing this runtime. */
-    mozilla::LinkedList<JSContext> contextList;
-
-    bool hasContexts() const {
-        return !contextList.isEmpty();
-    }
-
     mozilla::UniquePtr<js::SourceHook> sourceHook;
 
     /* SPS profiling metadata */
     js::SPSProfiler     spsProfiler;
 
     /* If true, new scripts must be created with PC counter information. */
     bool                profilingScripts;
 
@@ -1214,19 +1225,16 @@ struct JSRuntime : public JS::shadow::Ru
     /* Had an out-of-memory error which did not populate an exception. */
     bool                hadOutOfMemory;
 
 #ifdef DEBUG
     /* We are currently deleting an object due to an initialization failure. */
     bool handlingInitFailure;
 #endif
 
-    /* A context has been created on this runtime. */
-    bool                haveCreatedContext;
-
     /*
      * Allow relazifying functions in compartments that are active. This is
      * only used by the relazifyFunctions() testing function.
      */
     bool                allowRelazificationForTesting;
 
     /* Linked list of all Debugger objects in the runtime. */
     mozilla::LinkedList<js::Debugger> debuggerList;
--- a/js/xpconnect/src/XPCComponents.cpp
+++ b/js/xpconnect/src/XPCComponents.cpp
@@ -2625,23 +2625,19 @@ class PreciseGCRunnable : public Runnabl
   public:
     PreciseGCRunnable(ScheduledGCCallback* aCallback, bool aShrinking)
     : mCallback(aCallback), mShrinking(aShrinking) {}
 
     NS_IMETHOD Run()
     {
         JSRuntime* rt = nsXPConnect::GetRuntimeInstance()->Runtime();
 
-        JSContext* cx;
-        JSContext* iter = nullptr;
-        while ((cx = JS_ContextIterator(rt, &iter)) != nullptr) {
-            if (JS_IsRunning(cx)) {
-                return NS_DispatchToMainThread(this);
-            }
-        }
+        JSContext* cx = JS_GetContext(rt);
+        if (JS_IsRunning(cx))
+            return NS_DispatchToMainThread(this);
 
         nsJSContext::GarbageCollectNow(gcreason::COMPONENT_UTILS,
                                        nsJSContext::NonIncrementalGC,
                                        mShrinking ?
                                          nsJSContext::ShrinkingGC :
                                          nsJSContext::NonShrinkingGC);
 
         mCallback->Callback();
--- a/js/xpconnect/src/XPCJSContextStack.cpp
+++ b/js/xpconnect/src/XPCJSContextStack.cpp
@@ -18,17 +18,16 @@ using namespace xpc;
 using mozilla::dom::DestroyProtoAndIfaceCache;
 
 /***************************************************************************/
 
 XPCJSContextStack::~XPCJSContextStack()
 {
     if (mSafeJSContext) {
         delete XPCContext::GetXPCContext(mSafeJSContext);
-        JS_DestroyContextNoGC(mSafeJSContext);
         mSafeJSContext = nullptr;
     }
 }
 
 void
 XPCJSContextStack::Pop()
 {
     MOZ_ASSERT(!mStack.IsEmpty());
@@ -60,14 +59,15 @@ XPCJSContextStack::GetSafeJSContext()
     return mSafeJSContext;
 }
 
 void
 XPCJSContextStack::InitSafeJSContext()
 {
     MOZ_ASSERT(!mSafeJSContext);
 
-    mSafeJSContext = JS_NewContext(XPCJSRuntime::Get()->Runtime(), 8192);
-    MOZ_RELEASE_ASSERT(mSafeJSContext, "JS_NewContext failed");
+    mSafeJSContext = JS_GetContext(mRuntime->Runtime());
+    if (!JS::InitSelfHostedCode(mSafeJSContext))
+        MOZ_CRASH("InitSelfHostedCode failed");
 
     if (!mRuntime->InitXPCContext(mSafeJSContext))
         MOZ_CRASH("InitXPCContext failed");
 }
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -3785,29 +3785,21 @@ void
 XPCJSRuntime::DebugDump(int16_t depth)
 {
 #ifdef DEBUG
     depth--;
     XPC_LOG_ALWAYS(("XPCJSRuntime @ %x", this));
         XPC_LOG_INDENT();
         XPC_LOG_ALWAYS(("mJSRuntime @ %x", Runtime()));
 
-        int cxCount = 0;
-        JSContext* iter = nullptr;
-        while (JS_ContextIterator(Runtime(), &iter))
-            ++cxCount;
-        XPC_LOG_ALWAYS(("%d JS context(s)", cxCount));
-
-        iter = nullptr;
-        while (JS_ContextIterator(Runtime(), &iter)) {
-            XPCContext* xpc = XPCContext::GetXPCContext(iter);
-            XPC_LOG_INDENT();
-            xpc->DebugDump(depth);
-            XPC_LOG_OUTDENT();
-        }
+        JSContext* cx = JS_GetContext(Runtime());
+        XPCContext* xpc = XPCContext::GetXPCContext(cx);
+        XPC_LOG_INDENT();
+        xpc->DebugDump(depth);
+        XPC_LOG_OUTDENT();
 
         XPC_LOG_ALWAYS(("mWrappedJSClassMap @ %x with %d wrapperclasses(s)",
                         mWrappedJSClassMap, mWrappedJSClassMap->Count()));
         // iterate wrappersclasses...
         if (depth && mWrappedJSClassMap->Count()) {
             XPC_LOG_INDENT();
             for (auto i = mWrappedJSClassMap->Iter(); !i.Done(); i.Next()) {
                 auto entry = static_cast<IID2WrappedJSClassMap::Entry*>(i.Get());
--- a/netwerk/base/ProxyAutoConfig.cpp
+++ b/netwerk/base/ProxyAutoConfig.cpp
@@ -634,19 +634,16 @@ class JSRuntimeWrapper
     return mGlobal;
   }
 
   ~JSRuntimeWrapper()
   {
     mGlobal = nullptr;
 
     MOZ_COUNT_DTOR(JSRuntimeWrapper);
-    if (mContext) {
-      JS_DestroyContext(mContext);
-    }
 
     if (mRuntime) {
       JS_DestroyRuntime(mRuntime);
     }
   }
 
   void SetOK()
   {
@@ -679,18 +676,20 @@ private:
     /*
      * Not setting this will cause JS_CHECK_RECURSION to report false
      * positives
      */
     JS_SetNativeStackQuota(mRuntime, 128 * sizeof(size_t) * 1024);
 
     JS::SetWarningReporter(mRuntime, PACWarningReporter);
 
-    mContext = JS_NewContext(mRuntime, 0);
-    NS_ENSURE_TRUE(mContext, NS_ERROR_OUT_OF_MEMORY);
+    mContext = JS_GetContext(mRuntime);
+    if (!JS::InitSelfHostedCode(mContext)) {
+      return NS_ERROR_OUT_OF_MEMORY;
+    }
 
     JSAutoRequest ar(mContext);
 
     JS::CompartmentOptions options;
     options.creationOptions().setZone(JS::SystemZone);
     options.behaviors().setVersion(JSVERSION_LATEST);
     mGlobal = JS_NewGlobalObject(mContext, &sGlobalClass, nullptr,
                                  JS::DontFireOnNewGlobalHook, options);
--- a/xpcom/glue/tests/gtest/TestGCPostBarriers.cpp
+++ b/xpcom/glue/tests/gtest/TestGCPostBarriers.cpp
@@ -127,17 +127,16 @@ CreateGlobalAndRunTest(JSRuntime* rt, JS
 }
 
 TEST(GCPostBarriers, nsTArray) {
   CycleCollectedJSRuntime* ccrt = CycleCollectedJSRuntime::Get();
   ASSERT_TRUE(ccrt != nullptr);
   JSRuntime* rt = ccrt->Runtime();
   ASSERT_TRUE(rt != nullptr);
 
-  JSContext* cx = nullptr;
-  MOZ_RELEASE_ASSERT(JS_ContextIterator(rt, &cx));
+  JSContext* cx = JS_GetContext(rt);
 
   JS_BeginRequest(cx);
 
   CreateGlobalAndRunTest(rt, cx);
 
   JS_EndRequest(cx);
 }