Factor out the GC rooters into per-thread state.
authorNicholas D. Matsakis <nmatsakis@mozilla.com>
Thu, 01 Nov 2012 15:02:05 -0700
changeset 112020 a5efa31bdc18
parent 112019 81a8c5b7fd9f
child 112021 35b68eb3abd1
push id94
push usernmatsakis@mozilla.com
push dateThu, 01 Nov 2012 22:10:18 +0000
milestone19.0a1
Factor out the GC rooters into per-thread state.
js/src/builtin/ParallelArray.cpp
js/src/gc/Root.h
js/src/jscntxt.h
js/src/jsgc.cpp
js/src/jsmonitor.h
js/src/jspubtd.h
js/src/jstaskset.cpp
js/src/jstaskset.h
js/src/jsthreadpool.cpp
js/src/jsthreadpool.h
js/src/jsthreadpoolinlines.h
--- a/js/src/builtin/ParallelArray.cpp
+++ b/js/src/builtin/ParallelArray.cpp
@@ -646,23 +646,25 @@ ParallelArrayObject::ParallelArrayTaskSe
     return opDefn_.pre(numThreads);
 }
 
 template<typename OpDefn, uint32_t MaxArgc>
 bool
 ParallelArrayObject::ParallelArrayTaskSet<OpDefn, MaxArgc>::parallel(
     ThreadContext &threadCx)
 {
+    JS::PerThreadData *pt = threadCx.perThreadData;
+
     // compute number of arguments
     const uint32_t argc = opDefn_.argc();
     JS_ASSERT(argc <= MaxArgc); // other compilation should have failed
     Value actualArgv[MaxArgc + 1], *argv = actualArgv + 1;
 
     // Set 'callee' and 'this'.
-    RootedFunction callee(cx_, elementalFun_->toFunction());
+    RootedFunction callee(pt, elementalFun_->toFunction());
     argv[-1] = ObjectValue(*callee);
     argv[0] = UndefinedValue();
 
     // find jitcode ptr
     IonScript *ion = callee->script()->ionScript(COMPILE_MODE_PAR);
     IonCode *code = ion->method();
     void *jitcode = code->raw();
     EnterIonCode enter = cx_->compartment->ionCompartment()->enterJITInfallible();
@@ -1534,16 +1536,17 @@ ParallelArrayObject::MapOp::MapOp(MapOpD
 
 bool
 ParallelArrayObject::MapOp::init() {
     return true;
 }
 
 bool
 ParallelArrayObject::MapOp::initializeArgv(Value *argv, unsigned i) {
+    // XXX should not use cx
     if (!getParallelArrayElement(opDefn_.cx, source, i, &elem))
         return false;
 
     // Arguments are in eic(h) order.
     argv[1] = elem;
     argv[2] = Int32Value(i);
     argv[3] = ObjectValue(*source);
     return true;
@@ -1653,22 +1656,23 @@ ParallelArrayObject::ReduceOp::execute(E
 
     // ReduceOpDefn::pre() ensures that there is at least one element
     // for each thread to process:
     JS_ASSERT(end - start > 1);
 
     // NB---I am not 100% comfortable with using RootedValue here, but
     // there doesn't seem to be an easy alternative.
 
+    PerThreadData *pt = args.threadCx.perThreadData;
     HandleParallelArrayObject source = opDefn_.source;
-    RootedValue acc(opDefn_.cx);
+    RootedValue acc(pt);
     if (!getParallelArrayElement(opDefn_.cx, source, start, &acc))
         return false;
 
-    RootedValue elem(opDefn_.cx);
+    RootedValue elem(pt);
     for (unsigned i = start + 1; i < end; i++) {
         if (!args.threadCx.check())
             return false;
 
         if (!getParallelArrayElement(opDefn_.cx, source, i, &elem))
             return false;
 
         args.argv[1] = acc;
@@ -1803,17 +1807,17 @@ ParallelArrayObject::FilterCopyTaskSet::
         count += counts_[i];
 
     unsigned length, start, end;
     length = source_->outermostDimension();
     ComputeTileBounds(threadCx, length, &start, &end);
     for (unsigned i = start; i < end; i++) {
         Value felem = filter_->getDenseArrayElement(i + filterBase_);
         if (ToBoolean(felem)) {
-            RootedValue elem(cx_); // FIXME
+            RootedValue elem(threadCx.perThreadData);
             if (!getParallelArrayElement(cx_, source_, i, &elem))
                 return false;
             resultBuffer_->setDenseArrayElement(count++, elem);
         }
     }
     return true;
 }
 
--- a/js/src/gc/Root.h
+++ b/js/src/gc/Root.h
@@ -511,37 +511,35 @@ class RootedBase {};
  */
 template <typename T>
 class Rooted : public RootedBase<T>
 {
     void init(JSContext *cxArg)
     {
 #if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)
         ContextFriendFields *cx = ContextFriendFields::get(cxArg);
-
-        ThingRootKind kind = RootMethods<T>::kind();
-        this->stack = reinterpret_cast<Rooted<T>**>(&cx->thingGCRooters[kind]);
-        this->prev = *stack;
-        *stack = this;
-
-        JS_ASSERT(!RootMethods<T>::poisoned(ptr));
+        commonInit(cx->thingGCRooters);
 #endif
     }
 
     void init(JSRuntime *rtArg)
     {
 #if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)
-        RuntimeFriendFields *rt = const_cast<RuntimeFriendFields *>(RuntimeFriendFields::get(rtArg));
+        RuntimeFriendFields *rt =
+          const_cast<RuntimeFriendFields *>(RuntimeFriendFields::get(rtArg));
+        commonInit(rt->thingGCRooters);
+#endif
+    }
 
-        ThingRootKind kind = RootMethods<T>::kind();
-        this->stack = reinterpret_cast<Rooted<T>**>(&rt->thingGCRooters[kind]);
-        this->prev = *stack;
-        *stack = this;
-
-        JS_ASSERT(!RootMethods<T>::poisoned(ptr));
+    void init(JS::PerThreadData *ptArg)
+    {
+#if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)
+        PerThreadDataFriendFields *pt =
+          const_cast<PerThreadDataFriendFields *>(PerThreadDataFriendFields::get(ptArg));
+        commonInit(pt->thingGCRooters);
 #endif
     }
 
   public:
     Rooted(JSRuntime *rt
            MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
       : ptr(RootMethods<T>::initial())
     {
@@ -568,25 +566,50 @@ class Rooted : public RootedBase<T>
     Rooted(JSContext *cx, T initial
            MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
       : ptr(initial)
     {
         MOZ_GUARD_OBJECT_NOTIFIER_INIT;
         init(cx);
     }
 
+    Rooted(JS::PerThreadData *pt
+           MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
+      : ptr(RootMethods<T>::initial())
+    {
+        MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+        init(pt);
+    }
+
+    Rooted(JS::PerThreadData *pt, T initial
+           MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
+      : ptr(initial)
+    {
+        MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+        init(pt);
+    }
+
     template <typename S>
     Rooted(JSContext *cx, const Return<S> &initial
            MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
       : ptr(initial.ptr_)
     {
         MOZ_GUARD_OBJECT_NOTIFIER_INIT;
         init(cx);
     }
 
+    template <typename S>
+    Rooted(JS::PerThreadData *pt, const Return<S> &initial
+           MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
+      : ptr(initial.ptr_)
+    {
+        MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+        init(pt);
+    }
+
     ~Rooted()
     {
 #if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)
         JS_ASSERT(*stack == this);
         *stack = prev;
 #endif
     }
 
@@ -617,16 +640,27 @@ class Rooted : public RootedBase<T>
     template <typename S>
     T & operator =(const Return<S> &value)
     {
         ptr = value.ptr_;
         return ptr;
     }
 
   private:
+    void commonInit(Rooted<void*> **thingGCRooters) {
+#if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)
+        ThingRootKind kind = RootMethods<T>::kind();
+        this->stack = reinterpret_cast<Rooted<T>**>(&thingGCRooters[kind]);
+        this->prev = *stack;
+        *stack = this;
+
+        JS_ASSERT(!RootMethods<T>::poisoned(ptr));
+#endif
+    }
+
 #if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)
     Rooted<T> **stack, *prev;
 #endif
     T ptr;
     MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
 
     Rooted(const Rooted &) MOZ_DELETE;
 };
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -387,17 +387,17 @@ struct JSAtomState
     JS_FOR_EACH_PROTOTYPE(PROPERTYNAME_FIELD)
 #undef PROPERTYNAME_FIELD
 };
 
 #define NAME_OFFSET(name)       offsetof(JSAtomState, name)
 #define OFFSET_TO_NAME(rt,off)  (*(js::FixedHeapPtr<js::PropertyName>*)((char*)&(rt)->atomState + (off)))
 
 namespace JS {
-struct PerThreadData
+struct PerThreadData : public js::PerThreadDataFriendFields
 {
     JSRuntime *runtime; // backpointer to the full shraed runtime
 
     /*
      * We save all conservative scanned roots in this vector so that
      * conservative scanning can be "replayed" deterministically. In DEBUG mode,
      * this allows us to run a non-incremental GC after every incremental GC to
      * ensure that no objects were missed.
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -996,16 +996,17 @@ MarkExactStackRooters(JSTracer *trc, Roo
 
 static void
 MarkExactStackRoots(JSTracer *trc)
 {
     for (unsigned i = 0; i < THING_ROOT_LIMIT; i++) {
         for (ContextIter cx(trc->runtime); !cx.done(); cx.next()) {
             MarkExactStackRooters(trc, cx->thingGCRooters[i], ThingRootKind(i));
         }
+        MarkExactStackRooters(trc, rt->mainThread.thingGCRooters[i], ThingRootKind(i));
         MarkExactStackRooters(trc, rt->thingGCRooters[i], ThingRootKind(i));
     }
 }
 #endif /* JSGC_USE_EXACT_ROOTING */
 
 enum ConservativeGCTest
 {
     CGCT_VALID,
@@ -4932,16 +4933,18 @@ CheckStackRoot(JSTracer *trc, uintptr_t 
 
     ConservativeGCTest test = MarkIfGCThingWord(trc, *w);
 
     if (test == CGCT_VALID) {
         bool matched = false;
         JSRuntime *rt = trc->runtime;
         for (unsigned i = 0; i < THING_ROOT_LIMIT; i++) {
             CheckStackRootThings(w, rt->thingGCRooters[i], ThingRootKind(i), &matched);
+            CheckStackRootThings(w, rt->mainThread.thingGCRooters[i],
+                                 ThingRootKind(i), &matched);
             for (ContextIter cx(rt); !cx.done(); cx.next()) {
                 CheckStackRootThings(w, cx->thingGCRooters[i], ThingRootKind(i), &matched);
                 SkipRoot *skip = cx->skipGCRooters;
                 while (skip) {
                     if (skip->contains(reinterpret_cast<uint8_t*>(w), sizeof(w)))
                         matched = true;
                     skip = skip->previous();
                 }
--- a/js/src/jsmonitor.h
+++ b/js/src/jsmonitor.h
@@ -11,22 +11,16 @@
 #include <stdlib.h>
 #include "mozilla/Util.h"
 #include "js/Utility.h"
 #include "prlock.h"
 #include "prcvar.h"
 
 namespace js {
 
-#ifndef JS_THREADSAFE
-
-class Monitor {};
-
-#else
-
 /*
  * A base class used for types intended to be used in a parallel
  * fashion, such as the workers in the |ThreadPool| class.  Combines a
  * lock and a condition variable.  You can acquire the lock or signal
  * the condition variable using the |AutoLockMonitor| type.
  */
 class Monitor
 {
@@ -78,13 +72,11 @@ class AutoUnlockMonitor
   private:
     Monitor &monitor;
 
   public:
     AutoUnlockMonitor(Monitor &monitor) : monitor(monitor) { PR_Unlock(monitor.lock_); }
     ~AutoUnlockMonitor() { PR_Lock(monitor.lock_); }
 };
 
-#endif /* def JS_THREADSAFE */
-
 }
 
 #endif /* ndef jsmonitor_h___ */
--- a/js/src/jspubtd.h
+++ b/js/src/jspubtd.h
@@ -14,17 +14,17 @@
 #include "jsprototypes.h"
 #include "jstypes.h"
 
 /*
  * Allow headers to reference JS::Value without #including the whole jsapi.h.
  * Unfortunately, typedefs (hence jsval) cannot be declared.
  */
 #ifdef __cplusplus
-namespace JS { class Value; }
+namespace JS { class Value; struct PerThreadData; }
 #endif
 
 /*
  * In release builds, jsid is defined to be an integral type. This
  * prevents many bugs from being caught at compile time. E.g.:
  *
  *  jsid id = ...
  *  if (id == JS_TRUE)  // error
@@ -309,26 +309,45 @@ struct RuntimeFriendFields {
 
     /* Limit pointer for checking native stack consumption. */
     uintptr_t           nativeStackLimit;
 
 #if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)
     /*
      * Stack allocated GC roots for stack GC heap pointers, which may be
      * overwritten if moved during a GC.
+     *
+     * The actual set of roots is split between the |JSContext*|, the
+     * |JSRuntime*|, and any active |JS::PerThread| data.  This is purely
+     * for efficiency.  A given |Rooted<T>| pointer is associated with
+     * precisely one of those.
      */
     Rooted<void*> *thingGCRooters[THING_ROOT_LIMIT];
 #endif
 
     RuntimeFriendFields()
       : interrupt(0),
         nativeStackLimit(0) { }
 
     static const RuntimeFriendFields *get(const JSRuntime *rt) {
         return reinterpret_cast<const RuntimeFriendFields *>(rt);
     }
 };
 
+struct PerThreadDataFriendFields {
+#if defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING)
+    /*
+     * Stack allocated GC roots for stack GC heap pointers, which may be
+     * overwritten if moved during a GC.
+     */
+    Rooted<void*> *thingGCRooters[THING_ROOT_LIMIT];
+#endif
+
+    static const PerThreadDataFriendFields *get(const JS::PerThreadData *pt) {
+        return reinterpret_cast<const PerThreadDataFriendFields *>(pt);
+    }
+};
+
 } /* namespace js */
 
 #endif /* __cplusplus */
 
 #endif /* jspubtd_h___ */
--- a/js/src/jstaskset.cpp
+++ b/js/src/jstaskset.cpp
@@ -4,16 +4,17 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "jstaskset.h"
 #include "jsmonitor.h"
 #include "jscntxt.h"
 #include "jscompartment.h"
+#include "prthread.h"
 
 namespace js {
 
 class TaskSetSharedContext
     : public TaskExecutor,
       public Monitor
 {
     ////////////////////////////////////////////////////////////////////////
@@ -60,17 +61,17 @@ class TaskSetSharedContext
     // be *read* without the lock.
     volatile bool rendezvous_;
 
     // Invoked only from the main thread:
     void executeFromMainThread(uintptr_t stackLimit);
 
     // Executes slice #threadId of the work, either from a worker or
     // the main thread.
-    void executePortion(size_t threadId, uintptr_t stackLimit);
+    void executePortion(JS::PerThreadData *perThread, size_t threadId, uintptr_t stackLimit);
 
     // Rendezvous protocol:
     //
     // Use AutoRendezvous rather than invoking initiateRendezvous()
     // and endRendezvous() directly.
 
     friend class AutoRendezvous;
 
@@ -285,40 +286,43 @@ TaskSetSharedContext::transferArenasToCo
 
 void
 TaskSetSharedContext::executeFromWorker(size_t workerId, uintptr_t stackLimit)
 {
     JS_ASSERT(workerId < numThreads_ - 1);
 
     JS::PerThreadData thisThread(cx_->runtime);
     JS::TlsPerThreadData.set(&thisThread);
-    executePortion(workerId, stackLimit);
+    executePortion(&thisThread, workerId, stackLimit);
     JS::TlsPerThreadData.set(NULL);
 
     AutoLockMonitor lock(*this);
     uncompleted_ -= 1;
     if (blocked_ == uncompleted_) {
         // Signal the main thread that we have terminated.  It will be
         // either working, arranging a rendezvous, or waiting for
         // workers to complete.
         lock.notify();
     }
 }
 
 void
 TaskSetSharedContext::executeFromMainThread(uintptr_t stackLimit)
 {
-    executePortion(numThreads_ - 1, stackLimit);
+    executePortion(&cx_->runtime->mainThread, numThreads_ - 1, stackLimit);
 }
 
 void
-TaskSetSharedContext::executePortion(size_t threadId, uintptr_t stackLimit)
+TaskSetSharedContext::executePortion(JS::PerThreadData *perThread,
+                                     size_t threadId,
+                                     uintptr_t stackLimit)
 {
     gc::ArenaLists *arenaLists = arenaListss_[threadId];
-    ThreadContext threadCx(threadId, numThreads_, stackLimit, arenaLists, this);
+    ThreadContext threadCx(perThread, threadId, numThreads_,
+                           stackLimit, arenaLists, this);
     AutoSetThreadContext autoContext(&threadCx);
 
     if (!taskSet_.parallel(threadCx))
         abort_ = true;
 }
 
 bool
 TaskSetSharedContext::setFatal()
@@ -440,20 +444,22 @@ TaskSetSharedContext::endRendezvous(Thre
     // signal other threads that rendezvous is over
     PR_NotifyAllCondVar(rendezvousEnd_);
 }
 
 /****************************************************************************
  * ThreadContext
  */
 
-ThreadContext::ThreadContext(size_t threadId, size_t numThreads,
+ThreadContext::ThreadContext(JS::PerThreadData *perThreadData,
+                             size_t threadId, size_t numThreads,
                              uintptr_t stackLimit, js::gc::ArenaLists *arenaLists,
                              TaskSetSharedContext *shared)
-    : threadId(threadId),
+    : perThreadData(perThreadData),
+      threadId(threadId),
       numThreads(numThreads),
       ionStackLimit(stackLimit),
       arenaLists(arenaLists),
       shared(shared)
 {}
 
 bool
 ThreadContext::isMainThread()
--- a/js/src/jstaskset.h
+++ b/js/src/jstaskset.h
@@ -21,44 +21,34 @@ enum ParallelResult { TP_SUCCESS, TP_RET
 struct TaskSet;
 
 // Executes the given |TaskSet| in parallel using the runtime's
 // |ThreadPool|, returning upon completion.  In general, if there are
 // |N| workers in the threadpool, the problem will be divided into
 // |N+1| slices, as the main thread will also execute one slice.
 ParallelResult ExecuteTaskSet(JSContext *cx, TaskSet &taskSet);
 
-#ifndef JS_THREADSAFE_ION
-
-struct TaskSet {};
-struct ThreadContext {};
-
-static inline bool InParallelSection() {
-    return ThreadContext::current() != NULL;
-}
-
-#else
-
 class TaskSetSharedContext;
 class AutoRendezvous;
 class AutoSetThreadContext;
 namespace gc { struct ArenaLists; }
 
 struct ThreadContext
 {
 public:
+    JS::PerThreadData *perThreadData;
     const size_t threadId;
     const size_t numThreads;
     uintptr_t ionStackLimit;
 
     // Arenas to use when allocating on this thread.
     // See |js::ion::ParFunctions::ParNewGCThing()|.
     gc::ArenaLists *const arenaLists;
 
-    ThreadContext(size_t threadId, size_t numThreads,
+    ThreadContext(JS::PerThreadData *perThreadData, size_t threadId, size_t numThreads,
                   uintptr_t stackLimit, js::gc::ArenaLists *arenaLists,
                   TaskSetSharedContext *shared);
 
     // True if this is the main thread, false if it is one of the parallel workers
     bool isMainThread();
 
     // Generally speaking, if a thread returns false, that is
     // interpreted as a "bailout"---meaning, a recoverable error.  If
@@ -117,16 +107,18 @@ public:
     //
     // Returns true on success, false to halt parallel execution.
     virtual bool post(size_t numThreads) = 0;
 };
 
 /* True if this thread is currently executing a ParallelArray
    operation across multiple threads. */
 static inline bool InParallelSection() {
+#   ifdef JS_THREADSAFE_ION
     return ThreadContext::current() != NULL;
+#   else
+    return false;
+#   endif
 }
 
 #endif
 
 }
-
-#endif
--- a/js/src/jsthreadpool.cpp
+++ b/js/src/jsthreadpool.cpp
@@ -2,28 +2,23 @@
 /* vim: set ts=4 sw=4 et tw=99: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "jscntxt.h"
 #include "jslock.h"
 #include "jsthreadpool.h"
+#include "prthread.h"
 #if JS_ION
 #  include "ion/IonBuilder.h"
 #endif
 
 namespace js {
 
-#ifndef JS_THREADSAFE_ION
-
-struct ThreadPool {};
-
-#else
-
 /****************************************************************************
  * WorkerThread
  *
  * Each |WorkerThread| just hangs around waiting for items to be added
  * to its |worklist_|.  Whenever something is added, it gets executed.
  * Once the worker's state is set to |TERMINATING|, the worker will
  * exit as soon as its queue is empty.
  */
@@ -199,16 +194,17 @@ ThreadPool::~ThreadPool() {
         WorkerThread *worker = workers_.popCopy();
         delete worker;
     }
 }
 
 bool
 ThreadPool::init()
 {
+#ifdef JS_THREADSAFE_ION
     // Compute desired number of workers based on env var or # of CPUs.
     size_t numWorkers = 0;
     char *pathreads = getenv("PATHREADS");
     if (pathreads != NULL) {
         numWorkers = strtol(pathreads, NULL, 10);
     } else {
         numWorkers = GetCPUCount() - 1;
     }
@@ -228,16 +224,18 @@ ThreadPool::init()
         if (!workers_.append(worker)) {
             delete worker;
             return false;
         }
         if (!worker->start()) {
             return false;
         }
     }
+#endif
+
     return true;
 }
 
 void
 ThreadPool::terminateWorkers()
 {
     for (size_t i = 0; i < workers_.length(); i++) {
         workers_[i]->terminate();
@@ -265,11 +263,9 @@ ThreadPool::submitAll(TaskExecutor *exec
 }
 
 bool
 ThreadPool::terminate() {
     terminateWorkers();
     return true;
 }
 
-#endif
-
 }
--- a/js/src/jsthreadpool.h
+++ b/js/src/jsthreadpool.h
@@ -7,42 +7,31 @@
 
 #ifndef jsthreadpool_h___
 #define jsthreadpool_h___
 
 #if defined(JS_THREADSAFE) && defined(JS_ION)
 # define JS_THREADSAFE_ION
 #endif
 
-#ifdef JS_THREADSAFE_ION
 #include <stddef.h>
 #include "mozilla/StandardInteger.h"
 #include "prtypes.h"
+#include "js/Vector.h"
+#include "jsalloc.h"
 #include "prlock.h"
 #include "prcvar.h"
-#include "js/Vector.h"
-#include "jsalloc.h"
-#endif
 
 struct JSContext;
 struct JSRuntime;
 struct JSCompartment;
 struct JSScript;
 
 namespace js {
 
-#ifndef JS_THREADSAFE_ION
-
-struct ThreadPool {
-    bool init() { return true; }
-    size_t numWorkers() { return 0; }
-};
-
-#else
-
 class WorkerThread;
 
 typedef void (*TaskFun)(void *userdata, size_t workerId, uintptr_t stackLimit);
 
 class TaskExecutor
 {
 public:
     virtual void executeFromWorker(size_t workerId, uintptr_t stackLimit) = 0;
@@ -80,15 +69,13 @@ public:
     bool submitOne(TaskExecutor *executor);
 
     // Submits a job that will be executed by all workers.
     bool submitAll(TaskExecutor *executor);
 
     bool terminate();
 };
 
-#endif
-
 }
 
 
 
 #endif
--- a/js/src/jsthreadpoolinlines.h
+++ b/js/src/jsthreadpoolinlines.h
@@ -1,12 +1,12 @@
-#ifdef JS_THREADSAFE_ION
-
 namespace js {
 
 ThreadContext *
 ThreadContext::current() {
+#ifdef JS_THREADSAFE_ION
     return (ThreadContext*) PR_GetThreadPrivate(ThreadPrivateIndex);
+#else
+    return NULL;
+#endif
 }
 
 }
-
-#endif