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 222906 46c80c517631bd66053a9a84f8419329f7891935
parent 222905 68d1c3fd25f1fbbb5b8910a41ff0a691c0eae371
child 222907 dfa1f0425c654d6058be1ef238c9d4a6e605f6ba
push id10731
push usercbook@mozilla.com
push dateFri, 09 Jan 2015 14:51:37 +0000
treeherderfx-team@e6756043d930 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerslth
bugs1118107
milestone37.0a1
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
 };