Bug 1118107 - Convert ThreadSafeContext -> ExclusiveContext and remove PJS paths in object ops. (r=lth)
authorShu-yu Guo <shu@rfrn.org>
Fri, 09 Jan 2015 00:06:03 -0800
changeset 248702 46c80c517631bd66053a9a84f8419329f7891935
parent 248701 68d1c3fd25f1fbbb5b8910a41ff0a691c0eae371
child 248703 dfa1f0425c654d6058be1ef238c9d4a6e605f6ba
push id4489
push userraliiev@mozilla.com
push dateMon, 23 Feb 2015 15:17:55 +0000
treeherdermozilla-beta@fd7c3dc24146 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerslth
bugs1118107
milestone37.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 1118107 - Convert ThreadSafeContext -> ExclusiveContext and remove PJS paths in object ops. (r=lth)
js/src/jit/CodeGenerator.cpp
js/src/jit/IonCaches.cpp
js/src/jit/VMFunctions.cpp
js/src/jsarray.cpp
js/src/jsarray.h
js/src/jscntxt.h
js/src/jsobj.cpp
js/src/jsobj.h
js/src/jspropertytree.cpp
js/src/jspropertytree.h
js/src/vm/Interpreter-inl.h
js/src/vm/Interpreter.cpp
js/src/vm/NativeObject-inl.h
js/src/vm/NativeObject.cpp
js/src/vm/NativeObject.h
js/src/vm/ScopeObject.cpp
js/src/vm/Shape-inl.h
js/src/vm/Shape.cpp
js/src/vm/Shape.h
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -2383,17 +2383,17 @@ CodeGenerator::visitMaybeToDoubleElement
 
     masm.bind(&convert);
     masm.convertInt32ToDouble(value, temp);
     masm.boxDouble(temp, out);
 
     masm.bind(&done);
 }
 
-typedef bool (*CopyElementsForWriteFn)(ThreadSafeContext *, NativeObject *);
+typedef bool (*CopyElementsForWriteFn)(ExclusiveContext *, NativeObject *);
 static const VMFunction CopyElementsForWriteInfo =
     FunctionInfo<CopyElementsForWriteFn>(NativeObject::CopyElementsForWrite);
 
 void
 CodeGenerator::visitMaybeCopyElementsForWrite(LMaybeCopyElementsForWrite *lir)
 {
     Register object = ToRegister(lir->object());
     Register temp = ToRegister(lir->temp());
--- a/js/src/jit/IonCaches.cpp
+++ b/js/src/jit/IonCaches.cpp
@@ -2626,17 +2626,17 @@ IsPropertyAddInlineable(NativeObject *ob
     if (needsTypeBarrier)
         return CanInlineSetPropTypeCheck(obj, id, val, checkTypeset);
 
     *checkTypeset = false;
     return true;
 }
 
 static SetPropertyIC::NativeSetPropCacheability
-CanAttachNativeSetProp(ThreadSafeContext *cx, HandleObject obj, HandleId id, ConstantOrRegister val,
+CanAttachNativeSetProp(JSContext *cx, HandleObject obj, HandleId id, ConstantOrRegister val,
                        bool needsTypeBarrier, MutableHandleNativeObject holder,
                        MutableHandleShape shape, bool *checkTypeset)
 {
     if (!obj->isNative())
         return SetPropertyIC::CanAttachNone;
 
     // See if the property exists on the object.
     if (IsPropertySetInlineable(&obj->as<NativeObject>(), id, shape, val, needsTypeBarrier, checkTypeset))
--- a/js/src/jit/VMFunctions.cpp
+++ b/js/src/jit/VMFunctions.cpp
@@ -498,17 +498,17 @@ SetProperty(JSContext *cx, HandleObject 
         // required for initializing 'const' closure variables.
         Shape *shape = obj->as<NativeObject>().lookup(cx, name);
         MOZ_ASSERT(shape && shape->hasSlot());
         obj->as<NativeObject>().setSlotWithType(cx, shape, value);
         return true;
     }
 
     if (MOZ_LIKELY(!obj->getOps()->setProperty)) {
-        return baseops::SetPropertyHelper<SequentialExecution>(
+        return baseops::SetPropertyHelper(
             cx, obj.as<NativeObject>(), obj.as<NativeObject>(), id,
             (op == JSOP_SETNAME || op == JSOP_STRICTSETNAME ||
              op == JSOP_SETGNAME || op == JSOP_STRICTSETGNAME)
             ? baseops::Unqualified
             : baseops::Qualified,
             &v,
             strict);
     }
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -470,135 +470,101 @@ array_length_setter(JSContext *cx, Handl
         const Class *clasp = obj->getClass();
         return JSObject::defineProperty(cx, obj, cx->names().length, vp,
                                         clasp->getProperty, clasp->setProperty, JSPROP_ENUMERATE);
     }
 
     Rooted<ArrayObject*> arr(cx, &obj->as<ArrayObject>());
     MOZ_ASSERT(arr->lengthIsWritable(),
                "setter shouldn't be called if property is non-writable");
-    return ArraySetLength<SequentialExecution>(cx, arr, id, JSPROP_PERMANENT, vp, strict);
+    return ArraySetLength(cx, arr, id, JSPROP_PERMANENT, vp, strict);
 }
 
 struct ReverseIndexComparator
 {
     bool operator()(const uint32_t& a, const uint32_t& b, bool *lessOrEqualp) {
         MOZ_ASSERT(a != b, "how'd we get duplicate indexes?");
         *lessOrEqualp = b <= a;
         return true;
     }
 };
 
-template <ExecutionMode mode>
 bool
-js::CanonicalizeArrayLengthValue(typename ExecutionModeTraits<mode>::ContextType cx,
-                                 HandleValue v, uint32_t *newLen)
+js::CanonicalizeArrayLengthValue(JSContext *cx, HandleValue v, uint32_t *newLen)
 {
     double d;
 
-    if (mode == ParallelExecution) {
-        if (v.isObject())
-            return false;
-
-        if (!NonObjectToUint32(cx, v, newLen))
-            return false;
-
-        if (!NonObjectToNumber(cx, v, &d))
-            return false;
-    } else {
-        if (!ToUint32(cx->asJSContext(), v, newLen))
-            return false;
-
-        if (!ToNumber(cx->asJSContext(), v, &d))
-            return false;
-    }
+    if (!ToUint32(cx, v, newLen))
+        return false;
+
+    if (!ToNumber(cx, v, &d))
+        return false;
 
     if (d == *newLen)
         return true;
 
-    if (cx->isJSContext())
-        JS_ReportErrorNumber(cx->asJSContext(), js_GetErrorMessage, nullptr,
-                             JSMSG_BAD_ARRAY_LENGTH);
+    JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_BAD_ARRAY_LENGTH);
     return false;
 }
 
-template bool
-js::CanonicalizeArrayLengthValue<SequentialExecution>(JSContext *cx,
-                                                      HandleValue v, uint32_t *newLen);
-template bool
-js::CanonicalizeArrayLengthValue<ParallelExecution>(ForkJoinContext *cx,
-                                                    HandleValue v, uint32_t *newLen);
-
 /* ES6 20130308 draft 8.4.2.4 ArraySetLength */
-template <ExecutionMode mode>
 bool
-js::ArraySetLength(typename ExecutionModeTraits<mode>::ContextType cxArg,
-                   Handle<ArrayObject*> arr, HandleId id,
+js::ArraySetLength(JSContext *cx, Handle<ArrayObject*> arr, HandleId id,
                    unsigned attrs, HandleValue value, bool setterIsStrict)
 {
-    MOZ_ASSERT(cxArg->isThreadLocal(arr));
-    MOZ_ASSERT(id == NameToId(cxArg->names().length));
-
-    if (!arr->maybeCopyElementsForWrite(cxArg))
+    MOZ_ASSERT(id == NameToId(cx->names().length));
+
+    if (!arr->maybeCopyElementsForWrite(cx))
         return false;
 
     /* Steps 1-2 are irrelevant in our implementation. */
 
     /* Steps 3-5. */
     uint32_t newLen;
-    if (!CanonicalizeArrayLengthValue<mode>(cxArg, value, &newLen))
+    if (!CanonicalizeArrayLengthValue(cx, value, &newLen))
         return false;
 
     // Abort if we're being asked to change enumerability or configurability.
     // (The length property of arrays is non-configurable, so such attempts
     // must fail.)  This behavior is spread throughout the ArraySetLength spec
     // algorithm, but we only need check it once as our array implementation
     // is internally so different from the spec algorithm.  (ES5 and ES6 define
     // behavior by delegating to the default define-own-property algorithm --
     // OrdinaryDefineOwnProperty in ES6, the default [[DefineOwnProperty]] in
     // ES5 -- but we reimplement all the conflict-detection bits ourselves here
     // so that we can use a customized length representation.)
     if (!(attrs & JSPROP_PERMANENT) || (attrs & JSPROP_ENUMERATE)) {
         if (!setterIsStrict)
             return true;
-        // Bail for strict mode in parallel execution, as we need to go back
-        // to sequential mode to throw the error.
-        if (mode == ParallelExecution)
-            return false;
-        return Throw(cxArg->asJSContext(), id, JSMSG_CANT_REDEFINE_PROP);
+        return Throw(cx, id, JSMSG_CANT_REDEFINE_PROP);
     }
 
     /* Steps 6-7. */
     bool lengthIsWritable = arr->lengthIsWritable();
 #ifdef DEBUG
     {
-        RootedShape lengthShape(cxArg, arr->lookupPure(id));
+        RootedShape lengthShape(cx, arr->lookupPure(id));
         MOZ_ASSERT(lengthShape);
         MOZ_ASSERT(lengthShape->writable() == lengthIsWritable);
     }
 #endif
 
     uint32_t oldLen = arr->length();
 
     /* Steps 8-9 for arrays with non-writable length. */
     if (!lengthIsWritable) {
         if (newLen == oldLen)
             return true;
 
-        if (!cxArg->isJSContext())
-            return false;
-
         if (setterIsStrict) {
-            return JS_ReportErrorFlagsAndNumber(cxArg->asJSContext(),
-                                                JSREPORT_ERROR, js_GetErrorMessage, nullptr,
+            return JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, js_GetErrorMessage, nullptr,
                                                 JSMSG_CANT_REDEFINE_ARRAY_LENGTH);
         }
 
-        return JSObject::reportReadOnly(cxArg->asJSContext(), id,
-                                        JSREPORT_STRICT | JSREPORT_WARNING);
+        return JSObject::reportReadOnly(cx, id, JSREPORT_STRICT | JSREPORT_WARNING);
     }
 
     /* Step 8. */
     bool succeeded = true;
     do {
         // The initialized length and capacity of an array only need updating
         // when non-hole elements are added or removed, which doesn't happen
         // when array length stays the same or increases.
@@ -610,40 +576,33 @@ js::ArraySetLength(typename ExecutionMod
         // We can only do this if there are only densely-indexed elements.
         // Once there's a sparse indexed element, there's no good way to know,
         // save by enumerating all the properties to find it.  But we *have* to
         // know in case that sparse indexed element is non-configurable, as
         // that element must prevent any deletions below it.  Bug 586842 should
         // fix this inefficiency by moving indexed storage to be entirely
         // separate from non-indexed storage.
         if (!arr->isIndexed()) {
-            if (!arr->maybeCopyElementsForWrite(cxArg))
+            if (!arr->maybeCopyElementsForWrite(cx))
                 return false;
 
             uint32_t oldCapacity = arr->getDenseCapacity();
             uint32_t oldInitializedLength = arr->getDenseInitializedLength();
             MOZ_ASSERT(oldCapacity >= oldInitializedLength);
             if (oldInitializedLength > newLen)
                 arr->setDenseInitializedLength(newLen);
             if (oldCapacity > newLen)
-                arr->shrinkElements(cxArg, newLen);
+                arr->shrinkElements(cx, newLen);
 
             // We've done the work of deleting any dense elements needing
             // deletion, and there are no sparse elements.  Thus we can skip
             // straight to defining the length.
             break;
         }
 
-        // Bail from parallel execution if need to perform step 15, which is
-        // unsafe and isn't a common case.
-        if (mode == ParallelExecution)
-            return false;
-
-        JSContext *cx = cxArg->asJSContext();
-
         // Step 15.
         //
         // Attempt to delete all elements above the new length, from greatest
         // to least.  If any of these deletions fails, we're supposed to define
         // the length to one greater than the index that couldn't be deleted,
         // *with the property attributes specified*.  This might convert the
         // length to be not the value specified, yet non-writable.  (You may be
         // forgiven for thinking these are interesting semantics.)  Example:
@@ -742,36 +701,25 @@ js::ArraySetLength(typename ExecutionMod
     } while (false);
 
     /* Steps 12, 16. */
 
     // Yes, we totally drop a non-stub getter/setter from a defineProperty
     // API call on the floor here.  Given that getter/setter will go away in
     // the long run, with accessors replacing them both internally and at the
     // API level, just run with this.
-    RootedShape lengthShape(cxArg, mode == ParallelExecution
-                            ? arr->lookupPure(id)
-                            : arr->lookup(cxArg->asJSContext(), id));
-    if (!NativeObject::changeProperty<mode>(cxArg, arr, lengthShape, attrs,
-                                            JSPROP_PERMANENT | JSPROP_READONLY | JSPROP_SHARED,
-                                            array_length_getter, array_length_setter))
+    RootedShape lengthShape(cx, arr->lookup(cx, id));
+    if (!NativeObject::changeProperty(cx, arr, lengthShape, attrs,
+                                      JSPROP_PERMANENT | JSPROP_READONLY | JSPROP_SHARED,
+                                      array_length_getter, array_length_setter))
     {
         return false;
     }
 
-    if (mode == ParallelExecution) {
-        // Overflowing int32 requires changing TI state.
-        if (newLen > INT32_MAX)
-            return false;
-        arr->setLengthInt32(newLen);
-    } else {
-        JSContext *cx = cxArg->asJSContext();
-        arr->setLength(cx, newLen);
-    }
-
+    arr->setLength(cx, newLen);
 
     // All operations past here until the |!succeeded| code must be infallible,
     // so that all element fields remain properly synchronized.
 
     // Trim the initialized length, if needed, to preserve the <= length
     // invariant.  (Capacity was already reduced during element deletion, if
     // necessary.)
     ObjectElements *header = arr->getElementsHeader();
@@ -782,45 +730,33 @@ js::ArraySetLength(typename ExecutionMod
 
         // When an array's length becomes non-writable, writes to indexes
         // greater than or equal to the length don't change the array.  We
         // handle this with a check for non-writable length in most places.
         // But in JIT code every check counts -- so we piggyback the check on
         // the already-required range check for |index < capacity| by making
         // capacity of arrays with non-writable length never exceed the length.
         if (arr->getDenseCapacity() > newLen) {
-            arr->shrinkElements(cxArg, newLen);
+            arr->shrinkElements(cx, newLen);
             arr->getElementsHeader()->capacity = newLen;
         }
     }
 
     if (setterIsStrict && !succeeded) {
-        // We can't have arrived here under ParallelExecution, as we have
-        // returned from the function before step 15 above.
-        JSContext *cx = cxArg->asJSContext();
         RootedId elementId(cx);
         if (!IndexToId(cx, newLen - 1, &elementId))
             return false;
         return arr->reportNotConfigurable(cx, elementId);
     }
 
     return true;
 }
 
-template bool
-js::ArraySetLength<SequentialExecution>(JSContext *cx, Handle<ArrayObject*> arr,
-                                        HandleId id, unsigned attrs, HandleValue value,
-                                        bool setterIsStrict);
-template bool
-js::ArraySetLength<ParallelExecution>(ForkJoinContext *cx, Handle<ArrayObject*> arr,
-                                      HandleId id, unsigned attrs, HandleValue value,
-                                      bool setterIsStrict);
-
 bool
-js::WouldDefinePastNonwritableLength(ThreadSafeContext *cx,
+js::WouldDefinePastNonwritableLength(ExclusiveContext *cx,
                                      HandleObject obj, uint32_t index, bool strict,
                                      bool *definesPast)
 {
     if (!obj->is<ArrayObject>()) {
         *definesPast = false;
         return true;
     }
 
@@ -835,19 +771,16 @@ js::WouldDefinePastNonwritableLength(Thr
         *definesPast = false;
         return true;
     }
 
     *definesPast = true;
 
     // Error in strict mode code or warn with strict option.
     unsigned flags = strict ? JSREPORT_ERROR : (JSREPORT_STRICT | JSREPORT_WARNING);
-    if (cx->isForkJoinContext())
-        return cx->asForkJoinContext()->reportError(flags);
-
     if (!cx->isJSContext())
         return true;
 
     JSContext *ncx = cx->asJSContext();
 
     if (!strict && !ncx->compartment()->options().extraWarnings(ncx))
         return true;
 
@@ -2059,18 +1992,16 @@ js::array_sort(JSContext *cx, unsigned a
                     if (!MergeSort(vec.begin(), n, vec.begin() + n, SortComparatorInt32s[comp]))
                         return false;
                 } else {
                     if (!SortNumerically(cx, &vec, n, comp))
                         return false;
                 }
             } else {
                 FastInvokeGuard fig(cx, fval);
-                MOZ_ASSERT(!InParallelSection(),
-                           "Array.sort() can't currently be used from parallel code");
                 JS_ALWAYS_TRUE(vec.resize(n * 2));
                 if (!MergeSort(vec.begin(), n, vec.begin() + n,
                                SortComparatorFunction(cx, fval, fig)))
                 {
                     return false;
                 }
             }
         }
@@ -3052,17 +2983,16 @@ array_filter(JSContext *cx, unsigned arg
 
     /* Step 7. */
     uint32_t k = 0;
 
     /* Step 8. */
     uint32_t to = 0;
 
     /* Step 9. */
-    MOZ_ASSERT(!InParallelSection());
     FastInvokeGuard fig(cx, ObjectValue(*callable));
     InvokeArgs &args2 = fig.args();
     RootedValue kValue(cx);
     while (k < len) {
         if (!CheckForInterrupt(cx))
             return false;
 
         /* Step a, b, and c.i. */
--- a/js/src/jsarray.h
+++ b/js/src/jsarray.h
@@ -102,30 +102,26 @@ extern JSObject *
 NewDenseCopyOnWriteArray(JSContext *cx, HandleArrayObject templateObject, gc::InitialHeap heap);
 
 /*
  * Determines whether a write to the given element on |obj| should fail because
  * |obj| is an Array with a non-writable length, and writing that element would
  * increase the length of the array.
  */
 extern bool
-WouldDefinePastNonwritableLength(ThreadSafeContext *cx,
+WouldDefinePastNonwritableLength(ExclusiveContext *cx,
                                  HandleObject obj, uint32_t index, bool strict,
                                  bool *definesPast);
 
 /*
  * Canonicalize |vp| to a uint32_t value potentially suitable for use as an
  * array length.
- *
- * For parallel execution we can only canonicalize non-object values.
  */
-template <ExecutionMode mode>
 extern bool
-CanonicalizeArrayLengthValue(typename ExecutionModeTraits<mode>::ContextType cx,
-                             HandleValue v, uint32_t *canonicalized);
+CanonicalizeArrayLengthValue(JSContext *cx, HandleValue v, uint32_t *canonicalized);
 
 extern bool
 GetLengthProperty(JSContext *cx, HandleObject obj, uint32_t *lengthp);
 
 extern bool
 SetLengthProperty(JSContext *cx, HandleObject obj, double length);
 
 extern bool
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -155,21 +155,16 @@ namespace frontend { struct CompileError
  * to represent a ForkJoinContext, the per-thread parallel context used in PJS.
  */
 
 struct ThreadSafeContext : ContextFriendFields,
                            public MallocProvider<ThreadSafeContext>
 {
     friend struct StackBaseShape;
     friend class Activation;
-    friend UnownedBaseShape *BaseShape::lookupUnowned(ThreadSafeContext *cx,
-                                                      const StackBaseShape &base);
-    friend Shape *NativeObject::lookupChildProperty(ThreadSafeContext *cx,
-                                                    HandleNativeObject obj, HandleShape parent,
-                                                    StackShape &child);
 
   public:
     enum ContextKind {
         Context_JS,
         Context_Exclusive,
         Context_ForkJoin
     };
 
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -903,17 +903,17 @@ DefinePropertyOnArray(JSContext *cx, Han
         // But canonicalization may throw a RangeError (or other exception, if
         // the value is an object with user-defined conversion semantics)
         // before other attributes are checked.  So as long as our internal
         // defineProperty hook doesn't match the ECMA one, this duplicate
         // checking can't be helped.
         RootedValue v(cx);
         if (desc.hasValue()) {
             uint32_t newLen;
-            if (!CanonicalizeArrayLengthValue<SequentialExecution>(cx, desc.value(), &newLen))
+            if (!CanonicalizeArrayLengthValue(cx, desc.value(), &newLen))
                 return false;
             v.setNumber(newLen);
         } else {
             v.setNumber(arr->length());
         }
 
         if (desc.hasConfigurable() && desc.configurable())
             return Reject(cx, id, JSMSG_CANT_REDEFINE_PROP, throwError, rval);
@@ -927,17 +927,17 @@ DefinePropertyOnArray(JSContext *cx, Han
         if (!arr->lengthIsWritable()) {
             if (desc.hasWritable() && desc.writable())
                 return Reject(cx, id, JSMSG_CANT_REDEFINE_PROP, throwError, rval);
         } else {
             if (desc.hasWritable() && !desc.writable())
                 attrs = attrs | JSPROP_READONLY;
         }
 
-        return ArraySetLength<SequentialExecution>(cx, arr, id, attrs, v, throwError);
+        return ArraySetLength(cx, arr, id, attrs, v, throwError);
     }
 
     /* Step 3. */
     uint32_t index;
     if (js_IdIsIndex(id, &index)) {
         /* Step 3b. */
         uint32_t oldLen = arr->length();
 
@@ -3112,17 +3112,17 @@ js::HasOwnProperty(JSContext *cx, Handle
     LookupGenericOp lookupOp = obj->getOps()->lookupGeneric;
     if (!NonProxyLookupOwnProperty<CanGC>(cx, lookupOp, obj, id, &pobj, &shape))
         return false;
     *resultp = (shape != nullptr);
     return true;
 }
 
 static MOZ_ALWAYS_INLINE bool
-LookupPropertyPureInline(ThreadSafeContext *cx, JSObject *obj, jsid id, NativeObject **objp,
+LookupPropertyPureInline(ExclusiveContext *cx, JSObject *obj, jsid id, NativeObject **objp,
                          Shape **propp)
 {
     if (!obj->isNative())
         return false;
 
     NativeObject *current = &obj->as<NativeObject>();
     while (true) {
         /* Search for a native dense element, typed array element, or property. */
@@ -3192,34 +3192,34 @@ NativeGetPureInline(NativeObject *pobj, 
         vp->setUndefined();
     }
 
     /* Fail if we have a custom getter. */
     return shape->hasDefaultGetter();
 }
 
 bool
-js::LookupPropertyPure(ThreadSafeContext *cx, JSObject *obj, jsid id, NativeObject **objp,
+js::LookupPropertyPure(ExclusiveContext *cx, JSObject *obj, jsid id, NativeObject **objp,
                        Shape **propp)
 {
     return LookupPropertyPureInline(cx, obj, id, objp, propp);
 }
 
 /*
  * A pure version of GetPropertyHelper that can be called from parallel code
  * without locking. This code path cannot GC. This variant returns false
  * whenever a side-effect might have occured in the effectful version. This
  * includes, but is not limited to:
  *
  *  - Any object in the lookup chain has a non-stub resolve hook.
  *  - Any object in the lookup chain is non-native.
  *  - The property has a getter.
  */
 bool
-js::GetPropertyPure(ThreadSafeContext *cx, JSObject *obj, jsid id, Value *vp)
+js::GetPropertyPure(ExclusiveContext *cx, JSObject *obj, jsid id, Value *vp)
 {
     /* Deal with native objects. */
     NativeObject *obj2;
     Shape *shape;
     if (!LookupPropertyPureInline(cx, obj, id, &obj2, &shape))
         return false;
 
     if (!shape) {
@@ -3253,30 +3253,30 @@ js::GetPropertyPure(ThreadSafeContext *c
         }
     }
 
     return NativeGetPureInline(obj2, shape, vp);
 }
 
 static bool
 MOZ_ALWAYS_INLINE
-GetElementPure(ThreadSafeContext *cx, JSObject *obj, uint32_t index, Value *vp)
+GetElementPure(ExclusiveContext *cx, JSObject *obj, uint32_t index, Value *vp)
 {
     if (index <= JSID_INT_MAX)
         return GetPropertyPure(cx, obj, INT_TO_JSID(index), vp);
     return false;
 }
 
 /*
  * A pure version of GetObjectElementOperation that can be called from
  * parallel code without locking. This variant returns false whenever a
  * side-effect might have occurred.
  */
 bool
-js::GetObjectElementOperationPure(ThreadSafeContext *cx, JSObject *obj, const Value &prop,
+js::GetObjectElementOperationPure(ExclusiveContext *cx, JSObject *obj, const Value &prop,
                                   Value *vp)
 {
     uint32_t index;
     if (IsDefinitelyIndex(prop, &index))
         return GetElementPure(cx, obj, index, vp);
 
     /* Atomizing the property value is effectful and not threadsafe. */
     if (!prop.isString() || !prop.toString()->isAtom())
@@ -3285,57 +3285,36 @@ js::GetObjectElementOperationPure(Thread
     JSAtom *name = &prop.toString()->asAtom();
     if (name->isIndex(&index))
         return GetElementPure(cx, obj, index, vp);
 
     return GetPropertyPure(cx, obj, NameToId(name->asPropertyName()), vp);
 }
 
 bool
-JSObject::reportReadOnly(ThreadSafeContext *cxArg, jsid id, unsigned report)
+JSObject::reportReadOnly(JSContext *cx, jsid id, unsigned report)
 {
-    if (cxArg->isForkJoinContext())
-        return cxArg->asForkJoinContext()->reportError(report);
-
-    if (!cxArg->isJSContext())
-        return true;
-
-    JSContext *cx = cxArg->asJSContext();
     RootedValue val(cx, IdToValue(id));
     return js_ReportValueErrorFlags(cx, report, JSMSG_READ_ONLY,
                                     JSDVG_IGNORE_STACK, val, js::NullPtr(),
                                     nullptr, nullptr);
 }
 
 bool
-JSObject::reportNotConfigurable(ThreadSafeContext *cxArg, jsid id, unsigned report)
+JSObject::reportNotConfigurable(JSContext *cx, jsid id, unsigned report)
 {
-    if (cxArg->isForkJoinContext())
-        return cxArg->asForkJoinContext()->reportError(report);
-
-    if (!cxArg->isJSContext())
-        return true;
-
-    JSContext *cx = cxArg->asJSContext();
     RootedValue val(cx, IdToValue(id));
     return js_ReportValueErrorFlags(cx, report, JSMSG_CANT_DELETE,
                                     JSDVG_IGNORE_STACK, val, js::NullPtr(),
                                     nullptr, nullptr);
 }
 
 bool
-JSObject::reportNotExtensible(ThreadSafeContext *cxArg, unsigned report)
+JSObject::reportNotExtensible(JSContext *cx, unsigned report)
 {
-    if (cxArg->isForkJoinContext())
-        return cxArg->asForkJoinContext()->reportError(report);
-
-    if (!cxArg->isJSContext())
-        return true;
-
-    JSContext *cx = cxArg->asJSContext();
     RootedValue val(cx, ObjectValue(*this));
     return js_ReportValueErrorFlags(cx, report, JSMSG_OBJECT_NOT_EXTENSIBLE,
                                     JSDVG_IGNORE_STACK, val, js::NullPtr(),
                                     nullptr, nullptr);
 }
 
 bool
 JSObject::callMethod(JSContext *cx, HandleId id, unsigned argc, Value *argv, MutableHandleValue vp)
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -563,19 +563,19 @@ class JSObject : public js::gc::Cell
 
     static inline bool hasProperty(JSContext *cx, js::HandleObject obj, js::HandleId id,
                                    bool *foundp);
 
     static inline bool hasProperty(JSContext *cx, js::HandleObject obj, js::PropertyName *name,
                                    bool *foundp);
 
   public:
-    static bool reportReadOnly(js::ThreadSafeContext *cx, jsid id, unsigned report = JSREPORT_ERROR);
-    bool reportNotConfigurable(js::ThreadSafeContext *cx, jsid id, unsigned report = JSREPORT_ERROR);
-    bool reportNotExtensible(js::ThreadSafeContext *cx, unsigned report = JSREPORT_ERROR);
+    static bool reportReadOnly(JSContext *cx, jsid id, unsigned report = JSREPORT_ERROR);
+    bool reportNotConfigurable(JSContext *cx, jsid id, unsigned report = JSREPORT_ERROR);
+    bool reportNotExtensible(JSContext *cx, unsigned report = JSREPORT_ERROR);
 
     /*
      * Get the property with the given id, then call it as a function with the
      * given arguments, providing this object as |this|. If the property isn't
      * callable a TypeError will be thrown. On success the value returned by
      * the call is stored in *vp.
      */
     bool callMethod(JSContext *cx, js::HandleId id, unsigned argc, js::Value *argv,
@@ -1091,24 +1091,24 @@ LookupNameUnqualified(JSContext *cx, Han
 
 extern JSObject *
 js_FindVariableScope(JSContext *cx, JSFunction **funp);
 
 
 namespace js {
 
 bool
-LookupPropertyPure(ThreadSafeContext *cx, JSObject *obj, jsid id, NativeObject **objp,
+LookupPropertyPure(ExclusiveContext *cx, JSObject *obj, jsid id, NativeObject **objp,
                    Shape **propp);
 
 bool
-GetPropertyPure(ThreadSafeContext *cx, JSObject *obj, jsid id, Value *vp);
+GetPropertyPure(ExclusiveContext *cx, JSObject *obj, jsid id, Value *vp);
 
 inline bool
-GetPropertyPure(ThreadSafeContext *cx, JSObject *obj, PropertyName *name, Value *vp)
+GetPropertyPure(ExclusiveContext *cx, JSObject *obj, PropertyName *name, Value *vp)
 {
     return GetPropertyPure(cx, obj, NameToId(name), vp);
 }
 
 bool
 GetOwnPropertyDescriptor(JSContext *cx, HandleObject obj, HandleId id,
                          MutableHandle<PropertyDescriptor> desc);
 
@@ -1122,17 +1122,17 @@ extern bool
 IsDelegate(JSContext *cx, HandleObject obj, const Value &v, bool *result);
 
 // obj is a JSObject*, but we root it immediately up front. We do it
 // that way because we need a Rooted temporary in this method anyway.
 extern bool
 IsDelegateOfObject(JSContext *cx, HandleObject protoObj, JSObject* obj, bool *result);
 
 bool
-GetObjectElementOperationPure(ThreadSafeContext *cx, JSObject *obj, const Value &prop, Value *vp);
+GetObjectElementOperationPure(ExclusiveContext *cx, JSObject *obj, const Value &prop, Value *vp);
 
 /* Wrap boolean, number or string as Boolean, Number or String object. */
 extern JSObject *
 PrimitiveToObject(JSContext *cx, const Value &v);
 
 } /* namespace js */
 
 namespace js {
--- a/js/src/jspropertytree.cpp
+++ b/js/src/jspropertytree.cpp
@@ -188,46 +188,16 @@ PropertyTree::getChild(ExclusiveContext 
         return nullptr;
 
     if (!insertChild(cx, parent, shape))
         return nullptr;
 
     return shape;
 }
 
-Shape *
-PropertyTree::lookupChild(ThreadSafeContext *cx, Shape *parent, const StackShape &child)
-{
-    /* Keep this in sync with the logic of getChild above. */
-    Shape *shape = nullptr;
-
-    MOZ_ASSERT(parent);
-
-    KidsPointer *kidp = &parent->kids;
-    if (kidp->isShape()) {
-        Shape *kid = kidp->toShape();
-        if (kid->matches(child))
-            shape = kid;
-    } else if (kidp->isHash()) {
-        if (KidsHash::Ptr p = kidp->toHash()->readonlyThreadsafeLookup(child))
-            shape = *p;
-    } else {
-        return nullptr;
-    }
-
-    if (shape) {
-        DebugOnly<JS::Zone *> zone = shape->arenaHeader()->zone;
-        MOZ_ASSERT(!zone->needsIncrementalBarrier());
-        MOZ_ASSERT(!(zone->isGCSweeping() && !shape->isMarked() &&
-                     !shape->arenaHeader()->allocatedDuringIncremental));
-    }
-
-    return shape;
-}
-
 void
 Shape::sweep()
 {
     if (inDictionary())
         return;
 
     /*
      * We detach the child from the parent if the parent is reachable.
--- a/js/src/jspropertytree.h
+++ b/js/src/jspropertytree.h
@@ -92,14 +92,13 @@ class PropertyTree
     explicit PropertyTree(JSCompartment *comp)
         : compartment_(comp)
     {
     }
 
     JSCompartment *compartment() { return compartment_; }
 
     Shape *getChild(ExclusiveContext *cx, Shape *parent, StackShape &child);
-    Shape *lookupChild(ThreadSafeContext *cx, Shape *parent, const StackShape &child);
 };
 
 } /* namespace js */
 
 #endif /* jspropertytree_h */
--- a/js/src/vm/Interpreter-inl.h
+++ b/js/src/vm/Interpreter-inl.h
@@ -319,21 +319,18 @@ SetNameOperation(JSContext *cx, JSScript
     /*
      * In strict-mode, we need to trigger an error when trying to assign to an
      * undeclared global variable. To do this, we call SetPropertyHelper
      * directly and pass Unqualified.
      */
     if (scope->isUnqualifiedVarObj()) {
         MOZ_ASSERT(!scope->getOps()->setProperty);
         RootedId id(cx, NameToId(name));
-        return baseops::SetPropertyHelper<SequentialExecution>(cx,
-                                                               scope.as<NativeObject>(),
-                                                               scope.as<NativeObject>(),
-                                                               id, baseops::Unqualified, &valCopy,
-                                                               strict);
+        return baseops::SetPropertyHelper(cx, scope.as<NativeObject>(), scope.as<NativeObject>(),
+                                          id, baseops::Unqualified, &valCopy, strict);
     }
 
     return JSObject::setProperty(cx, scope, scope, name, &valCopy, strict);
 }
 
 inline bool
 DefVarOrConstOperation(JSContext *cx, HandleObject varobj, HandlePropertyName dn, unsigned attrs)
 {
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -307,22 +307,18 @@ static bool
 SetObjectProperty(JSContext *cx, JSOp op, HandleValue lval, HandleId id, MutableHandleValue rref)
 {
     MOZ_ASSERT(lval.isObject());
 
     RootedObject obj(cx, &lval.toObject());
 
     bool strict = op == JSOP_STRICTSETPROP;
     if (MOZ_LIKELY(!obj->getOps()->setProperty)) {
-        if (!baseops::SetPropertyHelper<SequentialExecution>(cx,
-                                                             obj.as<NativeObject>(),
-                                                             obj.as<NativeObject>(),
-                                                             id,
-                                                             baseops::Qualified,
-                                                             rref, strict))
+        if (!baseops::SetPropertyHelper(cx, obj.as<NativeObject>(), obj.as<NativeObject>(),
+                                        id, baseops::Qualified, rref, strict))
         {
             return false;
         }
     } else {
         if (!JSObject::setGeneric(cx, obj, obj, id, rref, strict))
             return false;
     }
 
--- a/js/src/vm/NativeObject-inl.h
+++ b/js/src/vm/NativeObject-inl.h
@@ -27,18 +27,17 @@ NativeObject::fixedData(size_t nslots) c
     MOZ_ASSERT(nslots == numFixedSlots() + (hasPrivate() ? 1 : 0));
     return reinterpret_cast<uint8_t *>(&fixedSlots()[nslots]);
 }
 
 /* static */ inline bool
 NativeObject::changePropertyAttributes(JSContext *cx, HandleNativeObject obj,
                                        HandleShape shape, unsigned attrs)
 {
-    return !!changeProperty<SequentialExecution>(cx, obj, shape, attrs, 0,
-                                                 shape->getter(), shape->setter());
+    return !!changeProperty(cx, obj, shape, attrs, 0, shape->getter(), shape->setter());
 }
 
 inline void
 NativeObject::removeLastProperty(ExclusiveContext *cx)
 {
     MOZ_ASSERT(canRemoveLastProperty());
     RootedNativeObject self(cx, this);
     RootedShape prev(cx, lastProperty()->previous());
@@ -71,25 +70,16 @@ NativeObject::setShouldConvertDoubleElem
 
 inline void
 NativeObject::clearShouldConvertDoubleElements()
 {
     MOZ_ASSERT(is<ArrayObject>() && !hasEmptyElements());
     getElementsHeader()->clearShouldConvertDoubleElements();
 }
 
-inline bool
-NativeObject::setDenseElementIfHasType(uint32_t index, const Value &val)
-{
-    if (!types::HasTypePropertyId(this, JSID_VOID, val))
-        return false;
-    setDenseElementMaybeConvertDouble(index, val);
-    return true;
-}
-
 inline void
 NativeObject::setDenseElementWithType(ExclusiveContext *cx, uint32_t index,
                                       const Value &val)
 {
     // Avoid a slow AddTypePropertyId call if the type is the same as the type
     // of the previous element.
     types::Type thisType = types::GetValueType(val);
     if (index == 0 || types::GetValueType(elements_[index - 1]) != thisType)
@@ -133,17 +123,17 @@ NativeObject::writeToIndexWouldMarkNotPa
 inline void
 NativeObject::markDenseElementsNotPacked(ExclusiveContext *cx)
 {
     MOZ_ASSERT(isNative());
     MarkTypeObjectFlags(cx, this, types::OBJECT_FLAG_NON_PACKED);
 }
 
 inline void
-NativeObject::ensureDenseInitializedLengthNoPackedCheck(ThreadSafeContext *cx, uint32_t index,
+NativeObject::ensureDenseInitializedLengthNoPackedCheck(ExclusiveContext *cx, uint32_t index,
                                                         uint32_t extra)
 {
     MOZ_ASSERT(cx->isThreadLocal(this));
     MOZ_ASSERT(!denseElementsAreCopyOnWrite());
 
     /*
      * Ensure that the array's contents have been initialized up to index, and
      * mark the elements through 'index + extra' as initialized in preparation
@@ -167,26 +157,18 @@ NativeObject::ensureDenseInitializedLeng
 inline void
 NativeObject::ensureDenseInitializedLength(ExclusiveContext *cx, uint32_t index, uint32_t extra)
 {
     if (writeToIndexWouldMarkNotPacked(index))
         markDenseElementsNotPacked(cx);
     ensureDenseInitializedLengthNoPackedCheck(cx, index, extra);
 }
 
-inline void
-NativeObject::ensureDenseInitializedLengthPreservePackedFlag(ThreadSafeContext *cx,
-                                                             uint32_t index, uint32_t extra)
-{
-    MOZ_ASSERT(!writeToIndexWouldMarkNotPacked(index));
-    ensureDenseInitializedLengthNoPackedCheck(cx, index, extra);
-}
-
 NativeObject::EnsureDenseResult
-NativeObject::extendDenseElements(ThreadSafeContext *cx,
+NativeObject::extendDenseElements(ExclusiveContext *cx,
                                   uint32_t requiredCapacity, uint32_t extra)
 {
     MOZ_ASSERT(cx->isThreadLocal(this));
     MOZ_ASSERT(!denseElementsAreCopyOnWrite());
 
     /*
      * Don't grow elements for non-extensible objects or watched objects. Dense
      * elements can be added/written with no extensible or watchpoint checks as
@@ -216,20 +198,23 @@ NativeObject::extendDenseElements(Thread
 
     if (!growElements(cx, requiredCapacity))
         return ED_FAILED;
 
     return ED_OK;
 }
 
 inline NativeObject::EnsureDenseResult
-NativeObject::ensureDenseElementsNoPackedCheck(ThreadSafeContext *cx, uint32_t index, uint32_t extra)
+NativeObject::ensureDenseElements(ExclusiveContext *cx, uint32_t index, uint32_t extra)
 {
     MOZ_ASSERT(isNative());
 
+    if (writeToIndexWouldMarkNotPacked(index))
+        markDenseElementsNotPacked(cx);
+
     if (!maybeCopyElementsForWrite(cx))
         return ED_FAILED;
 
     uint32_t currentCapacity = getDenseCapacity();
 
     uint32_t requiredCapacity;
     if (extra == 1) {
         /* Optimize for the common case. */
@@ -257,32 +242,16 @@ NativeObject::ensureDenseElementsNoPacke
     EnsureDenseResult edr = extendDenseElements(cx, requiredCapacity, extra);
     if (edr != ED_OK)
         return edr;
 
     ensureDenseInitializedLengthNoPackedCheck(cx, index, extra);
     return ED_OK;
 }
 
-inline NativeObject::EnsureDenseResult
-NativeObject::ensureDenseElements(ExclusiveContext *cx, uint32_t index, uint32_t extra)
-{
-    if (writeToIndexWouldMarkNotPacked(index))
-        markDenseElementsNotPacked(cx);
-    return ensureDenseElementsNoPackedCheck(cx, index, extra);
-}
-
-inline NativeObject::EnsureDenseResult
-NativeObject::ensureDenseElementsPreservePackedFlag(ThreadSafeContext *cx, uint32_t index,
-                                                    uint32_t extra)
-{
-    MOZ_ASSERT(!writeToIndexWouldMarkNotPacked(index));
-    return ensureDenseElementsNoPackedCheck(cx, index, extra);
-}
-
 inline Value
 NativeObject::getDenseOrTypedArrayElement(uint32_t idx)
 {
     if (is<TypedArrayObject>())
         return as<TypedArrayObject>().getElement(idx);
     if (is<SharedTypedArrayObject>())
         return as<SharedTypedArrayObject>().getElement(idx);
     return getDenseElement(idx);
--- a/js/src/vm/NativeObject.cpp
+++ b/js/src/vm/NativeObject.cpp
@@ -313,17 +313,17 @@ void
 PropDesc::trace(JSTracer *trc)
 {
     gc::MarkValueRoot(trc, &value_, "PropDesc value");
     gc::MarkValueRoot(trc, &get_, "PropDesc get");
     gc::MarkValueRoot(trc, &set_, "PropDesc set");
 }
 
 /* static */ inline bool
-NativeObject::updateSlotsForSpan(ThreadSafeContext *cx,
+NativeObject::updateSlotsForSpan(ExclusiveContext *cx,
                                  HandleNativeObject obj, size_t oldSpan, size_t newSpan)
 {
     MOZ_ASSERT(cx->isThreadLocal(obj));
     MOZ_ASSERT(oldSpan != newSpan);
 
     size_t oldCount = dynamicSlotsCount(obj->numFixedSlots(), oldSpan, obj->getClass());
     size_t newCount = dynamicSlotsCount(obj->numFixedSlots(), newSpan, obj->getClass());
 
@@ -343,17 +343,17 @@ NativeObject::updateSlotsForSpan(ThreadS
         if (oldCount > newCount)
             shrinkSlots(cx, obj, oldCount, newCount);
     }
 
     return true;
 }
 
 /* static */ bool
-NativeObject::setLastProperty(ThreadSafeContext *cx, HandleNativeObject obj, HandleShape shape)
+NativeObject::setLastProperty(ExclusiveContext *cx, HandleNativeObject obj, HandleShape shape)
 {
     MOZ_ASSERT(cx->isThreadLocal(obj));
     MOZ_ASSERT(!obj->inDictionaryMode());
     MOZ_ASSERT(!shape->inDictionary());
     MOZ_ASSERT(shape->compartment() == obj->compartment());
     MOZ_ASSERT(shape->numFixedSlots() == obj->numFixedSlots());
 
     size_t oldSpan = obj->lastProperty()->slotSpan();
@@ -386,17 +386,17 @@ NativeObject::setLastPropertyShrinkFixed
     MOZ_ASSERT(shape->slotSpan() <= newFixed);
     MOZ_ASSERT(dynamicSlotsCount(oldFixed, shape->slotSpan(), getClass()) == 0);
     MOZ_ASSERT(dynamicSlotsCount(newFixed, shape->slotSpan(), getClass()) == 0);
 
     shape_ = shape;
 }
 
 /* static */ bool
-NativeObject::setSlotSpan(ThreadSafeContext *cx, HandleNativeObject obj, uint32_t span)
+NativeObject::setSlotSpan(ExclusiveContext *cx, HandleNativeObject obj, uint32_t span)
 {
     MOZ_ASSERT(cx->isThreadLocal(obj));
     MOZ_ASSERT(obj->inDictionaryMode());
 
     size_t oldSpan = obj->lastProperty()->base()->slotSpan();
     if (oldSpan == span)
         return true;
 
@@ -405,40 +405,40 @@ NativeObject::setSlotSpan(ThreadSafeCont
 
     obj->lastProperty()->base()->setSlotSpan(span);
     return true;
 }
 
 // This will not run the garbage collector.  If a nursery cannot accomodate the slot array
 // an attempt will be made to place the array in the tenured area.
 static HeapSlot *
-AllocateSlots(ThreadSafeContext *cx, JSObject *obj, uint32_t nslots)
+AllocateSlots(ExclusiveContext *cx, JSObject *obj, uint32_t nslots)
 {
     if (cx->isJSContext())
         return cx->asJSContext()->runtime()->gc.nursery.allocateSlots(obj, nslots);
     return obj->zone()->pod_malloc<HeapSlot>(nslots);
 }
 
 // This will not run the garbage collector.  If a nursery cannot accomodate the slot array
 // an attempt will be made to place the array in the tenured area.
 //
 // If this returns null then the old slots will be left alone.
 static HeapSlot *
-ReallocateSlots(ThreadSafeContext *cx, JSObject *obj, HeapSlot *oldSlots,
+ReallocateSlots(ExclusiveContext *cx, JSObject *obj, HeapSlot *oldSlots,
                 uint32_t oldCount, uint32_t newCount)
 {
     if (cx->isJSContext()) {
         return cx->asJSContext()->runtime()->gc.nursery.reallocateSlots(obj, oldSlots,
                                                                         oldCount, newCount);
     }
     return obj->zone()->pod_realloc<HeapSlot>(oldSlots, oldCount, newCount);
 }
 
 /* static */ bool
-NativeObject::growSlots(ThreadSafeContext *cx, HandleNativeObject obj, uint32_t oldCount, uint32_t newCount)
+NativeObject::growSlots(ExclusiveContext *cx, HandleNativeObject obj, uint32_t oldCount, uint32_t newCount)
 {
     MOZ_ASSERT(cx->isThreadLocal(obj));
     MOZ_ASSERT(newCount > oldCount);
     MOZ_ASSERT_IF(!obj->is<ArrayObject>(), newCount >= SLOT_CAPACITY_MIN);
 
     /*
      * Slot capacities are determined by the span of allocated objects. Due to
      * the limited number of bits to store shape slots, object growth is
@@ -462,26 +462,26 @@ NativeObject::growSlots(ThreadSafeContex
     obj->slots_ = newslots;
 
     Debug_SetSlotRangeToCrashOnTouch(obj->slots_ + oldCount, newCount - oldCount);
 
     return true;
 }
 
 static void
-FreeSlots(ThreadSafeContext *cx, HeapSlot *slots)
+FreeSlots(ExclusiveContext *cx, HeapSlot *slots)
 {
     // Note: threads without a JSContext do not have access to GGC nursery allocated things.
     if (cx->isJSContext())
         return cx->asJSContext()->runtime()->gc.nursery.freeSlots(slots);
     js_free(slots);
 }
 
 /* static */ void
-NativeObject::shrinkSlots(ThreadSafeContext *cx, HandleNativeObject obj,
+NativeObject::shrinkSlots(ExclusiveContext *cx, HandleNativeObject obj,
                           uint32_t oldCount, uint32_t newCount)
 {
     MOZ_ASSERT(cx->isThreadLocal(obj));
     MOZ_ASSERT(newCount < oldCount);
 
     if (newCount == 0) {
         FreeSlots(cx, obj->slots_);
         obj->slots_ = nullptr;
@@ -695,27 +695,27 @@ NativeObject::maybeDensifySparseElements
         return ED_FAILED;
 
     return ED_OK;
 }
 
 // This will not run the garbage collector.  If a nursery cannot accomodate the element array
 // an attempt will be made to place the array in the tenured area.
 static ObjectElements *
-AllocateElements(ThreadSafeContext *cx, JSObject *obj, uint32_t nelems)
+AllocateElements(ExclusiveContext *cx, JSObject *obj, uint32_t nelems)
 {
     if (cx->isJSContext())
         return cx->asJSContext()->runtime()->gc.nursery.allocateElements(obj, nelems);
     return reinterpret_cast<js::ObjectElements *>(obj->zone()->pod_malloc<HeapSlot>(nelems));
 }
 
 // This will not run the garbage collector.  If a nursery cannot accomodate the element array
 // an attempt will be made to place the array in the tenured area.
 static ObjectElements *
-ReallocateElements(ThreadSafeContext *cx, JSObject *obj, ObjectElements *oldHeader,
+ReallocateElements(ExclusiveContext *cx, JSObject *obj, ObjectElements *oldHeader,
                    uint32_t oldCount, uint32_t newCount)
 {
     if (cx->isJSContext()) {
         return cx->asJSContext()->runtime()->gc.nursery.reallocateElements(obj, oldHeader,
                                                                            oldCount, newCount);
     }
     return reinterpret_cast<js::ObjectElements *>(
             obj->zone()->pod_realloc<HeapSlot>(reinterpret_cast<HeapSlot *>(oldHeader),
@@ -803,17 +803,17 @@ NativeObject::goodAllocated(uint32_t req
             }
         }
     }
 
     return goodAllocated;
 }
 
 bool
-NativeObject::growElements(ThreadSafeContext *cx, uint32_t reqCapacity)
+NativeObject::growElements(ExclusiveContext *cx, uint32_t reqCapacity)
 {
     MOZ_ASSERT(nonProxyIsExtensible());
     MOZ_ASSERT(canHaveNonEmptyElements());
     if (denseElementsAreCopyOnWrite())
         MOZ_CRASH();
 
     uint32_t oldCapacity = getDenseCapacity();
     MOZ_ASSERT(oldCapacity < reqCapacity);
@@ -867,17 +867,17 @@ NativeObject::growElements(ThreadSafeCon
     elements_ = newheader->elements();
 
     Debug_SetSlotRangeToCrashOnTouch(elements_ + initlen, newCapacity - initlen);
 
     return true;
 }
 
 void
-NativeObject::shrinkElements(ThreadSafeContext *cx, uint32_t reqCapacity)
+NativeObject::shrinkElements(ExclusiveContext *cx, uint32_t reqCapacity)
 {
     MOZ_ASSERT(cx->isThreadLocal(this));
     MOZ_ASSERT(canHaveNonEmptyElements());
     if (denseElementsAreCopyOnWrite())
         MOZ_CRASH();
 
     if (!hasDynamicElements())
         return;
@@ -901,17 +901,17 @@ NativeObject::shrinkElements(ThreadSafeC
         return;  // Leave elements at its old size.
     }
 
     newheader->capacity = newCapacity;
     elements_ = newheader->elements();
 }
 
 /* static */ bool
-NativeObject::CopyElementsForWrite(ThreadSafeContext *cx, NativeObject *obj)
+NativeObject::CopyElementsForWrite(ExclusiveContext *cx, NativeObject *obj)
 {
     MOZ_ASSERT(obj->denseElementsAreCopyOnWrite());
 
     // The original owner of a COW elements array should never be modified.
     MOZ_ASSERT(obj->getElementsHeader()->ownerObject() != obj);
 
     uint32_t initlen = obj->getDenseInitializedLength();
     uint32_t allocated = initlen + ObjectElements::VALUES_PER_HEADER;
@@ -935,17 +935,17 @@ NativeObject::CopyElementsForWrite(Threa
     obj->elements_ = newheader->elements();
 
     Debug_SetSlotRangeToCrashOnTouch(obj->elements_ + initlen, newCapacity - initlen);
 
     return true;
 }
 
 /* static */ bool
-NativeObject::allocSlot(ThreadSafeContext *cx, HandleNativeObject obj, uint32_t *slotp)
+NativeObject::allocSlot(ExclusiveContext *cx, HandleNativeObject obj, uint32_t *slotp)
 {
     MOZ_ASSERT(cx->isThreadLocal(obj));
 
     uint32_t slot = obj->slotSpan();
     MOZ_ASSERT(slot >= JSSLOT_FREE(obj->getClass()));
 
     /*
      * If this object is in dictionary mode, try to pull a free slot from the
@@ -1028,28 +1028,23 @@ NativeObject::addDataProperty(ExclusiveC
 }
 
 /*
  * Backward compatibility requires allowing addProperty hooks to mutate the
  * nominal initial value of a slotful property, while GC safety wants that
  * value to be stored before the call-out through the hook.  Optimize to do
  * both while saving cycles for classes that stub their addProperty hook.
  */
-template <ExecutionMode mode>
 static inline bool
-CallAddPropertyHook(typename ExecutionModeTraits<mode>::ExclusiveContextType cxArg,
-                    HandleNativeObject obj, HandleShape shape, HandleValue nominal)
+CallAddPropertyHook(ExclusiveContext *cx, HandleNativeObject obj, HandleShape shape,
+                    HandleValue nominal)
 {
     if (JSPropertyOp addProperty = obj->getClass()->addProperty) {
         MOZ_ASSERT(addProperty != JS_PropertyStub);
 
-        if (mode == ParallelExecution)
-            return false;
-
-        ExclusiveContext *cx = cxArg->asExclusiveContext();
         if (!cx->shouldBeJSContext())
             return false;
 
         /* Make a local copy of value so addProperty can mutate its inout parameter. */
         RootedValue value(cx, nominal);
 
         Rooted<jsid> id(cx, shape->propid());
         if (!CallJSPropertyOp(cx->asJSContext(), addProperty, obj, id, &value)) {
@@ -1059,45 +1054,32 @@ CallAddPropertyHook(typename ExecutionMo
         if (value.get() != nominal) {
             if (shape->hasSlot())
                 obj->setSlotWithType(cx, shape, value);
         }
     }
     return true;
 }
 
-template <ExecutionMode mode>
 static inline bool
-CallAddPropertyHookDense(typename ExecutionModeTraits<mode>::ExclusiveContextType cxArg,
-                         HandleNativeObject obj, uint32_t index, HandleValue nominal)
+CallAddPropertyHookDense(ExclusiveContext *cx, HandleNativeObject obj, uint32_t index,
+                         HandleValue nominal)
 {
     /* Inline addProperty for array objects. */
     if (obj->is<ArrayObject>()) {
         ArrayObject *arr = &obj->as<ArrayObject>();
         uint32_t length = arr->length();
-        if (index >= length) {
-            if (mode == ParallelExecution) {
-                /* We cannot deal with overflows in parallel. */
-                if (length > INT32_MAX)
-                    return false;
-                arr->setLengthInt32(index + 1);
-            } else {
-                arr->setLength(cxArg->asExclusiveContext(), index + 1);
-            }
-        }
+        if (index >= length)
+            arr->setLength(cx, index + 1);
         return true;
     }
 
     if (JSPropertyOp addProperty = obj->getClass()->addProperty) {
         MOZ_ASSERT(addProperty != JS_PropertyStub);
 
-        if (mode == ParallelExecution)
-            return false;
-
-        ExclusiveContext *cx = cxArg->asExclusiveContext();
         if (!cx->shouldBeJSContext())
             return false;
 
         if (!obj->maybeCopyElementsForWrite(cx))
             return false;
 
         /* Make a local copy of value so addProperty can mutate its inout parameter. */
         RootedValue value(cx, nominal);
@@ -1109,67 +1091,44 @@ CallAddPropertyHookDense(typename Execut
         }
         if (value.get() != nominal)
             obj->setDenseElementWithType(cx, index, value);
     }
 
     return true;
 }
 
-template <ExecutionMode mode>
 static bool
-UpdateShapeTypeAndValue(typename ExecutionModeTraits<mode>::ExclusiveContextType cx,
-                        NativeObject *obj, Shape *shape, const Value &value)
+UpdateShapeTypeAndValue(ExclusiveContext *cx, NativeObject *obj, Shape *shape, const Value &value)
 {
     jsid id = shape->propid();
     if (shape->hasSlot()) {
-        if (mode == ParallelExecution) {
-            if (!obj->setSlotIfHasType(shape, value, /* overwriting = */ false))
-                return false;
-        } else {
-            obj->setSlotWithType(cx->asExclusiveContext(), shape, value, /* overwriting = */ false);
-        }
+        obj->setSlotWithType(cx, shape, value, /* overwriting = */ false);
 
         // Per the acquired properties analysis, when the shape of a partially
         // initialized object is changed to its fully initialized shape, its
         // type can be updated as well.
         if (types::TypeNewScript *newScript = obj->typeRaw()->newScript()) {
             if (newScript->initializedShape() == shape)
                 obj->setType(newScript->initializedType());
         }
     }
-    if (!shape->hasSlot() || !shape->hasDefaultGetter() || !shape->hasDefaultSetter()) {
-        if (mode == ParallelExecution) {
-            if (!types::IsTypePropertyIdMarkedNonData(obj, id))
-                return false;
-        } else {
-            types::MarkTypePropertyNonData(cx->asExclusiveContext(), obj, id);
-        }
-    }
-    if (!shape->writable()) {
-        if (mode == ParallelExecution) {
-            if (!types::IsTypePropertyIdMarkedNonWritable(obj, id))
-                return false;
-        } else {
-            types::MarkTypePropertyNonWritable(cx->asExclusiveContext(), obj, id);
-        }
-    }
+    if (!shape->hasSlot() || !shape->hasDefaultGetter() || !shape->hasDefaultSetter())
+        types::MarkTypePropertyNonData(cx, obj, id);
+    if (!shape->writable())
+        types::MarkTypePropertyNonWritable(cx, obj, id);
     return true;
 }
 
-template <ExecutionMode mode>
 static bool
-NativeSet(typename ExecutionModeTraits<mode>::ContextType cx,
-          HandleNativeObject obj, HandleObject receiver,
+NativeSet(JSContext *cx, HandleNativeObject obj, HandleObject receiver,
           HandleShape shape, bool strict, MutableHandleValue vp);
 
-template <ExecutionMode mode>
 static inline bool
-DefinePropertyOrElement(typename ExecutionModeTraits<mode>::ExclusiveContextType cx,
-                        HandleNativeObject obj, HandleId id,
+DefinePropertyOrElement(ExclusiveContext *cx, HandleNativeObject obj, HandleId id,
                         PropertyOp getter, StrictPropertyOp setter,
                         unsigned attrs, HandleValue value,
                         bool callSetterAfterwards, bool setterIsStrict)
 {
     MOZ_ASSERT(getter != JS_PropertyStub);
     MOZ_ASSERT(setter != JS_StrictPropertyStub);
 
     /* Use dense storage for new indexed properties where possible. */
@@ -1183,44 +1142,32 @@ DefinePropertyOrElement(typename Executi
         uint32_t index = JSID_TO_INT(id);
         bool definesPast;
         if (!WouldDefinePastNonwritableLength(cx, obj, index, setterIsStrict, &definesPast))
             return false;
         if (definesPast)
             return true;
 
         NativeObject::EnsureDenseResult result;
-        if (mode == ParallelExecution) {
-            if (obj->writeToIndexWouldMarkNotPacked(index))
-                return false;
-            result = obj->ensureDenseElementsPreservePackedFlag(cx, index, 1);
-        } else {
-            result = obj->ensureDenseElements(cx->asExclusiveContext(), index, 1);
-        }
+        result = obj->ensureDenseElements(cx, index, 1);
 
         if (result == NativeObject::ED_FAILED)
             return false;
         if (result == NativeObject::ED_OK) {
-            if (mode == ParallelExecution) {
-                if (!obj->setDenseElementIfHasType(index, value))
-                    return false;
-            } else {
-                obj->setDenseElementWithType(cx->asExclusiveContext(), index, value);
-            }
-            return CallAddPropertyHookDense<mode>(cx, obj, index, value);
+            obj->setDenseElementWithType(cx, index, value);
+            return CallAddPropertyHookDense(cx, obj, index, value);
         }
     }
 
     if (obj->is<ArrayObject>()) {
         Rooted<ArrayObject*> arr(cx, &obj->as<ArrayObject>());
         if (id == NameToId(cx->names().length)) {
-            if (mode == SequentialExecution && !cx->shouldBeJSContext())
+            if (!cx->shouldBeJSContext())
                 return false;
-            return ArraySetLength<mode>(ExecutionModeTraits<mode>::toContextType(cx), arr, id,
-                                        attrs, value, setterIsStrict);
+            return ArraySetLength(cx->asJSContext(), arr, id, attrs, value, setterIsStrict);
         }
 
         uint32_t index;
         if (js_IdIsIndex(id, &index)) {
             bool definesPast;
             if (!WouldDefinePastNonwritableLength(cx, arr, index, setterIsStrict, &definesPast))
                 return false;
             if (definesPast)
@@ -1231,56 +1178,51 @@ DefinePropertyOrElement(typename Executi
     // Don't define new indexed properties on typed arrays.
     if (IsAnyTypedArray(obj)) {
         uint64_t index;
         if (IsTypedArrayIndex(id, &index))
             return true;
     }
 
     AutoRooterGetterSetter gsRoot(cx, attrs, &getter, &setter);
-    RootedShape shape(cx, NativeObject::putProperty<mode>(cx, obj, id, getter, setter,
-                                                          SHAPE_INVALID_SLOT, attrs, 0));
+    RootedShape shape(cx, NativeObject::putProperty(cx, obj, id, getter, setter,
+                                                    SHAPE_INVALID_SLOT, attrs, 0));
     if (!shape)
         return false;
 
-    if (!UpdateShapeTypeAndValue<mode>(cx, obj, shape, value))
+    if (!UpdateShapeTypeAndValue(cx, obj, shape, value))
         return false;
 
     /*
      * Clear any existing dense index after adding a sparse indexed property,
      * and investigate converting the object to dense indexes.
      */
     if (JSID_IS_INT(id)) {
-        if (mode == ParallelExecution)
-            return false;
-
         if (!obj->maybeCopyElementsForWrite(cx))
             return false;
 
-        ExclusiveContext *ncx = cx->asExclusiveContext();
         uint32_t index = JSID_TO_INT(id);
-        NativeObject::removeDenseElementForSparseIndex(ncx, obj, index);
-        NativeObject::EnsureDenseResult result = NativeObject::maybeDensifySparseElements(ncx, obj);
+        NativeObject::removeDenseElementForSparseIndex(cx, obj, index);
+        NativeObject::EnsureDenseResult result = NativeObject::maybeDensifySparseElements(cx, obj);
         if (result == NativeObject::ED_FAILED)
             return false;
         if (result == NativeObject::ED_OK) {
             MOZ_ASSERT(!setter);
-            return CallAddPropertyHookDense<mode>(cx, obj, index, value);
+            return CallAddPropertyHookDense(cx, obj, index, value);
         }
     }
 
-    if (!CallAddPropertyHook<mode>(cx, obj, shape, value))
+    if (!CallAddPropertyHook(cx, obj, shape, value))
         return false;
 
     if (callSetterAfterwards && setter) {
         if (!cx->shouldBeJSContext())
             return false;
         RootedValue nvalue(cx, value);
-        return NativeSet<mode>(ExecutionModeTraits<mode>::toContextType(cx),
-                               obj, obj, shape, setterIsStrict, &nvalue);
+        return NativeSet(cx->asJSContext(), obj, obj, shape, setterIsStrict, &nvalue);
     }
     return true;
 }
 
 static bool
 NativeLookupOwnProperty(ExclusiveContext *cx, HandleNativeObject obj, HandleId id,
                         MutableHandle<Shape*> shapep);
 
@@ -1427,24 +1369,24 @@ js::DefineNativeProperty(ExclusiveContex
                 if (!NativeObject::sparsifyDenseElement(cx, obj, JSID_TO_INT(id)))
                     return false;
                 shape = obj->lookup(cx, id);
             }
             if (shape->isAccessorDescriptor()) {
                 if (!CheckAccessorRedefinition(cx, obj, shape, getter, setter, id, attrs))
                     return false;
                 attrs = ApplyOrDefaultAttributes(attrs, shape);
-                shape = NativeObject::changeProperty<SequentialExecution>(cx, obj, shape, attrs,
-                                                                          JSPROP_GETTER | JSPROP_SETTER,
-                                                                          (attrs & JSPROP_GETTER)
-                                                                          ? getter
-                                                                          : shape->getter(),
-                                                                          (attrs & JSPROP_SETTER)
-                                                                          ? setter
-                                                                          : shape->setter());
+                shape = NativeObject::changeProperty(cx, obj, shape, attrs,
+                                                     JSPROP_GETTER | JSPROP_SETTER,
+                                                     (attrs & JSPROP_GETTER)
+                                                     ? getter
+                                                     : shape->getter(),
+                                                     (attrs & JSPROP_SETTER)
+                                                     ? setter
+                                                     : shape->setter());
                 if (!shape)
                     return false;
                 shouldDefine = false;
             }
         }
     } else if (!(attrs & JSPROP_IGNORE_VALUE)) {
         // If we did a normal lookup here, it would cause resolve hook recursion in
         // the following case. Suppose the first script we run in a lazy global is
@@ -1502,18 +1444,18 @@ js::DefineNativeProperty(ExclusiveContex
             {
                 return false;
             }
 
             attrs = ApplyOrDefaultAttributes(attrs, shape);
 
             /* Keep everything from the shape that isn't the things we're changing */
             unsigned attrMask = ~(JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT);
-            shape = NativeObject::changeProperty<SequentialExecution>(cx, obj, shape, attrs, attrMask,
-                                                                      shape->getter(), shape->setter());
+            shape = NativeObject::changeProperty(cx, obj, shape, attrs, attrMask,
+                                                 shape->getter(), shape->setter());
             if (!shape)
                 return false;
             if (shape->hasSlot())
                 updateValue = obj->getSlot(shape->slot());
             shouldDefine = false;
         }
     }
 
@@ -1524,25 +1466,25 @@ js::DefineNativeProperty(ExclusiveContex
     if (!PurgeScopeChain(cx, obj, id))
         return false;
 
     if (shouldDefine) {
         // Handle the default cases here. Anyone that wanted to set non-default attributes has
         // cleared the IGNORE flags by now. Since we can never get here with JSPROP_IGNORE_VALUE
         // relevant, just clear it.
         attrs = ApplyOrDefaultAttributes(attrs) & ~JSPROP_IGNORE_VALUE;
-        return DefinePropertyOrElement<SequentialExecution>(cx, obj, id, getter, setter,
-                                                            attrs, value, false, false);
+        return DefinePropertyOrElement(cx, obj, id, getter, setter,
+                                       attrs, value, false, false);
     }
 
     MOZ_ASSERT(shape);
 
-    JS_ALWAYS_TRUE(UpdateShapeTypeAndValue<SequentialExecution>(cx, obj, shape, updateValue));
+    JS_ALWAYS_TRUE(UpdateShapeTypeAndValue(cx, obj, shape, updateValue));
 
-    return CallAddPropertyHook<SequentialExecution>(cx, obj, shape, updateValue);
+    return CallAddPropertyHook(cx, obj, shape, updateValue);
 }
 
 static bool
 NativeLookupOwnProperty(ExclusiveContext *cx, HandleNativeObject obj, HandleId id,
                         MutableHandle<Shape*> shapep)
 {
     RootedObject pobj(cx);
     bool done;
@@ -1899,235 +1841,168 @@ MaybeReportUndeclaredVarAssignment(JSCon
 /*
  * When a [[Set]] operation finds no existing property with the given id
  * or finds a writable data property on the prototype chain, we end up here.
  * Finish the [[Set]] by defining a new property on receiver.
  *
  * This implements ES6 draft rev 28, 9.1.9 [[Set]] steps 5.c-f, but it
  * is really old code and there are a few barnacles.
  */
-template <ExecutionMode mode>
 static bool
-SetPropertyByDefining(typename ExecutionModeTraits<mode>::ContextType cxArg,
-                      HandleNativeObject obj, HandleObject receiver, HandleId id,
-                      HandleValue v, bool strict, bool objHasOwn)
+SetPropertyByDefining(JSContext *cx, HandleNativeObject obj, HandleObject receiver,
+                      HandleId id, HandleValue v, bool strict, bool objHasOwn)
 {
     // Step 5.c-d: Test whether receiver has an existing own property
     // receiver[id]. The spec calls [[GetOwnProperty]]; js::HasOwnProperty is
     // the same thing except faster in the non-proxy case. Sometimes we can
     // even optimize away the HasOwnProperty call.
     bool existing;
     if (receiver == obj) {
         // The common case. The caller has necessarily done a property lookup
         // on obj and passed us the answer as objHasOwn.
 #ifdef DEBUG
         // Check that objHasOwn is correct. This could fail if receiver or a
         // native object on its prototype chain has a nondeterministic resolve
         // hook. We shouldn't have any that are quite that badly behaved.
-        if (mode == SequentialExecution) {
-            if (!HasOwnProperty(cxArg->asJSContext(), receiver, id, &existing))
-                return false;
-            MOZ_ASSERT(existing == objHasOwn);
-        }
+        if (!HasOwnProperty(cx, receiver, id, &existing))
+            return false;
+        MOZ_ASSERT(existing == objHasOwn);
 #endif
         existing = objHasOwn;
-    } else if (mode == ParallelExecution) {
-        // Not the fastest possible implementation, but the fastest possible
-        // without refactoring LookupPropertyPure or duplicating code.
-        NativeObject *npobj;
-        Shape *shape;
-        if (!LookupPropertyPure(cxArg, receiver, id, &npobj, &shape))
-            return false;
-        existing = (npobj == receiver);
     } else {
-        if (!HasOwnProperty(cxArg->asJSContext(), receiver, id, &existing))
+        if (!HasOwnProperty(cx, receiver, id, &existing))
             return false;
     }
 
     // If the property doesn't already exist, check for an inextensible
     // receiver. (According to the specification, this is supposed to be
     // enforced by [[DefineOwnProperty]], but we haven't implemented that yet.)
     if (!existing) {
         bool extensible;
-        if (mode == ParallelExecution) {
-            if (receiver->is<ProxyObject>())
-                return false;
-            extensible = receiver->nonProxyIsExtensible();
-        } else {
-            if (!JSObject::isExtensible(cxArg->asJSContext(), receiver, &extensible))
-                return false;
-        }
+        if (!JSObject::isExtensible(cx, receiver, &extensible))
+            return false;
         if (!extensible) {
             // Error in strict mode code, warn with extra warnings option,
             // otherwise do nothing.
             if (strict)
-                return receiver->reportNotExtensible(cxArg);
-            if (mode == SequentialExecution &&
-                cxArg->asJSContext()->compartment()->options().extraWarnings(cxArg->asJSContext()))
-            {
-                return receiver->reportNotExtensible(cxArg, JSREPORT_STRICT | JSREPORT_WARNING);
-            }
+                return receiver->reportNotExtensible(cx);
+            if (cx->compartment()->options().extraWarnings(cx))
+                return receiver->reportNotExtensible(cx, JSREPORT_STRICT | JSREPORT_WARNING);
             return true;
         }
     }
 
     // Invalidate SpiderMonkey-specific caches or bail.
     const Class *clasp = receiver->getClass();
-    if (mode == ParallelExecution) {
-        if (receiver->isDelegate())
-            return false;
 
-        if (clasp->getProperty || !types::HasTypePropertyId(receiver, id, v))
-            return false;
-    } else {
-        // Purge the property cache of now-shadowed id in receiver's scope chain.
-        if (!PurgeScopeChain(cxArg->asJSContext(), receiver, id))
-            return false;
-    }
+    // Purge the property cache of now-shadowed id in receiver's scope chain.
+    if (!PurgeScopeChain(cx, receiver, id))
+        return false;
 
     // Step 5.e-f. Define the new data property.
     unsigned attrs =
         existing
         ? JSPROP_IGNORE_ENUMERATE | JSPROP_IGNORE_READONLY | JSPROP_IGNORE_PERMANENT
         : JSPROP_ENUMERATE;
     JSPropertyOp getter = clasp->getProperty;
     JSStrictPropertyOp setter = clasp->setProperty;
     MOZ_ASSERT(getter != JS_PropertyStub);
     MOZ_ASSERT(setter != JS_StrictPropertyStub);
-    if (!receiver->is<NativeObject>()) {
-        if (mode == ParallelExecution)
-            return false;
-        return JSObject::defineGeneric(cxArg->asJSContext(), receiver, id, v, getter, setter,
-                                       attrs);
-    }
-    Rooted<NativeObject*> nativeReceiver(cxArg, &receiver->as<NativeObject>());
-    return DefinePropertyOrElement<mode>(cxArg, nativeReceiver, id, getter, setter,
-                                         attrs, v, true, strict);
+    if (!receiver->is<NativeObject>())
+        return JSObject::defineGeneric(cx, receiver, id, v, getter, setter, attrs);
+
+    Rooted<NativeObject*> nativeReceiver(cx, &receiver->as<NativeObject>());
+    return DefinePropertyOrElement(cx, nativeReceiver, id, getter, setter, attrs, v, true, strict);
 }
 
 /*
  * Implement "the rest of" assignment to a property when no property receiver[id]
  * was found anywhere on the prototype chain.
  *
  * FIXME: This should be updated to follow ES6 draft rev 28, section 9.1.9,
  * steps 4.d.i and 5.
  *
  * Note that receiver is not necessarily native.
  */
-template <ExecutionMode mode>
 static bool
-SetNonexistentProperty(typename ExecutionModeTraits<mode>::ContextType cxArg,
-                       HandleNativeObject obj, HandleObject receiver, HandleId id,
+SetNonexistentProperty(JSContext *cx, HandleNativeObject obj, HandleObject receiver, HandleId id,
                        baseops::QualifiedBool qualified, HandleValue v, bool strict)
 {
     // We should never add properties to lexical blocks.
     MOZ_ASSERT(!receiver->is<BlockObject>());
 
     if (receiver->isUnqualifiedVarObj() && !qualified) {
-        if (mode == ParallelExecution)
-            return false;
-
-        if (!MaybeReportUndeclaredVarAssignment(cxArg->asJSContext(), JSID_TO_STRING(id)))
+        if (!MaybeReportUndeclaredVarAssignment(cx, JSID_TO_STRING(id)))
             return false;
     }
 
-    return SetPropertyByDefining<mode>(cxArg, obj, receiver, id, v, strict, false);
+    return SetPropertyByDefining(cx, obj, receiver, id, v, strict, false);
 }
 
 /*
  * Set an existing own property obj[index] that's a dense element or typed
  * array element.
  */
-template <ExecutionMode mode>
 static bool
-SetDenseOrTypedArrayElement(typename ExecutionModeTraits<mode>::ContextType cxArg,
-                            HandleNativeObject obj, uint32_t index, MutableHandleValue vp,
-                            bool strict)
+SetDenseOrTypedArrayElement(JSContext *cx, HandleNativeObject obj, uint32_t index,
+                            MutableHandleValue vp, bool strict)
 {
     if (IsAnyTypedArray(obj)) {
         double d;
-        if (mode == ParallelExecution) {
-            // Bail if converting the value might invoke user-defined
-            // conversions.
-            if (vp.isObject())
-                return false;
-            if (!NonObjectToNumber(cxArg, vp, &d))
-                return false;
-        } else {
-            if (!ToNumber(cxArg->asJSContext(), vp, &d))
-                return false;
-        }
+        if (!ToNumber(cx, vp, &d))
+            return false;
 
         // Silently do nothing for out-of-bounds sets, for consistency with
         // current behavior.  (ES6 currently says to throw for this in
         // strict mode code, so we may eventually need to change.)
         uint32_t len = AnyTypedArrayLength(obj);
         if (index < len) {
             if (obj->is<TypedArrayObject>())
                 TypedArrayObject::setElement(obj->as<TypedArrayObject>(), index, d);
             else
                 SharedTypedArrayObject::setElement(obj->as<SharedTypedArrayObject>(), index, d);
         }
         return true;
     }
 
     bool definesPast;
-    if (!WouldDefinePastNonwritableLength(cxArg, obj, index, strict, &definesPast))
+    if (!WouldDefinePastNonwritableLength(cx, obj, index, strict, &definesPast))
         return false;
-    if (definesPast) {
-        /* Bail out of parallel execution if we are strict to throw. */
-        if (mode == ParallelExecution)
-            return !strict;
+    if (definesPast)
         return true;
-    }
 
-    if (!obj->maybeCopyElementsForWrite(cxArg))
+    if (!obj->maybeCopyElementsForWrite(cx))
         return false;
 
-    if (mode == ParallelExecution)
-        return obj->setDenseElementIfHasType(index, vp);
-
-    obj->setDenseElementWithType(cxArg->asJSContext(), index, vp);
+    obj->setDenseElementWithType(cx, index, vp);
     return true;
 }
 
 /*
  * Finish assignment to a shapeful property of a native object obj. This
  * conforms to no standard and there is a lot of legacy baggage here.
  */
-template <ExecutionMode mode>
 static bool
-NativeSet(typename ExecutionModeTraits<mode>::ContextType cxArg, HandleNativeObject obj,
-          HandleObject receiver, HandleShape shape, bool strict, MutableHandleValue vp)
+NativeSet(JSContext *cx, HandleNativeObject obj, HandleObject receiver,
+          HandleShape shape, bool strict, MutableHandleValue vp)
 {
-    MOZ_ASSERT(cxArg->isThreadLocal(obj));
     MOZ_ASSERT(obj->isNative());
 
     if (shape->hasSlot()) {
         /* If shape has a stub setter, just store vp. */
         if (shape->hasDefaultSetter()) {
-            if (mode == ParallelExecution) {
-                if (!obj->setSlotIfHasType(shape, vp))
-                    return false;
-            } else {
-                // Global properties declared with 'var' will be initially
-                // defined with an undefined value, so don't treat the initial
-                // assignments to such properties as overwrites.
-                bool overwriting = !obj->is<GlobalObject>() || !obj->getSlot(shape->slot()).isUndefined();
-                obj->setSlotWithType(cxArg->asExclusiveContext(), shape, vp, overwriting);
-            }
-
+            // Global properties declared with 'var' will be initially
+            // defined with an undefined value, so don't treat the initial
+            // assignments to such properties as overwrites.
+            bool overwriting = !obj->is<GlobalObject>() || !obj->getSlot(shape->slot()).isUndefined();
+            obj->setSlotWithType(cx, shape, vp, overwriting);
             return true;
         }
     }
 
-    if (mode == ParallelExecution)
-        return false;
-    JSContext *cx = cxArg->asJSContext();
-
     if (!shape->hasSlot()) {
         /*
          * Allow API consumers to create shared properties with stub setters.
          * Such properties effectively function as data descriptors which are
          * not writable, so attempting to set such a property should do nothing
          * or throw if we're in strict mode.
          */
         if (!shape->hasGetterValue() && shape->hasDefaultSetter())
@@ -2156,205 +2031,152 @@ NativeSet(typename ExecutionModeTraits<m
 
 /*
  * Implement "the rest of" assignment to receiver[id] when an existing property
  * (shape) has been found on a native object (pobj).
  *
  * It is necessary to pass both id and shape because shape could be an implicit
  * dense or typed array element (i.e. not actually a pointer to a Shape).
  */
-template <ExecutionMode mode>
 static bool
-SetExistingProperty(typename ExecutionModeTraits<mode>::ContextType cxArg,
-                    HandleNativeObject obj, HandleObject receiver, HandleId id,
+SetExistingProperty(JSContext *cx, HandleNativeObject obj, HandleObject receiver, HandleId id,
                     HandleNativeObject pobj, HandleShape shape, MutableHandleValue vp, bool strict)
 {
     if (IsImplicitDenseOrTypedArrayElement(shape)) {
         /* ES5 8.12.4 [[Put]] step 2, for a dense data property on pobj. */
         if (pobj == receiver)
-            return SetDenseOrTypedArrayElement<mode>(cxArg, pobj, JSID_TO_INT(id), vp, strict);
+            return SetDenseOrTypedArrayElement(cx, pobj, JSID_TO_INT(id), vp, strict);
     } else {
         /* ES5 8.12.4 [[Put]] step 2. */
         if (shape->isAccessorDescriptor()) {
-            if (shape->hasDefaultSetter()) {
-                /* Bail out of parallel execution if we are strict to throw. */
-                if (mode == ParallelExecution)
-                    return !strict;
-
-                return js_ReportGetterOnlyAssignment(cxArg->asJSContext(), strict);
-            }
+            if (shape->hasDefaultSetter())
+                return js_ReportGetterOnlyAssignment(cx, strict);
         } else {
             MOZ_ASSERT(shape->isDataDescriptor());
 
             if (!shape->writable()) {
                 /*
                  * Error in strict mode code, warn with extra warnings
                  * options, otherwise do nothing.
-                 *
-                 * Bail out of parallel execution if we are strict to throw.
                  */
-                if (mode == ParallelExecution)
-                    return !strict;
 
-                JSContext *cx = cxArg->asJSContext();
                 if (strict)
                     return JSObject::reportReadOnly(cx, id, JSREPORT_ERROR);
                 if (cx->compartment()->options().extraWarnings(cx))
                     return JSObject::reportReadOnly(cx, id, JSREPORT_STRICT | JSREPORT_WARNING);
                 return true;
             }
         }
 
         if (pobj == receiver) {
-            if (pobj->is<ArrayObject>() && id == NameToId(cxArg->names().length)) {
-                Rooted<ArrayObject*> arr(cxArg, &pobj->as<ArrayObject>());
-                return ArraySetLength<mode>(cxArg, arr, id, shape->attributes(), vp, strict);
+            if (pobj->is<ArrayObject>() && id == NameToId(cx->names().length)) {
+                Rooted<ArrayObject*> arr(cx, &pobj->as<ArrayObject>());
+                return ArraySetLength(cx, arr, id, shape->attributes(), vp, strict);
             }
-            return NativeSet<mode>(cxArg, obj, receiver, shape, strict, vp);
+            return NativeSet(cx, obj, receiver, shape, strict, vp);
         }
 
         // pobj[id] is not an own property of receiver. Call the setter or shadow it.
         if (!shape->shadowable() &&
-            !(pobj->is<ArrayObject>() && id == NameToId(cxArg->names().length)))
+            !(pobj->is<ArrayObject>() && id == NameToId(cx->names().length)))
         {
             // Weird special case: slotless property with default setter.
             if (shape->hasDefaultSetter() && !shape->hasGetterValue())
                 return true;
 
-            // We're setting an accessor property.
-            if (mode == ParallelExecution)
-                return false;
-            return shape->set(cxArg->asJSContext(), obj, receiver, strict, vp);
+            return shape->set(cx, obj, receiver, strict, vp);
         }
     }
 
     // Shadow pobj[id] by defining a new data property receiver[id].
-    return SetPropertyByDefining<mode>(cxArg, obj, receiver, id, vp, strict, obj == pobj);
+    return SetPropertyByDefining(cx, obj, receiver, id, vp, strict, obj == pobj);
 }
 
-template <ExecutionMode mode>
 bool
-baseops::SetPropertyHelper(typename ExecutionModeTraits<mode>::ContextType cxArg,
-                           HandleNativeObject obj, HandleObject receiver, HandleId id,
-                           QualifiedBool qualified, MutableHandleValue vp, bool strict)
+baseops::SetPropertyHelper(JSContext *cx, HandleNativeObject obj, HandleObject receiver,
+                           HandleId id, QualifiedBool qualified, MutableHandleValue vp,
+                           bool strict)
 {
-    MOZ_ASSERT(cxArg->isThreadLocal(obj));
-
     // Fire watchpoints, if any.
     if (MOZ_UNLIKELY(obj->watched())) {
-        if (mode == ParallelExecution)
-            return false;
-
-        JSContext *cx = cxArg->asJSContext();
         WatchpointMap *wpmap = cx->compartment()->watchpointMap;
         if (wpmap && !wpmap->triggerWatchpoint(cx, obj, id, vp))
             return false;
     }
 
     // Step numbers below reference ES6 rev 27 9.1.9, the [[Set]] internal
     // method for ordinary objects. We substitute our own names for these names
     // used in the spec: O -> pobj, P -> id, V -> *vp, ownDesc -> shape.
-    RootedShape shape(cxArg);
-    RootedNativeObject pobj(cxArg, obj);
+    RootedShape shape(cx);
+    RootedNativeObject pobj(cx, obj);
 
     // This loop isn't explicit in the spec algorithm. See the comment on step
     // 4.c.i below.
     for (;;) {
         // Steps 2-3. ('done' is a SpiderMonkey-specific thing, used below.)
         bool done;
-        if (mode == ParallelExecution) {
-            // Use the loop in LookupPropertyPure instead of this loop.
-            // It amounts to the same thing.
-            NativeObject *ancestor;
-            if (!LookupPropertyPure(cxArg, pobj, id, &ancestor, shape.address()))
-                return false;
-            done = true;
-            if (shape)
-                pobj = ancestor;
-        } else {
-            RootedObject ancestor(cxArg);
-            if (!LookupOwnPropertyInline<CanGC>(cxArg->asJSContext(), pobj, id, &ancestor,
-                                                &shape, &done))
-            {
-                return false;
-            }
-            if (!done || ancestor != pobj)
-                shape = nullptr;
-        }
+        RootedObject ancestor(cx);
+        if (!LookupOwnPropertyInline<CanGC>(cx, pobj, id, &ancestor, &shape, &done))
+            return false;
+
+        if (!done || ancestor != pobj)
+            shape = nullptr;
 
         if (shape) {
             // Steps 5-6.
-            return SetExistingProperty<mode>(cxArg, obj, receiver, id, pobj, shape, vp, strict);
+            return SetExistingProperty(cx, obj, receiver, id, pobj, shape, vp, strict);
         }
 
         // Steps 4.a-b. The check for 'done' on this next line is tricky.
         // done can be true in exactly these unlikely-sounding cases:
         // - We're looking up an element, and pobj is a TypedArray that
         //   doesn't have that many elements.
         // - We're being called from a resolve hook to assign to the property
         //   being resolved.
         // - We're running in parallel mode so we've already done the whole
         //   lookup (in LookupPropertyPure above).
         // What they all have in common is we do not want to keep walking
         // the prototype chain.
-        RootedObject proto(cxArg, done ? nullptr : pobj->getProto());
+        RootedObject proto(cx, done ? nullptr : pobj->getProto());
         if (!proto) {
             // Step 4.d.i (and step 5).
-            return SetNonexistentProperty<mode>(cxArg, obj, receiver, id, qualified, vp, strict);
+            return SetNonexistentProperty(cx, obj, receiver, id, qualified, vp, strict);
         }
 
         // Step 4.c.i. If the prototype is also native, this step is a
         // recursive tail call, and we don't need to go through all the
         // plumbing of JSObject::setGeneric; the top of the loop is where
         // we're going to end up anyway. But if pobj is non-native,
         // that optimization would be incorrect.
         if (!proto->isNative()) {
-            if (mode == ParallelExecution)
-                return false;
-
             // Unqualified assignments are not specified to go through [[Set]]
             // at all, but they do go through this function. So check for
             // unqualified assignment to a nonexistent global (a strict error).
             if (!qualified) {
-                RootedObject pobj(cxArg);
-                if (!JSObject::lookupGeneric(cxArg->asJSContext(), proto, id, &pobj, &shape))
+                RootedObject pobj(cx);
+                if (!JSObject::lookupGeneric(cx, proto, id, &pobj, &shape))
                     return false;
-                if (!shape) {
-                    return SetNonexistentProperty<mode>(cxArg, obj, receiver, id, qualified, vp,
-                                                        strict);
-                }
+                if (!shape)
+                    return SetNonexistentProperty(cx, obj, receiver, id, qualified, vp, strict);
             }
 
-            return JSObject::setGeneric(cxArg->asJSContext(), proto, receiver, id, vp,
-                                        strict);
+            return JSObject::setGeneric(cx, proto, receiver, id, vp, strict);
         }
         pobj = &proto->as<NativeObject>();
     }
 }
 
-template bool
-baseops::SetPropertyHelper<SequentialExecution>(JSContext *cx, HandleNativeObject obj,
-                                                HandleObject receiver, HandleId id,
-                                                QualifiedBool qualified,
-                                                MutableHandleValue vp, bool strict);
-template bool
-baseops::SetPropertyHelper<ParallelExecution>(ForkJoinContext *cx, HandleNativeObject obj,
-                                              HandleObject receiver, HandleId id,
-                                              QualifiedBool qualified,
-                                              MutableHandleValue vp, bool strict);
-
 bool
 baseops::SetElementHelper(JSContext *cx, HandleNativeObject obj, HandleObject receiver, uint32_t index,
                           MutableHandleValue vp, bool strict)
 {
     RootedId id(cx);
     if (!IndexToId(cx, index, &id))
         return false;
-    return baseops::SetPropertyHelper<SequentialExecution>(cx, obj, receiver, id, Qualified, vp,
-                                                           strict);
+    return baseops::SetPropertyHelper(cx, obj, receiver, id, Qualified, vp, strict);
 }
 
 bool
 baseops::GetAttributes(JSContext *cx, HandleNativeObject obj, HandleId id, unsigned *attrsp)
 {
     RootedObject nobj(cx);
     RootedShape shape(cx);
     if (!baseops::LookupProperty<CanGC>(cx, obj, id, &nobj, &shape))
--- a/js/src/vm/NativeObject.h
+++ b/js/src/vm/NativeObject.h
@@ -81,20 +81,18 @@ class ArrayObject;
 /*
  * ES6 20130308 draft 8.4.2.4 ArraySetLength.
  *
  * |id| must be "length", |attrs| are the attributes to be used for the newly-
  * changed length property, |value| is the value for the new length, and
  * |setterIsStrict| indicates whether invalid changes will cause a TypeError
  * to be thrown.
  */
-template <ExecutionMode mode>
 extern bool
-ArraySetLength(typename ExecutionModeTraits<mode>::ContextType cx,
-               Handle<ArrayObject*> obj, HandleId id,
+ArraySetLength(JSContext *cx, Handle<ArrayObject*> obj, HandleId id,
                unsigned attrs, HandleValue value, bool setterIsStrict);
 
 /*
  * Elements header used for native objects. The elements component of such objects
  * offers an efficient representation for all or some of the indexed properties
  * of the object, using a flat array of Values rather than a shape hierarchy
  * stored in the object's slots. This structure is immediately followed by an
  * array of elements, with the elements member in an object pointing to the
@@ -182,20 +180,18 @@ class ObjectElements
     };
 
   private:
     friend class ::JSObject;
     friend class NativeObject;
     friend class ArrayObject;
     friend class Nursery;
 
-    template <ExecutionMode mode>
     friend bool
-    ArraySetLength(typename ExecutionModeTraits<mode>::ContextType cx,
-                   Handle<ArrayObject*> obj, HandleId id,
+    ArraySetLength(JSContext *cx, Handle<ArrayObject*> obj, HandleId id,
                    unsigned attrs, HandleValue value, bool setterIsStrict);
 
     /* See Flags enum above. */
     uint32_t flags;
 
     /*
      * Number of initialized elements. This is <= the capacity, and for arrays
      * is <= the length. Memory for elements above the initialized length is
@@ -398,52 +394,52 @@ class NativeObject : public JSObject
     uint32_t getDenseCapacity() {
         return getElementsHeader()->capacity;
     }
 
     /*
      * Update the last property, keeping the number of allocated slots in sync
      * with the object's new slot span.
      */
-    static bool setLastProperty(ThreadSafeContext *cx,
+    static bool setLastProperty(ExclusiveContext *cx,
                                 HandleNativeObject obj, HandleShape shape);
 
     // As for setLastProperty(), but allows the number of fixed slots to
     // change. This can only be used when fixed slots are being erased from the
     // object, and only when the object will not require dynamic slots to cover
     // the new properties.
     void setLastPropertyShrinkFixedSlots(Shape *shape);
 
   protected:
 #ifdef DEBUG
     void checkShapeConsistency();
 #else
     void checkShapeConsistency() { }
 #endif
 
     Shape *
-    replaceWithNewEquivalentShape(ThreadSafeContext *cx,
+    replaceWithNewEquivalentShape(ExclusiveContext *cx,
                                   Shape *existingShape, Shape *newShape = nullptr,
                                   bool accessorShape = false);
 
     /*
      * Remove the last property of an object, provided that it is safe to do so
      * (the shape and previous shape do not carry conflicting information about
      * the object itself).
      */
     inline void removeLastProperty(ExclusiveContext *cx);
     inline bool canRemoveLastProperty();
 
     /*
      * Update the slot span directly for a dictionary object, and allocate
      * slots to cover the new span if necessary.
      */
-    static bool setSlotSpan(ThreadSafeContext *cx, HandleNativeObject obj, uint32_t span);
+    static bool setSlotSpan(ExclusiveContext *cx, HandleNativeObject obj, uint32_t span);
 
-    bool toDictionaryMode(ThreadSafeContext *cx);
+    bool toDictionaryMode(ExclusiveContext *cx);
 
   private:
     friend class Nursery;
 
     /*
      * Get internal pointers to the range of values starting at start and
      * running for length.
      */
@@ -529,17 +525,17 @@ class NativeObject : public JSObject
      */
     static const uint32_t SLOT_CAPACITY_MIN = 8;
 
     HeapSlot *fixedSlots() const {
         return reinterpret_cast<HeapSlot *>(uintptr_t(this) + sizeof(NativeObject));
     }
 
   public:
-    bool generateOwnShape(ThreadSafeContext *cx, Shape *newShape = nullptr) {
+    bool generateOwnShape(ExclusiveContext *cx, Shape *newShape = nullptr) {
         return replaceWithNewEquivalentShape(cx, lastProperty(), newShape);
     }
 
     bool shadowingShapeChange(ExclusiveContext *cx, const Shape &shape);
     bool clearFlag(ExclusiveContext *cx, BaseShape::Flag flag);
 
     static void slotsSizeMustNotOverflow() {
         static_assert((NativeObject::NELEMENTS_LIMIT - 1) <= INT32_MAX / sizeof(JS::Value),
@@ -574,19 +570,19 @@ class NativeObject : public JSObject
         return slot - numFixedSlots();
     }
 
     /*
      * Grow or shrink slots immediately before changing the slot span.
      * The number of allocated slots is not stored explicitly, and changes to
      * the slots must track changes in the slot span.
      */
-    static bool growSlots(ThreadSafeContext *cx, HandleNativeObject obj, uint32_t oldCount,
+    static bool growSlots(ExclusiveContext *cx, HandleNativeObject obj, uint32_t oldCount,
                           uint32_t newCount);
-    static void shrinkSlots(ThreadSafeContext *cx, HandleNativeObject obj, uint32_t oldCount,
+    static void shrinkSlots(ExclusiveContext *cx, HandleNativeObject obj, uint32_t oldCount,
                             uint32_t newCount);
 
     bool hasDynamicSlots() const { return !!slots_; }
 
     /* Compute dynamicSlotsCount() for this object. */
     uint32_t numDynamicSlots() const {
         return dynamicSlotsCount(numFixedSlots(), slotSpan(), getClass());
     }
@@ -628,75 +624,54 @@ class NativeObject : public JSObject
 
     /*
      * Allocate and free an object slot.
      *
      * FIXME: bug 593129 -- slot allocation should be done by object methods
      * after calling object-parameter-free shape methods, avoiding coupling
      * logic across the object vs. shape module wall.
      */
-    static bool allocSlot(ThreadSafeContext *cx, HandleNativeObject obj, uint32_t *slotp);
+    static bool allocSlot(ExclusiveContext *cx, HandleNativeObject obj, uint32_t *slotp);
     void freeSlot(uint32_t slot);
 
   private:
-    static Shape *getChildPropertyOnDictionary(ThreadSafeContext *cx, HandleNativeObject obj,
+    static Shape *getChildPropertyOnDictionary(ExclusiveContext *cx, HandleNativeObject obj,
                                                HandleShape parent, StackShape &child);
     static Shape *getChildProperty(ExclusiveContext *cx, HandleNativeObject obj,
                                    HandleShape parent, StackShape &child);
-    template <ExecutionMode mode>
-    static inline Shape *
-    getOrLookupChildProperty(typename ExecutionModeTraits<mode>::ExclusiveContextType cx,
-                             HandleNativeObject obj, HandleShape parent, StackShape &child)
-    {
-        if (mode == ParallelExecution)
-            return lookupChildProperty(cx, obj, parent, child);
-        return getChildProperty(cx->asExclusiveContext(), obj, parent, child);
-    }
 
   public:
-    /*
-     * XXX: This should be private, but is public because it needs to be a
-     * friend of ThreadSafeContext to get to the propertyTree on cx->compartment_.
-     */
-    static Shape *lookupChildProperty(ThreadSafeContext *cx, HandleNativeObject obj,
-                                      HandleShape parent, StackShape &child);
-
     /* Add a property whose id is not yet in this scope. */
     static Shape *addProperty(ExclusiveContext *cx, HandleNativeObject obj, HandleId id,
                               JSPropertyOp getter, JSStrictPropertyOp setter,
                               uint32_t slot, unsigned attrs, unsigned flags,
                               bool allowDictionary = true);
 
     /* Add a data property whose id is not yet in this scope. */
     Shape *addDataProperty(ExclusiveContext *cx,
                            jsid id_, uint32_t slot, unsigned attrs);
     Shape *addDataProperty(ExclusiveContext *cx, HandlePropertyName name,
                            uint32_t slot, unsigned attrs);
 
     /* Add or overwrite a property for id in this scope. */
-    template <ExecutionMode mode>
     static Shape *
-    putProperty(typename ExecutionModeTraits<mode>::ExclusiveContextType cx,
-                HandleNativeObject obj, HandleId id,
+    putProperty(ExclusiveContext *cx, HandleNativeObject obj, HandleId id,
                 JSPropertyOp getter, JSStrictPropertyOp setter,
                 uint32_t slot, unsigned attrs,
                 unsigned flags);
-    template <ExecutionMode mode>
     static inline Shape *
-    putProperty(typename ExecutionModeTraits<mode>::ExclusiveContextType cx,
-                HandleObject obj, PropertyName *name,
+    putProperty(ExclusiveContext *cx, HandleObject obj, PropertyName *name,
                 JSPropertyOp getter, JSStrictPropertyOp setter,
                 uint32_t slot, unsigned attrs,
                 unsigned flags);
 
     /* Change the given property into a sibling with the same id in this scope. */
-    template <ExecutionMode mode>
     static Shape *
-    changeProperty(typename ExecutionModeTraits<mode>::ExclusiveContextType cx,
-                   HandleNativeObject obj, HandleShape shape, unsigned attrs, unsigned mask,
+    changeProperty(ExclusiveContext *cx, HandleNativeObject obj,
+                   HandleShape shape, unsigned attrs, unsigned mask,
                    JSPropertyOp getter, JSStrictPropertyOp setter);
 
     static inline bool changePropertyAttributes(JSContext *cx, HandleNativeObject obj,
                                                 HandleShape shape, unsigned attrs);
 
     /* Remove the property named by id from this object. */
     bool removeProperty(ExclusiveContext *cx, jsid id);
 
@@ -706,20 +681,18 @@ class NativeObject : public JSObject
   protected:
     /*
      * Internal helper that adds a shape not yet mapped by this object.
      *
      * Notes:
      * 1. getter and setter must be normalized based on flags (see jsscope.cpp).
      * 2. Checks for non-extensibility must be done by callers.
      */
-    template <ExecutionMode mode>
     static Shape *
-    addPropertyInternal(typename ExecutionModeTraits<mode>::ExclusiveContextType cx,
-                        HandleNativeObject obj, HandleId id,
+    addPropertyInternal(ExclusiveContext *cx, HandleNativeObject obj, HandleId id,
                         JSPropertyOp getter, JSStrictPropertyOp setter,
                         uint32_t slot, unsigned attrs, unsigned flags, Shape **spp,
                         bool allowDictionary);
 
     void fillInAfterSwap(JSContext *cx, const Vector<Value> &values, void *priv);
 
   public:
     // Return true if this object has been converted from shared-immutable
@@ -798,17 +771,17 @@ class NativeObject : public JSObject
         getSlotAddressUnchecked(slot)->init(this, HeapSlot::Slot, slot, value);
     }
 
     // MAX_FIXED_SLOTS is the biggest number of fixed slots our GC
     // size classes will give an object.
     static const uint32_t MAX_FIXED_SLOTS = 16;
 
   protected:
-    static inline bool updateSlotsForSpan(ThreadSafeContext *cx,
+    static inline bool updateSlotsForSpan(ExclusiveContext *cx,
                                           HandleNativeObject obj, size_t oldSpan, size_t newSpan);
 
   public:
     /*
      * Trigger the write barrier on a range of slots that will no longer be
      * reachable.
      */
     void prepareSlotRangeForOverwrite(size_t start, size_t end) {
@@ -898,56 +871,54 @@ class NativeObject : public JSObject
                       "uint32_t (and sometimes int32_t ,too)");
     }
 
     ObjectElements * getElementsHeader() const {
         return ObjectElements::fromElements(elements_);
     }
 
     /* Accessors for elements. */
-    bool ensureElements(ThreadSafeContext *cx, uint32_t capacity) {
+    bool ensureElements(ExclusiveContext *cx, uint32_t capacity) {
         MOZ_ASSERT(!denseElementsAreCopyOnWrite());
         if (capacity > getDenseCapacity())
             return growElements(cx, capacity);
         return true;
     }
 
     static uint32_t goodAllocated(uint32_t n, uint32_t length);
-    bool growElements(ThreadSafeContext *cx, uint32_t newcap);
-    void shrinkElements(ThreadSafeContext *cx, uint32_t cap);
+    bool growElements(ExclusiveContext *cx, uint32_t newcap);
+    void shrinkElements(ExclusiveContext *cx, uint32_t cap);
     void setDynamicElements(ObjectElements *header) {
         MOZ_ASSERT(!hasDynamicElements());
         elements_ = header->elements();
         MOZ_ASSERT(hasDynamicElements());
     }
 
-    static bool CopyElementsForWrite(ThreadSafeContext *cx, NativeObject *obj);
+    static bool CopyElementsForWrite(ExclusiveContext *cx, NativeObject *obj);
 
-    bool maybeCopyElementsForWrite(ThreadSafeContext *cx) {
+    bool maybeCopyElementsForWrite(ExclusiveContext *cx) {
         if (denseElementsAreCopyOnWrite())
             return CopyElementsForWrite(cx, this);
         return true;
     }
 
   private:
-    inline void ensureDenseInitializedLengthNoPackedCheck(ThreadSafeContext *cx,
+    inline void ensureDenseInitializedLengthNoPackedCheck(ExclusiveContext *cx,
                                                           uint32_t index, uint32_t extra);
 
   public:
     void setDenseInitializedLength(uint32_t length) {
         MOZ_ASSERT(length <= getDenseCapacity());
         MOZ_ASSERT(!denseElementsAreCopyOnWrite());
         prepareElementRangeForOverwrite(length, getElementsHeader()->initializedLength);
         getElementsHeader()->initializedLength = length;
     }
 
     inline void ensureDenseInitializedLength(ExclusiveContext *cx,
                                              uint32_t index, uint32_t extra);
-    inline void ensureDenseInitializedLengthPreservePackedFlag(ThreadSafeContext *cx,
-                                                               uint32_t index, uint32_t extra);
     void setDenseElement(uint32_t index, const Value &val) {
         MOZ_ASSERT(index < getDenseInitializedLength());
         MOZ_ASSERT(!denseElementsAreCopyOnWrite());
         elements_[index].set(this, HeapSlot::Element, index, val);
     }
 
     void initDenseElement(uint32_t index, const Value &val) {
         MOZ_ASSERT(index < getDenseInitializedLength());
@@ -957,17 +928,16 @@ class NativeObject : public JSObject
 
     void setDenseElementMaybeConvertDouble(uint32_t index, const Value &val) {
         if (val.isInt32() && shouldConvertDoubleElements())
             setDenseElement(index, DoubleValue(val.toInt32()));
         else
             setDenseElement(index, val);
     }
 
-    inline bool setDenseElementIfHasType(uint32_t index, const Value &val);
     inline void setDenseElementWithType(ExclusiveContext *cx, uint32_t index,
                                         const Value &val);
     inline void initDenseElementWithType(ExclusiveContext *cx, uint32_t index,
                                          const Value &val);
     inline void setDenseElementHole(ExclusiveContext *cx, uint32_t index);
     static inline void removeDenseElementForSparseIndex(ExclusiveContext *cx,
                                                         HandleNativeObject obj, uint32_t index);
 
@@ -1063,27 +1033,21 @@ class NativeObject : public JSObject
      * ensureDenseElements ensures that the object can hold at least
      * index + extra elements. It returns ED_OK on success, ED_FAILED on
      * failure to grow the array, ED_SPARSE when the object is too sparse to
      * grow (this includes the case of index + extra overflow). In the last
      * two cases the object is kept intact.
      */
     enum EnsureDenseResult { ED_OK, ED_FAILED, ED_SPARSE };
 
-  private:
-    inline EnsureDenseResult ensureDenseElementsNoPackedCheck(ThreadSafeContext *cx,
-                                                              uint32_t index, uint32_t extra);
-
   public:
     inline EnsureDenseResult ensureDenseElements(ExclusiveContext *cx,
                                                  uint32_t index, uint32_t extra);
-    inline EnsureDenseResult ensureDenseElementsPreservePackedFlag(ThreadSafeContext *cx,
-                                                                   uint32_t index, uint32_t extra);
 
-    inline EnsureDenseResult extendDenseElements(ThreadSafeContext *cx,
+    inline EnsureDenseResult extendDenseElements(ExclusiveContext *cx,
                                                  uint32_t requiredCapacity, uint32_t extra);
 
     /* Convert a single dense element to a sparse property. */
     static bool sparsifyDenseElement(ExclusiveContext *cx,
                                      HandleNativeObject obj, uint32_t index);
 
     /* Convert all dense elements to sparse properties. */
     static bool sparsifyDenseElements(ExclusiveContext *cx, HandleNativeObject obj);
@@ -1316,25 +1280,22 @@ GetElement(JSContext *cx, HandleNativeOb
  *
  * Used as an argument to baseops::SetPropertyHelper.
  */
 enum QualifiedBool {
     Unqualified = 0,
     Qualified = 1
 };
 
-template <ExecutionMode mode>
 extern bool
-SetPropertyHelper(typename ExecutionModeTraits<mode>::ContextType cx,
-                  HandleNativeObject obj,
-                  HandleObject receiver, HandleId id, QualifiedBool qualified,
-                  MutableHandleValue vp, bool strict);
+SetPropertyHelper(JSContext *cx, HandleNativeObject obj, HandleObject receiver, HandleId id,
+                  QualifiedBool qualified, MutableHandleValue vp, bool strict);
 
 extern bool
-SetElementHelper(JSContext *cx, HandleNativeObject obj, HandleObject Receiver, uint32_t index,
+SetElementHelper(JSContext *cx, HandleNativeObject obj, HandleObject receiver, uint32_t index,
                  MutableHandleValue vp, bool strict);
 
 extern bool
 GetAttributes(JSContext *cx, HandleNativeObject obj, HandleId id, unsigned *attrsp);
 
 extern bool
 SetAttributes(JSContext *cx, HandleNativeObject obj, HandleId id, unsigned *attrsp);
 
@@ -1414,18 +1375,18 @@ JSObject::getGenericNoGC(JSContext *cx, 
 }
 
 /* static */ inline bool
 JSObject::setGeneric(JSContext *cx, js::HandleObject obj, js::HandleObject receiver,
                      js::HandleId id, js::MutableHandleValue vp, bool strict)
 {
     if (obj->getOps()->setGeneric)
         return nonNativeSetProperty(cx, obj, receiver, id, vp, strict);
-    return js::baseops::SetPropertyHelper<js::SequentialExecution>(
-        cx, obj.as<js::NativeObject>(), receiver, id, js::baseops::Qualified, vp, strict);
+    return js::baseops::SetPropertyHelper(cx, obj.as<js::NativeObject>(),
+                                          receiver, id, js::baseops::Qualified, vp, strict);
 }
 
 /* static */ inline bool
 JSObject::setElement(JSContext *cx, js::HandleObject obj, js::HandleObject receiver,
                      uint32_t index, js::MutableHandleValue vp, bool strict)
 {
     if (obj->getOps()->setElement)
         return nonNativeSetElement(cx, obj, receiver, index, vp, strict);
--- a/js/src/vm/ScopeObject.cpp
+++ b/js/src/vm/ScopeObject.cpp
@@ -331,20 +331,18 @@ DeclEnvObject::createTemplateObject(JSCo
     const Class *clasp = obj->getClass();
     unsigned attrs = JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY;
 
     JSPropertyOp getter = clasp->getProperty;
     JSStrictPropertyOp setter = clasp->setProperty;
     MOZ_ASSERT(getter != JS_PropertyStub);
     MOZ_ASSERT(setter != JS_StrictPropertyStub);
 
-    if (!NativeObject::putProperty<SequentialExecution>(cx, obj, id, getter, setter, lambdaSlot(),
-                                                        attrs, 0)) {
+    if (!NativeObject::putProperty(cx, obj, id, getter, setter, lambdaSlot(), attrs, 0))
         return nullptr;
-    }
 
     MOZ_ASSERT(!obj->hasDynamicSlots());
     return &obj->as<DeclEnvObject>();
 }
 
 DeclEnvObject *
 DeclEnvObject::create(JSContext *cx, HandleObject enclosing, HandleFunction callee)
 {
@@ -710,24 +708,24 @@ StaticBlockObject::addVar(ExclusiveConte
 
     /*
      * Don't convert this object to dictionary mode so that we can clone the
      * block's shape later.
      */
     uint32_t slot = JSSLOT_FREE(&BlockObject::class_) + index;
     uint32_t readonly = constant ? JSPROP_READONLY : 0;
     uint32_t propFlags = readonly | JSPROP_ENUMERATE | JSPROP_PERMANENT;
-    return NativeObject::addPropertyInternal<SequentialExecution>(cx, block, id,
-                                                                  /* getter = */ nullptr,
-                                                                  /* setter = */ nullptr,
-                                                                  slot,
-                                                                  propFlags,
-                                                                  /* attrs = */ 0,
-                                                                  spp,
-                                                                  /* allowDictionary = */ false);
+    return NativeObject::addPropertyInternal(cx, block, id,
+                                             /* getter = */ nullptr,
+                                             /* setter = */ nullptr,
+                                             slot,
+                                             propFlags,
+                                             /* attrs = */ 0,
+                                             spp,
+                                             /* allowDictionary = */ false);
 }
 
 const Class BlockObject::class_ = {
     "Block",
     JSCLASS_IMPLEMENTS_BARRIERS |
     JSCLASS_HAS_RESERVED_SLOTS(BlockObject::RESERVED_SLOTS) |
     JSCLASS_IS_ANONYMOUS
 };
--- a/js/src/vm/Shape-inl.h
+++ b/js/src/vm/Shape-inl.h
@@ -19,17 +19,17 @@
 
 #include "jsatominlines.h"
 #include "jscntxtinlines.h"
 #include "jsgcinlines.h"
 
 namespace js {
 
 inline
-StackBaseShape::StackBaseShape(ThreadSafeContext *cx, const Class *clasp,
+StackBaseShape::StackBaseShape(ExclusiveContext *cx, const Class *clasp,
                                JSObject *parent, JSObject *metadata, uint32_t objectFlags)
   : flags(objectFlags),
     clasp(clasp),
     parent(parent),
     metadata(metadata),
     compartment(cx->compartment_)
 {}
 
@@ -50,43 +50,16 @@ Shape::get(JSContext* cx, HandleObject r
 
 inline Shape *
 Shape::search(ExclusiveContext *cx, jsid id)
 {
     Shape **_;
     return search(cx, this, id, &_);
 }
 
-inline Shape *
-Shape::searchThreadLocal(ThreadSafeContext *cx, Shape *start, jsid id,
-                         Shape ***pspp, bool adding)
-{
-    /*
-     * Note that adding is a best-effort attempt to claim an entry in a shape
-     * table. In the sequential case, this can be done either when the object
-     * is in dictionary mode, or when it has been hashified.
-     *
-     * In parallel, an object that is in dictionary mode may be thread
-     * local. That is, it was converted to a dictionary in the current thread,
-     * with all its shapes cloned into the current thread, and its shape table
-     * allocated thread locally. In that case, we may add to the
-     * table. Otherwise it is not allowed.
-     */
-    MOZ_ASSERT_IF(adding, cx->isThreadLocal(start) && start->inDictionary());
-
-    if (start->inDictionary()) {
-        *pspp = start->table().search(id, adding);
-        return SHAPE_FETCH(*pspp);
-    }
-
-    *pspp = nullptr;
-
-    return searchNoHashify(start, id);
-}
-
 inline bool
 Shape::set(JSContext* cx, HandleObject obj, HandleObject receiver, bool strict,
            MutableHandleValue vp)
 {
     MOZ_ASSERT_IF(hasDefaultSetter(), hasGetterValue());
 
     if (attrs & JSPROP_SETTER) {
         Value fval = setterValue();
@@ -201,37 +174,37 @@ EmptyShape::ensureInitialCustomShape(Exc
     // Cache the initial shape for non-prototype objects, however, so that
     // future instances will begin life with that shape.
     RootedObject proto(cx, obj->getProto());
     EmptyShape::insertInitialShape(cx, shape, proto);
     return true;
 }
 
 inline
-AutoRooterGetterSetter::Inner::Inner(ThreadSafeContext *cx, uint8_t attrs,
+AutoRooterGetterSetter::Inner::Inner(ExclusiveContext *cx, uint8_t attrs,
                                      PropertyOp *pgetter_, StrictPropertyOp *psetter_)
   : CustomAutoRooter(cx), attrs(attrs),
     pgetter(pgetter_), psetter(psetter_)
 {
     MOZ_ASSERT_IF(attrs & JSPROP_GETTER, !IsPoisonedPtr(*pgetter));
     MOZ_ASSERT_IF(attrs & JSPROP_SETTER, !IsPoisonedPtr(*psetter));
 }
 
 inline
-AutoRooterGetterSetter::AutoRooterGetterSetter(ThreadSafeContext *cx, uint8_t attrs,
+AutoRooterGetterSetter::AutoRooterGetterSetter(ExclusiveContext *cx, uint8_t attrs,
                                                PropertyOp *pgetter, StrictPropertyOp *psetter
                                                MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
 {
     if (attrs & (JSPROP_GETTER | JSPROP_SETTER))
         inner.emplace(cx, attrs, pgetter, psetter);
     MOZ_GUARD_OBJECT_NOTIFIER_INIT;
 }
 
 inline
-AutoRooterGetterSetter::AutoRooterGetterSetter(ThreadSafeContext *cx, uint8_t attrs,
+AutoRooterGetterSetter::AutoRooterGetterSetter(ExclusiveContext *cx, uint8_t attrs,
                                                JSNative *pgetter, JSNative *psetter
                                                MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
 {
     if (attrs & (JSPROP_GETTER | JSPROP_SETTER)) {
         inner.emplace(cx, attrs, reinterpret_cast<PropertyOp *>(pgetter),
                       reinterpret_cast<StrictPropertyOp *>(psetter));
     }
     MOZ_GUARD_OBJECT_NOTIFIER_INIT;
--- a/js/src/vm/Shape.cpp
+++ b/js/src/vm/Shape.cpp
@@ -29,17 +29,17 @@ using namespace js;
 using namespace js::gc;
 
 using mozilla::CeilingLog2Size;
 using mozilla::DebugOnly;
 using mozilla::PodZero;
 using mozilla::RotateLeft;
 
 bool
-ShapeTable::init(ThreadSafeContext *cx, Shape *lastProp)
+ShapeTable::init(ExclusiveContext *cx, Shape *lastProp)
 {
     uint32_t sizeLog2 = CeilingLog2Size(entryCount);
     uint32_t size = JS_BIT(sizeLog2);
     if (entryCount >= size - (size >> 2))
         sizeLog2++;
     if (sizeLog2 < MIN_SIZE_LOG2)
         sizeLog2 = MIN_SIZE_LOG2;
 
@@ -98,17 +98,17 @@ Shape::insertIntoDictionary(HeapPtrShape
     setParent(dictp->get());
     if (parent)
         parent->listp = &parent;
     listp = (HeapPtrShape *) dictp;
     *dictp = this;
 }
 
 bool
-Shape::makeOwnBaseShape(ThreadSafeContext *cx)
+Shape::makeOwnBaseShape(ExclusiveContext *cx)
 {
     MOZ_ASSERT(!base()->isOwned());
     MOZ_ASSERT(cx->isThreadLocal(this));
     assertSameCompartmentDebugOnly(cx, compartment());
 
     BaseShape *nbase = js_NewGCBaseShape<NoGC>(cx);
     if (!nbase)
         return false;
@@ -137,17 +137,17 @@ Shape::handoffTableTo(Shape *shape)
 
     this->base_ = nbase->baseUnowned();
     nbase->adoptUnowned(shape->base()->toUnowned());
 
     shape->base_ = nbase;
 }
 
 /* static */ bool
-Shape::hashify(ThreadSafeContext *cx, Shape *shape)
+Shape::hashify(ExclusiveContext *cx, Shape *shape)
 {
     MOZ_ASSERT(!shape->hasTable());
 
     if (!shape->ensureOwnBaseShape(cx))
         return false;
 
     ShapeTable *table = cx->new_<ShapeTable>(shape->entryCount());
     if (!table)
@@ -257,17 +257,17 @@ ShapeTable::fixupAfterMovingGC()
         Shape *shape = SHAPE_FETCH(&entries[i]);
         if (shape && IsForwarded(shape))
             SHAPE_STORE_PRESERVING_COLLISION(&entries[i], Forwarded(shape));
     }
 }
 #endif
 
 bool
-ShapeTable::change(int log2Delta, ThreadSafeContext *cx)
+ShapeTable::change(int log2Delta, ExclusiveContext *cx)
 {
     MOZ_ASSERT(entries);
 
     /*
      * Grow, shrink, or compress by changing this->entries.
      */
     int oldlog2 = HASH_BITS - hashShift;
     int newlog2 = oldlog2 + log2Delta;
@@ -296,17 +296,17 @@ ShapeTable::change(int log2Delta, Thread
     }
 
     /* Finally, free the old entries storage. */
     js_free(oldTable);
     return true;
 }
 
 bool
-ShapeTable::grow(ThreadSafeContext *cx)
+ShapeTable::grow(ExclusiveContext *cx)
 {
     MOZ_ASSERT(needsToGrow());
 
     uint32_t size = capacity();
     int delta = removedCount < size >> 2;
 
     if (!change(delta, cx) && entryCount + removedCount == size - 1) {
         js_ReportOutOfMemory(cx);
@@ -340,17 +340,17 @@ Shape::replaceLastProperty(ExclusiveCont
 }
 
 /*
  * Get or create a property-tree or dictionary child property of |parent|,
  * which must be lastProperty() if inDictionaryMode(), else parent must be
  * one of lastProperty() or lastProperty()->parent.
  */
 /* static */ Shape *
-NativeObject::getChildPropertyOnDictionary(ThreadSafeContext *cx, HandleNativeObject obj,
+NativeObject::getChildPropertyOnDictionary(ExclusiveContext *cx, HandleNativeObject obj,
                                            HandleShape parent, StackShape &child)
 {
     /*
      * Shared properties have no slot, but slot_ will reflect that of parent.
      * Unshared properties allocate a slot here but may lose it due to a
      * JS_ClearScope call.
      */
     if (!child.hasSlot()) {
@@ -412,38 +412,18 @@ NativeObject::getChildProperty(Exclusive
         //MOZ_ASSERT_IF(parent != lastProperty(), parent == lastProperty()->parent);
         if (!setLastProperty(cx, obj, shape))
             return nullptr;
     }
 
     return shape;
 }
 
-/* static */ Shape *
-NativeObject::lookupChildProperty(ThreadSafeContext *cx,
-                                  HandleNativeObject obj, HandleShape parent, StackShape &unrootedChild)
-{
-    RootedGeneric<StackShape*> child(cx, &unrootedChild);
-    MOZ_ASSERT(cx->isThreadLocal(obj));
-
-    RootedShape shape(cx, getChildPropertyOnDictionary(cx, obj, parent, *child));
-
-    if (!obj->inDictionaryMode()) {
-        shape = cx->compartment_->propertyTree.lookupChild(cx, parent, *child);
-        if (!shape)
-            return nullptr;
-        if (!setLastProperty(cx, obj, shape))
-            return nullptr;
-    }
-
-    return shape;
-}
-
 bool
-js::NativeObject::toDictionaryMode(ThreadSafeContext *cx)
+js::NativeObject::toDictionaryMode(ExclusiveContext *cx)
 {
     MOZ_ASSERT(!inDictionaryMode());
 
     /* We allocate the shapes from cx->compartment(), so make sure it's right. */
     MOZ_ASSERT(cx->isInsideCurrentCompartment(this));
 
     /*
      * This function is thread safe as long as the object is thread local. It
@@ -517,45 +497,34 @@ NativeObject::addProperty(ExclusiveConte
             obj->reportNotExtensible(cx->asJSContext());
         return nullptr;
     }
 
     Shape **spp = nullptr;
     if (obj->inDictionaryMode())
         spp = obj->lastProperty()->table().search(id, true);
 
-    return addPropertyInternal<SequentialExecution>(cx, obj, id, getter, setter, slot, attrs,
-                                                    flags, spp, allowDictionary);
+    return addPropertyInternal(cx, obj, id, getter, setter, slot, attrs, flags, spp,
+                               allowDictionary);
 }
 
 static bool
 ShouldConvertToDictionary(JSObject *obj)
 {
     /*
      * Use a lower limit if this object is likely a hashmap (SETELEM was used
      * to set properties).
      */
     if (obj->hadElementsAccess())
         return obj->lastProperty()->entryCount() >= PropertyTree::MAX_HEIGHT_WITH_ELEMENTS_ACCESS;
     return obj->lastProperty()->entryCount() >= PropertyTree::MAX_HEIGHT;
 }
 
-template <ExecutionMode mode>
-static inline UnownedBaseShape *
-GetOrLookupUnownedBaseShape(typename ExecutionModeTraits<mode>::ExclusiveContextType cx,
-                            StackBaseShape &base)
-{
-    if (mode == ParallelExecution)
-        return BaseShape::lookupUnowned(cx, base);
-    return BaseShape::getUnowned(cx->asExclusiveContext(), base);
-}
-
-template <ExecutionMode mode>
 /* static */ Shape *
-NativeObject::addPropertyInternal(typename ExecutionModeTraits<mode>::ExclusiveContextType cx,
+NativeObject::addPropertyInternal(ExclusiveContext *cx,
                                   HandleNativeObject obj, HandleId id,
                                   PropertyOp getter, StrictPropertyOp setter,
                                   uint32_t slot, unsigned attrs,
                                   unsigned flags, Shape **spp,
                                   bool allowDictionary)
 {
     MOZ_ASSERT(cx->isThreadLocal(obj));
     MOZ_ASSERT_IF(!allowDictionary, !obj->inDictionaryMode());
@@ -605,24 +574,24 @@ NativeObject::addPropertyInternal(typena
         bool indexed = js_IdIsIndex(id, &index);
 
         Rooted<UnownedBaseShape*> nbase(cx);
         if (!indexed) {
             nbase = last->base()->unowned();
         } else {
             StackBaseShape base(last->base());
             base.flags |= BaseShape::INDEXED;
-            nbase = GetOrLookupUnownedBaseShape<mode>(cx, base);
+            nbase = BaseShape::getUnowned(cx, base);
             if (!nbase)
                 return nullptr;
         }
 
         StackShape child(nbase, id, slot, attrs, flags);
         child.updateGetterSetter(getter, setter);
-        shape = getOrLookupChildProperty<mode>(cx, obj, last, child);
+        shape = getChildProperty(cx, obj, last, child);
     }
 
     if (shape) {
         MOZ_ASSERT(shape == obj->lastProperty());
 
         if (table) {
             /* Store the tree node pointer in the table entry for id. */
             SHAPE_STORE_PRESERVING_COLLISION(spp, static_cast<Shape *>(shape));
@@ -636,31 +605,16 @@ NativeObject::addPropertyInternal(typena
         obj->checkShapeConsistency();
         return shape;
     }
 
     obj->checkShapeConsistency();
     return nullptr;
 }
 
-template /* static */ Shape *
-NativeObject::addPropertyInternal<SequentialExecution>(ExclusiveContext *cx,
-                                                       HandleNativeObject obj, HandleId id,
-                                                       PropertyOp getter, StrictPropertyOp setter,
-                                                       uint32_t slot, unsigned attrs,
-                                                       unsigned flags, Shape **spp,
-                                                       bool allowDictionary);
-template /* static */ Shape *
-NativeObject::addPropertyInternal<ParallelExecution>(ForkJoinContext *cx,
-                                                     HandleNativeObject obj, HandleId id,
-                                                     PropertyOp getter, StrictPropertyOp setter,
-                                                     uint32_t slot, unsigned attrs,
-                                                     unsigned flags, Shape **spp,
-                                                     bool allowDictionary);
-
 JSObject *
 js::NewReshapedObject(JSContext *cx, HandleTypeObject type, JSObject *parent,
                       gc::AllocKind allocKind, HandleShape shape, NewObjectKind newKind)
 {
     RootedPlainObject res(cx, NewObjectWithType<PlainObject>(cx, type, parent, allocKind, newKind));
     if (!res)
         return nullptr;
 
@@ -690,17 +644,17 @@ js::NewReshapedObject(JSContext *cx, Han
 
         uint32_t index;
         bool indexed = js_IdIsIndex(id, &index);
 
         Rooted<UnownedBaseShape*> nbase(cx, newShape->base()->unowned());
         if (indexed) {
             StackBaseShape base(nbase);
             base.flags |= BaseShape::INDEXED;
-            nbase = GetOrLookupUnownedBaseShape<SequentialExecution>(cx, base);
+            nbase = BaseShape::getUnowned(cx, base);
             if (!nbase)
                 return nullptr;
         }
 
         StackShape child(nbase, id, i, JSPROP_ENUMERATE, 0);
         newShape = cx->compartment()->propertyTree.getChild(cx, newShape, child);
         if (!newShape)
             return nullptr;
@@ -712,17 +666,17 @@ js::NewReshapedObject(JSContext *cx, Han
 }
 
 /*
  * Check and adjust the new attributes for the shape to make sure that our
  * slot access optimizations are sound. It is responsibility of the callers to
  * enforce all restrictions from ECMA-262 v5 8.12.9 [[DefineOwnProperty]].
  */
 static inline bool
-CheckCanChangeAttrs(ThreadSafeContext *cx, JSObject *obj, Shape *shape, unsigned *attrsp)
+CheckCanChangeAttrs(ExclusiveContext *cx, JSObject *obj, Shape *shape, unsigned *attrsp)
 {
     if (shape->configurable())
         return true;
 
     /* A permanent property must stay permanent. */
     *attrsp |= JSPROP_PERMANENT;
 
     /* Reject attempts to remove a slot from the permanent data property. */
@@ -732,20 +686,18 @@ CheckCanChangeAttrs(ThreadSafeContext *c
         if (cx->isJSContext())
             obj->reportNotConfigurable(cx->asJSContext(), shape->propid());
         return false;
     }
 
     return true;
 }
 
-template <ExecutionMode mode>
 /* static */ Shape *
-NativeObject::putProperty(typename ExecutionModeTraits<mode>::ExclusiveContextType cx,
-                          HandleNativeObject obj, HandleId id,
+NativeObject::putProperty(ExclusiveContext *cx, HandleNativeObject obj, HandleId id,
                           PropertyOp getter, StrictPropertyOp setter,
                           uint32_t slot, unsigned attrs, unsigned flags)
 {
     MOZ_ASSERT(cx->isThreadLocal(obj));
     MOZ_ASSERT(!JSID_IS_VOID(id));
     MOZ_ASSERT(getter != JS_PropertyStub);
     MOZ_ASSERT(setter != JS_StrictPropertyStub);
 
@@ -766,45 +718,35 @@ NativeObject::putProperty(typename Execu
      * Note that we can only try to claim an entry in a table that is thread
      * local. An object may be thread local *without* its shape being thread
      * local. The only thread local objects that *also* have thread local
      * shapes are dictionaries that were allocated/converted thread
      * locally. Only for those objects we can try to claim an entry in its
      * shape table.
      */
     Shape **spp;
-    RootedShape shape(cx, (mode == ParallelExecution
-                           ? Shape::searchThreadLocal(cx, obj->lastProperty(), id, &spp,
-                                                      cx->isThreadLocal(obj->lastProperty()))
-                           : Shape::search(cx->asExclusiveContext(), obj->lastProperty(), id,
-                                           &spp, true)));
+    RootedShape shape(cx, Shape::search(cx, obj->lastProperty(), id, &spp, true));
     if (!shape) {
         /*
          * You can't add properties to a non-extensible object, but you can change
          * attributes of properties in such objects.
          */
         bool extensible;
 
-        if (mode == ParallelExecution) {
-            if (obj->is<ProxyObject>())
-                return nullptr;
-            extensible = obj->nonProxyIsExtensible();
-        } else {
-            if (!JSObject::isExtensible(cx->asExclusiveContext(), obj, &extensible))
-                return nullptr;
-        }
+        if (!JSObject::isExtensible(cx, obj, &extensible))
+            return nullptr;
 
         if (!extensible) {
             if (cx->isJSContext())
                 obj->reportNotExtensible(cx->asJSContext());
             return nullptr;
         }
 
-        return addPropertyInternal<mode>(cx, obj, id, getter, setter, slot, attrs, flags,
-                                         spp, true);
+        return addPropertyInternal(cx, obj, id, getter, setter, slot, attrs, flags,
+                                   spp, true);
     }
 
     /* Property exists: search must have returned a valid *spp. */
     MOZ_ASSERT_IF(spp, !SHAPE_IS_REMOVED(*spp));
 
     if (!CheckCanChangeAttrs(cx, obj, shape, &attrs))
         return nullptr;
 
@@ -820,17 +762,17 @@ NativeObject::putProperty(typename Execu
 
     Rooted<UnownedBaseShape*> nbase(cx);
     {
         uint32_t index;
         bool indexed = js_IdIsIndex(id, &index);
         StackBaseShape base(obj->lastProperty()->base());
         if (indexed)
             base.flags |= BaseShape::INDEXED;
-        nbase = GetOrLookupUnownedBaseShape<mode>(cx, base);
+        nbase = BaseShape::getUnowned(cx, base);
         if (!nbase)
             return nullptr;
     }
 
     /*
      * Now that we've possibly preserved slot, check whether all members match.
      * If so, this is a redundant "put" and we can return without more work.
      */
@@ -896,27 +838,27 @@ NativeObject::putProperty(typename Execu
         }
     } else {
         /*
          * Updating the last property in a non-dictionary-mode object. Find an
          * alternate shared child of the last property's previous shape.
          */
         StackBaseShape base(obj->lastProperty()->base());
 
-        UnownedBaseShape *nbase = GetOrLookupUnownedBaseShape<mode>(cx, base);
+        UnownedBaseShape *nbase = BaseShape::getUnowned(cx, base);
         if (!nbase)
             return nullptr;
 
         MOZ_ASSERT(shape == obj->lastProperty());
 
         /* Find or create a property tree node labeled by our arguments. */
         StackShape child(nbase, id, slot, attrs, flags);
         child.updateGetterSetter(getter, setter);
         RootedShape parent(cx, shape->parent);
-        Shape *newShape = getOrLookupChildProperty<mode>(cx, obj, parent, child);
+        Shape *newShape = getChildProperty(cx, obj, parent, child);
 
         if (!newShape) {
             obj->checkShapeConsistency();
             return nullptr;
         }
 
         shape = newShape;
     }
@@ -935,85 +877,55 @@ NativeObject::putProperty(typename Execu
             ++cx->asJSContext()->runtime()->propertyRemovals;
     }
 
     obj->checkShapeConsistency();
 
     return shape;
 }
 
-template /* static */ Shape *
-NativeObject::putProperty<SequentialExecution>(ExclusiveContext *cx,
-                                               HandleNativeObject obj, HandleId id,
-                                               PropertyOp getter, StrictPropertyOp setter,
-                                               uint32_t slot, unsigned attrs,
-                                               unsigned flags);
-template /* static */ Shape *
-NativeObject::putProperty<ParallelExecution>(ForkJoinContext *cx,
-                                             HandleNativeObject obj, HandleId id,
-                                             PropertyOp getter, StrictPropertyOp setter,
-                                             uint32_t slot, unsigned attrs,
-                                             unsigned flags);
-
-template <ExecutionMode mode>
 /* static */ Shape *
-NativeObject::changeProperty(typename ExecutionModeTraits<mode>::ExclusiveContextType cx,
-                             HandleNativeObject obj, HandleShape shape, unsigned attrs,
+NativeObject::changeProperty(ExclusiveContext *cx, HandleNativeObject obj,
+                             HandleShape shape, unsigned attrs,
                              unsigned mask, PropertyOp getter, StrictPropertyOp setter)
 {
     MOZ_ASSERT(cx->isThreadLocal(obj));
     MOZ_ASSERT(obj->containsPure(shape));
     MOZ_ASSERT(getter != JS_PropertyStub);
     MOZ_ASSERT(setter != JS_StrictPropertyStub);
 
     attrs |= shape->attrs & mask;
     MOZ_ASSERT_IF(attrs & (JSPROP_GETTER | JSPROP_SETTER), attrs & JSPROP_SHARED);
 
     /* Allow only shared (slotless) => unshared (slotful) transition. */
     MOZ_ASSERT(!((attrs ^ shape->attrs) & JSPROP_SHARED) ||
                !(attrs & JSPROP_SHARED));
 
-    if (mode == ParallelExecution) {
-        if (!types::IsTypePropertyIdMarkedNonData(obj, shape->propid()))
-            return nullptr;
-    } else {
-        types::MarkTypePropertyNonData(cx->asExclusiveContext(), obj, shape->propid());
-    }
+    types::MarkTypePropertyNonData(cx, obj, shape->propid());
 
     if (!CheckCanChangeAttrs(cx, obj, shape, &attrs))
         return nullptr;
 
     if (shape->attrs == attrs && shape->getter() == getter && shape->setter() == setter)
         return shape;
 
     /*
      * Let JSObject::putProperty handle this |overwriting| case, including
      * the conservation of shape->slot (if it's valid). We must not call
      * removeProperty because it will free an allocated shape->slot, and
      * putProperty won't re-allocate it.
      */
     RootedId propid(cx, shape->propid());
-    Shape *newShape = putProperty<mode>(cx, obj, propid, getter, setter,
-                                        shape->maybeSlot(), attrs, shape->flags);
+    Shape *newShape = putProperty(cx, obj, propid, getter, setter,
+                                  shape->maybeSlot(), attrs, shape->flags);
 
     obj->checkShapeConsistency();
     return newShape;
 }
 
-template /* static */ Shape *
-NativeObject::changeProperty<SequentialExecution>(ExclusiveContext *cx,
-                                                  HandleNativeObject obj, HandleShape shape,
-                                                  unsigned attrs, unsigned mask,
-                                                  PropertyOp getter, StrictPropertyOp setter);
-template /* static */ Shape *
-NativeObject::changeProperty<ParallelExecution>(ForkJoinContext *cx,
-                                                HandleNativeObject obj, HandleShape shape,
-                                                unsigned attrs, unsigned mask,
-                                                PropertyOp getter, StrictPropertyOp setter);
-
 bool
 NativeObject::removeProperty(ExclusiveContext *cx, jsid id_)
 {
     RootedId id(cx, id_);
     RootedNativeObject self(cx, this);
 
     Shape **spp;
     RootedShape shape(cx, Shape::search(cx, lastProperty(), id, &spp));
@@ -1170,27 +1082,24 @@ NativeObject::rollbackProperties(Exclusi
         if (!obj->removeProperty(cx, obj->lastProperty()->propid()))
             return false;
     }
 
     return true;
 }
 
 Shape *
-NativeObject::replaceWithNewEquivalentShape(ThreadSafeContext *cx, Shape *oldShape, Shape *newShape,
+NativeObject::replaceWithNewEquivalentShape(ExclusiveContext *cx, Shape *oldShape, Shape *newShape,
                                             bool accessorShape)
 {
     MOZ_ASSERT(cx->isThreadLocal(this));
     MOZ_ASSERT(cx->isThreadLocal(oldShape));
     MOZ_ASSERT(cx->isInsideCurrentCompartment(oldShape));
     MOZ_ASSERT_IF(oldShape != lastProperty(),
-                  inDictionaryMode() &&
-                  ((cx->isExclusiveContext()
-                    ? lookup(cx->asExclusiveContext(), oldShape->propidRef())
-                    : lookupPure(oldShape->propidRef())) == oldShape));
+                  inDictionaryMode() && lookup(cx, oldShape->propidRef()) == oldShape);
 
     NativeObject *self = this;
 
     if (!inDictionaryMode()) {
         RootedNativeObject selfRoot(cx, self);
         RootedShape newRoot(cx, newShape);
         if (!toDictionaryMode(cx))
             return nullptr;
@@ -1468,28 +1377,16 @@ BaseShape::getUnowned(ExclusiveContext *
     UnownedBaseShape *nbase = static_cast<UnownedBaseShape *>(nbase_);
 
     if (!p.add(cx, table, root, nbase))
         return nullptr;
 
     return nbase;
 }
 
-/* static */ UnownedBaseShape *
-BaseShape::lookupUnowned(ThreadSafeContext *cx, const StackBaseShape &base)
-{
-    BaseShapeSet &table = cx->compartment_->baseShapes;
-
-    if (!table.initialized())
-        return nullptr;
-
-    BaseShapeSet::Ptr p = table.readonlyThreadsafeLookup(&base);
-    return *p;
-}
-
 void
 BaseShape::assertConsistency()
 {
 #ifdef DEBUG
     if (isOwned()) {
         UnownedBaseShape *unowned = baseUnowned();
         MOZ_ASSERT(getObjectParent() == unowned->getObjectParent());
         MOZ_ASSERT(getObjectMetadata() == unowned->getObjectMetadata());
--- a/js/src/vm/Shape.h
+++ b/js/src/vm/Shape.h
@@ -175,25 +175,25 @@ struct ShapeTable {
         return entryCount + removedCount >= size - (size >> 2);
     }
 
     /*
      * Try to grow the table.  On failure, reports out of memory on cx
      * and returns false.  This will make any extant pointers into the
      * table invalid.  Don't call this unless needsToGrow() is true.
      */
-    bool grow(ThreadSafeContext *cx);
+    bool grow(ExclusiveContext *cx);
 
     /*
      * NB: init and change are fallible but do not report OOM, so callers can
      * cope or ignore. They do however use the context's calloc method in
      * order to update the malloc counter on success.
      */
-    bool            init(ThreadSafeContext *cx, Shape *lastProp);
-    bool            change(int log2Delta, ThreadSafeContext *cx);
+    bool            init(ExclusiveContext *cx, Shape *lastProp);
+    bool            change(int log2Delta, ExclusiveContext *cx);
     Shape           **search(jsid id, bool adding);
 
 #ifdef JSGC_COMPACTING
     /* Update entries whose shapes have been moved */
     void            fixupAfterMovingGC();
 #endif
 };
 
@@ -426,22 +426,16 @@ class BaseShape : public gc::TenuredCell
     JSCompartment *compartment() const { return compartment_; }
 
     /*
      * Lookup base shapes from the compartment's baseShapes table, adding if
      * not already found.
      */
     static UnownedBaseShape* getUnowned(ExclusiveContext *cx, StackBaseShape &base);
 
-    /*
-     * Lookup base shapes from the compartment's baseShapes table, returning
-     * nullptr if not found.
-     */
-    static UnownedBaseShape *lookupUnowned(ThreadSafeContext *cx, const StackBaseShape &base);
-
     /* Get the canonical base shape. */
     inline UnownedBaseShape* unowned();
 
     /* Get the canonical base shape for an owned one. */
     inline UnownedBaseShape* baseUnowned();
 
     /* Get the canonical base shape for an unowned one (i.e. identity). */
     inline UnownedBaseShape* toUnowned();
@@ -528,17 +522,17 @@ struct StackBaseShape : public DefaultHa
     explicit StackBaseShape(BaseShape *base)
       : flags(base->flags & BaseShape::OBJECT_FLAG_MASK),
         clasp(base->clasp_),
         parent(base->parent),
         metadata(base->metadata),
         compartment(base->compartment())
     {}
 
-    inline StackBaseShape(ThreadSafeContext *cx, const Class *clasp,
+    inline StackBaseShape(ExclusiveContext *cx, const Class *clasp,
                           JSObject *parent, JSObject *metadata, uint32_t objectFlags);
     explicit inline StackBaseShape(Shape *shape);
 
     static inline HashNumber hash(const StackBaseShape *lookup);
     static inline bool match(UnownedBaseShape *key, const StackBaseShape *lookup);
 
     // For RootedGeneric<StackBaseShape*>
     void trace(JSTracer *trc);
@@ -616,52 +610,50 @@ class Shape : public gc::TenuredCell
         HeapPtrShape *listp;    /* dictionary list starting at shape_
                                    has a double-indirect back pointer,
                                    either to the next shape's parent if not
                                    last, else to obj->shape_ */
     };
 
     static inline Shape *search(ExclusiveContext *cx, Shape *start, jsid id,
                                 Shape ***pspp, bool adding = false);
-    static inline Shape *searchThreadLocal(ThreadSafeContext *cx, Shape *start, jsid id,
-                                           Shape ***pspp, bool adding = false);
     static inline Shape *searchNoHashify(Shape *start, jsid id);
 
     void removeFromDictionary(NativeObject *obj);
     void insertIntoDictionary(HeapPtrShape *dictp);
 
     inline void initDictionaryShape(const StackShape &child, uint32_t nfixed, HeapPtrShape *dictp);
 
     /* Replace the base shape of the last shape in a non-dictionary lineage with base. */
     static Shape *replaceLastProperty(ExclusiveContext *cx, StackBaseShape &base,
                                       TaggedProto proto, HandleShape shape);
 
     /*
      * This function is thread safe if every shape in the lineage of |shape|
      * is thread local, which is the case when we clone the entire shape
      * lineage in preparation for converting an object to dictionary mode.
      */
-    static bool hashify(ThreadSafeContext *cx, Shape *shape);
+    static bool hashify(ExclusiveContext *cx, Shape *shape);
     void handoffTableTo(Shape *newShape);
 
     void setParent(Shape *p) {
         MOZ_ASSERT_IF(p && !p->hasMissingSlot() && !inDictionary(),
                       p->maybeSlot() <= maybeSlot());
         MOZ_ASSERT_IF(p && !inDictionary(),
                       hasSlot() == (p->maybeSlot() != maybeSlot()));
         parent = p;
     }
 
-    bool ensureOwnBaseShape(ThreadSafeContext *cx) {
+    bool ensureOwnBaseShape(ExclusiveContext *cx) {
         if (base()->isOwned())
             return true;
         return makeOwnBaseShape(cx);
     }
 
-    bool makeOwnBaseShape(ThreadSafeContext *cx);
+    bool makeOwnBaseShape(ExclusiveContext *cx);
 
   public:
     bool hasTable() const { return base()->hasTable(); }
     ShapeTable &table() const { return base()->table(); }
 
     void addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf,
                                 JS::ClassInfo *info) const
     {
@@ -1053,32 +1045,32 @@ StackBaseShape::StackBaseShape(Shape *sh
     compartment(shape->compartment())
 {}
 
 class AutoRooterGetterSetter
 {
     class Inner : private JS::CustomAutoRooter
     {
       public:
-        inline Inner(ThreadSafeContext *cx, uint8_t attrs,
+        inline Inner(ExclusiveContext *cx, uint8_t attrs,
                      PropertyOp *pgetter_, StrictPropertyOp *psetter_);
 
       private:
         virtual void trace(JSTracer *trc);
 
         uint8_t attrs;
         PropertyOp *pgetter;
         StrictPropertyOp *psetter;
     };
 
   public:
-    inline AutoRooterGetterSetter(ThreadSafeContext *cx, uint8_t attrs,
+    inline AutoRooterGetterSetter(ExclusiveContext *cx, uint8_t attrs,
                                   PropertyOp *pgetter, StrictPropertyOp *psetter
                                   MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
-    inline AutoRooterGetterSetter(ThreadSafeContext *cx, uint8_t attrs,
+    inline AutoRooterGetterSetter(ExclusiveContext *cx, uint8_t attrs,
                                   JSNative *pgetter, JSNative *psetter
                                   MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
 
   private:
     mozilla::Maybe<Inner> inner;
     MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
 };