Backout bug 785905, off-thread IonBuilder. r=jorendorff
authorJan de Mooij <jdemooij@mozilla.com>
Fri, 14 Feb 2014 13:17:53 +0100
changeset 168809 8c521a802625683b42a1ca9245dfac06e10aa1a8
parent 168757 9e7cf0b1d80c2375d8a2ccde4c0cc1eff4901e49
child 168810 4da945c0084c96a28a492cc5b5ab1ec543bfde51
push id26218
push userryanvm@gmail.com
push dateFri, 14 Feb 2014 20:21:08 +0000
treeherdermozilla-central@33b3248b4aa0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjorendorff
bugs785905
milestone30.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Backout bug 785905, off-thread IonBuilder. r=jorendorff
js/src/builtin/TypeRepresentation.cpp
js/src/frontend/BytecodeEmitter.cpp
js/src/gc/Barrier.h
js/src/gc/Heap.h
js/src/jit/BaselineIC.cpp
js/src/jit/BaselineIC.h
js/src/jit/BaselineInspector.cpp
js/src/jit/BaselineJIT.h
js/src/jit/CodeGenerator.cpp
js/src/jit/CompileWrappers.cpp
js/src/jit/CompileWrappers.h
js/src/jit/Ion.cpp
js/src/jit/IonBuilder.cpp
js/src/jit/IonBuilder.h
js/src/jit/IonCode.h
js/src/jit/IonMacroAssembler.cpp
js/src/jit/JitOptions.cpp
js/src/jit/JitOptions.h
js/src/jit/MCallOptimize.cpp
js/src/jit/MIR.cpp
js/src/jit/shared/CodeGenerator-shared.cpp
js/src/jsatominlines.h
js/src/jsboolinlines.h
js/src/jscntxt.cpp
js/src/jscntxt.h
js/src/jscompartmentinlines.h
js/src/jsfun.cpp
js/src/jsfun.h
js/src/jsinfer.cpp
js/src/jsinfer.h
js/src/jsinferinlines.h
js/src/jsiter.cpp
js/src/jsobj.cpp
js/src/jsobj.h
js/src/jsobjinlines.h
js/src/jsscript.cpp
js/src/jsscript.h
js/src/jsscriptinlines.h
js/src/jsstr.cpp
js/src/jsworkers.cpp
js/src/jswrapper.cpp
js/src/shell/js.cpp
js/src/vm/GlobalObject.cpp
js/src/vm/GlobalObject.h
js/src/vm/Interpreter.cpp
js/src/vm/ObjectImpl.cpp
js/src/vm/ObjectImpl.h
js/src/vm/Runtime.cpp
js/src/vm/Runtime.h
js/src/vm/ScopeObject-inl.h
js/src/vm/ScopeObject.h
js/src/vm/Shape.h
js/src/vm/String.h
js/src/vm/TypedArrayObject.cpp
js/src/vm/TypedArrayObject.h
--- a/js/src/builtin/TypeRepresentation.cpp
+++ b/js/src/builtin/TypeRepresentation.cpp
@@ -821,17 +821,16 @@ SizedTypeRepresentation::traceInstance(J
 const StructField *
 StructTypeRepresentation::fieldNamed(jsid id) const
 {
     if (!JSID_IS_ATOM(id))
         return nullptr;
 
     uint32_t unused;
     JSAtom *atom = JSID_TO_ATOM(id);
-    AutoThreadSafeAccess ts(atom);
 
     if (atom->isIndex(&unused))
         return nullptr;
 
     PropertyName *name = atom->asPropertyName();
 
     for (size_t i = 0; i < fieldCount(); i++) {
         if (field(i).propertyName.get() == name)
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -2860,22 +2860,20 @@ frontend::EmitFunctionScript(ExclusiveCo
         bce->script->setTreatAsRunOnce();
         JS_ASSERT(!bce->script->hasRunOnce());
     }
 
     /* Initialize fun->script() so that the debugger has a valid fun->script(). */
     RootedFunction fun(cx, bce->script->functionNonDelazifying());
     JS_ASSERT(fun->isInterpreted());
 
-    if (fun->isInterpretedLazy()) {
-        AutoLockForCompilation lock(cx);
+    if (fun->isInterpretedLazy())
         fun->setUnlazifiedScript(bce->script);
-    } else {
+    else
         fun->setScript(bce->script);
-    }
 
     bce->tellDebuggerAboutCompiledScript(cx);
 
     return true;
 }
 
 static bool
 MaybeEmitVarDecl(ExclusiveContext *cx, BytecodeEmitter *bce, JSOp prologOp, ParseNode *pn,
--- a/js/src/gc/Barrier.h
+++ b/js/src/gc/Barrier.h
@@ -186,19 +186,16 @@ class BarrieredCell : public gc::Cell
     MOZ_ALWAYS_INLINE JS::shadow::Zone *shadowZone() const { return JS::shadow::Zone::asShadowZone(zone()); }
     MOZ_ALWAYS_INLINE JS::Zone *zoneFromAnyThread() const { return tenuredZoneFromAnyThread(); }
     MOZ_ALWAYS_INLINE JS::shadow::Zone *shadowZoneFromAnyThread() const {
         return JS::shadow::Zone::asShadowZone(zoneFromAnyThread());
     }
 
     static MOZ_ALWAYS_INLINE void readBarrier(T *thing) {
 #ifdef JSGC_INCREMENTAL
-        // Off thread Ion compilation never occurs when barriers are active.
-        js::AutoThreadSafeAccess ts(thing);
-
         JS::shadow::Zone *shadowZone = thing->shadowZoneFromAnyThread();
         if (shadowZone->needsBarrier()) {
             MOZ_ASSERT(!RuntimeFromMainThreadIsHeapMajorCollecting(shadowZone));
             T *tmp = thing;
             js::gc::MarkUnbarriered<T>(shadowZone->barrierTracer(), &tmp, "read barrier");
             JS_ASSERT(tmp == thing);
         }
 #endif
--- a/js/src/gc/Heap.h
+++ b/js/src/gc/Heap.h
@@ -1104,45 +1104,17 @@ InFreeList(ArenaHeader *aheader, void *t
          * span->end < thing < thingsEnd and so we must have more spans.
          */
         span = span->nextSpan();
     }
 }
 
 } /* namespace gc */
 
-// Ion compilation mainly occurs off the main thread, and may run while the
-// main thread is performing arbitrary VM operations, excepting GC activity.
-// The below class is used to mark functions and other operations which can
-// safely be performed off thread without racing. When running with thread
-// safety checking on, any access to a GC thing outside of AutoThreadSafeAccess
-// will cause an access violation.
-class MOZ_STACK_CLASS AutoThreadSafeAccess
-{
-public:
-#if defined(DEBUG) && defined(JS_CPU_X64) && !defined(XP_WIN)
-#define JS_CAN_CHECK_THREADSAFE_ACCESSES
-
-    JSRuntime *runtime;
-    gc::ArenaHeader *arena;
-
-    AutoThreadSafeAccess(const gc::Cell *cell MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
-    ~AutoThreadSafeAccess();
-#else
-    AutoThreadSafeAccess(const gc::Cell *cell MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
-    {
-        MOZ_GUARD_OBJECT_NOTIFIER_INIT;
-    }
-    ~AutoThreadSafeAccess() {}
-#endif
-    MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
-};
-
 gc::AllocKind
 gc::Cell::tenuredGetAllocKind() const
 {
-    AutoThreadSafeAccess ts(this);
     return arenaHeader()->getAllocKind();
 }
 
 } /* namespace js */
 
 #endif /* gc_Heap_h */
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -131,20 +131,17 @@ ICStubIterator::operator++()
 
 void
 ICStubIterator::unlink(JSContext *cx)
 {
     JS_ASSERT(currentStub_->next() != nullptr);
     JS_ASSERT(currentStub_ != fallbackStub_);
     JS_ASSERT(!unlinked_);
 
-    {
-        AutoLockForCompilation lock(cx);
-        fallbackStub_->unlinkStub(cx->zone(), previousStub_, currentStub_);
-    }
+    fallbackStub_->unlinkStub(cx->zone(), previousStub_, currentStub_);
 
     // Mark the current iterator position as unlinked, so operator++ works properly.
     unlinked_ = true;
 }
 
 
 void
 ICStub::markCode(JSTracer *trc, const char *name)
@@ -1061,17 +1058,17 @@ DoProfilerFallback(JSContext *cx, Baseli
     IonSpew(IonSpew_BaselineIC, "  Generating Profiler_PushFunction stub for %s:%d",
             script->filename(), script->lineno());
 
     // Create a new optimized stub.
     ICProfiler_PushFunction::Compiler compiler(cx, string, script);
     ICStub *optStub = compiler.getStub(compiler.getStubSpace(script));
     if (!optStub)
         return false;
-    stub->addNewStub(cx, optStub);
+    stub->addNewStub(optStub);
 
     return true;
 }
 
 typedef bool (*DoProfilerFallbackFn)(JSContext *, BaselineFrame *frame, ICProfiler_Fallback *);
 static const VMFunction DoProfilerFallbackInfo =
     FunctionInfo<DoProfilerFallbackFn>(DoProfilerFallback);
 
@@ -1792,17 +1789,17 @@ DoCompareFallback(JSContext *cx, Baselin
     // Try to generate new stubs.
     if (lhs.isInt32() && rhs.isInt32()) {
         IonSpew(IonSpew_BaselineIC, "  Generating %s(Int32, Int32) stub", js_CodeName[op]);
         ICCompare_Int32::Compiler compiler(cx, op);
         ICStub *int32Stub = compiler.getStub(compiler.getStubSpace(script));
         if (!int32Stub)
             return false;
 
-        stub->addNewStub(cx, int32Stub);
+        stub->addNewStub(int32Stub);
         return true;
     }
 
     if (!cx->runtime()->jitSupportsFloatingPoint && (lhs.isNumber() || rhs.isNumber()))
         return true;
 
     if (lhs.isNumber() && rhs.isNumber()) {
         IonSpew(IonSpew_BaselineIC, "  Generating %s(Number, Number) stub", js_CodeName[op]);
@@ -1810,80 +1807,80 @@ DoCompareFallback(JSContext *cx, Baselin
         // Unlink int32 stubs, it's faster to always use the double stub.
         stub->unlinkStubsWithKind(cx, ICStub::Compare_Int32);
 
         ICCompare_Double::Compiler compiler(cx, op);
         ICStub *doubleStub = compiler.getStub(compiler.getStubSpace(script));
         if (!doubleStub)
             return false;
 
-        stub->addNewStub(cx, doubleStub);
+        stub->addNewStub(doubleStub);
         return true;
     }
 
     if ((lhs.isNumber() && rhs.isUndefined()) ||
         (lhs.isUndefined() && rhs.isNumber()))
     {
         IonSpew(IonSpew_BaselineIC, "  Generating %s(%s, %s) stub", js_CodeName[op],
                     rhs.isUndefined() ? "Number" : "Undefined",
                     rhs.isUndefined() ? "Undefined" : "Number");
         ICCompare_NumberWithUndefined::Compiler compiler(cx, op, lhs.isUndefined());
         ICStub *doubleStub = compiler.getStub(compiler.getStubSpace(script));
         if (!doubleStub)
             return false;
 
-        stub->addNewStub(cx, doubleStub);
+        stub->addNewStub(doubleStub);
         return true;
     }
 
     if (lhs.isBoolean() && rhs.isBoolean()) {
         IonSpew(IonSpew_BaselineIC, "  Generating %s(Boolean, Boolean) stub", js_CodeName[op]);
         ICCompare_Boolean::Compiler compiler(cx, op);
         ICStub *booleanStub = compiler.getStub(compiler.getStubSpace(script));
         if (!booleanStub)
             return false;
 
-        stub->addNewStub(cx, booleanStub);
+        stub->addNewStub(booleanStub);
         return true;
     }
 
     if ((lhs.isBoolean() && rhs.isInt32()) || (lhs.isInt32() && rhs.isBoolean())) {
         IonSpew(IonSpew_BaselineIC, "  Generating %s(%s, %s) stub", js_CodeName[op],
                     rhs.isInt32() ? "Boolean" : "Int32",
                     rhs.isInt32() ? "Int32" : "Boolean");
         ICCompare_Int32WithBoolean::Compiler compiler(cx, op, lhs.isInt32());
         ICStub *optStub = compiler.getStub(compiler.getStubSpace(script));
         if (!optStub)
             return false;
 
-        stub->addNewStub(cx, optStub);
+        stub->addNewStub(optStub);
         return true;
     }
 
     if (IsEqualityOp(op)) {
         if (lhs.isString() && rhs.isString() && !stub->hasStub(ICStub::Compare_String)) {
             IonSpew(IonSpew_BaselineIC, "  Generating %s(String, String) stub", js_CodeName[op]);
             ICCompare_String::Compiler compiler(cx, op);
             ICStub *stringStub = compiler.getStub(compiler.getStubSpace(script));
             if (!stringStub)
                 return false;
 
-            stub->addNewStub(cx, stringStub);
+            stub->addNewStub(stringStub);
             return true;
         }
 
         if (lhs.isObject() && rhs.isObject()) {
             JS_ASSERT(!stub->hasStub(ICStub::Compare_Object));
             IonSpew(IonSpew_BaselineIC, "  Generating %s(Object, Object) stub", js_CodeName[op]);
             ICCompare_Object::Compiler compiler(cx, op);
             ICStub *objectStub = compiler.getStub(compiler.getStubSpace(script));
             if (!objectStub)
                 return false;
 
-            stub->addNewStub(cx, objectStub);
+            stub->addNewStub(objectStub);
             return true;
         }
 
         if ((lhs.isObject() || lhs.isNull() || lhs.isUndefined()) &&
             (rhs.isObject() || rhs.isNull() || rhs.isUndefined()) &&
             !stub->hasStub(ICStub::Compare_ObjectWithUndefined))
         {
             IonSpew(IonSpew_BaselineIC, "  Generating %s(Obj/Null/Undef, Obj/Null/Undef) stub",
@@ -1891,17 +1888,17 @@ DoCompareFallback(JSContext *cx, Baselin
             bool lhsIsUndefined = lhs.isNull() || lhs.isUndefined();
             bool compareWithNull = lhs.isNull() || rhs.isNull();
             ICCompare_ObjectWithUndefined::Compiler compiler(cx, op,
                                                              lhsIsUndefined, compareWithNull);
             ICStub *objectStub = compiler.getStub(compiler.getStubSpace(script));
             if (!objectStub)
                 return false;
 
-            stub->addNewStub(cx, objectStub);
+            stub->addNewStub(objectStub);
             return true;
         }
     }
 
     return true;
 }
 
 typedef bool (*DoCompareFallbackFn)(JSContext *, BaselineFrame *, ICCompare_Fallback *,
@@ -2202,60 +2199,60 @@ DoToBoolFallback(JSContext *cx, Baseline
     // Try to generate new stubs.
     if (arg.isInt32()) {
         IonSpew(IonSpew_BaselineIC, "  Generating ToBool(Int32) stub.");
         ICToBool_Int32::Compiler compiler(cx);
         ICStub *int32Stub = compiler.getStub(compiler.getStubSpace(script));
         if (!int32Stub)
             return false;
 
-        stub->addNewStub(cx, int32Stub);
+        stub->addNewStub(int32Stub);
         return true;
     }
 
     if (arg.isDouble() && cx->runtime()->jitSupportsFloatingPoint) {
         IonSpew(IonSpew_BaselineIC, "  Generating ToBool(Double) stub.");
         ICToBool_Double::Compiler compiler(cx);
         ICStub *doubleStub = compiler.getStub(compiler.getStubSpace(script));
         if (!doubleStub)
             return false;
 
-        stub->addNewStub(cx, doubleStub);
+        stub->addNewStub(doubleStub);
         return true;
     }
 
     if (arg.isString()) {
         IonSpew(IonSpew_BaselineIC, "  Generating ToBool(String) stub");
         ICToBool_String::Compiler compiler(cx);
         ICStub *stringStub = compiler.getStub(compiler.getStubSpace(script));
         if (!stringStub)
             return false;
 
-        stub->addNewStub(cx, stringStub);
+        stub->addNewStub(stringStub);
         return true;
     }
 
     if (arg.isNull() || arg.isUndefined()) {
         ICToBool_NullUndefined::Compiler compiler(cx);
         ICStub *nilStub = compiler.getStub(compiler.getStubSpace(script));
         if (!nilStub)
             return false;
 
-        stub->addNewStub(cx, nilStub);
+        stub->addNewStub(nilStub);
         return true;
     }
 
     if (arg.isObject()) {
         IonSpew(IonSpew_BaselineIC, "  Generating ToBool(Object) stub.");
         ICToBool_Object::Compiler compiler(cx);
         ICStub *objStub = compiler.getStub(compiler.getStubSpace(script));
         if (!objStub)
             return false;
 
-        stub->addNewStub(cx, objStub);
+        stub->addNewStub(objStub);
         return true;
     }
 
     return true;
 }
 
 typedef bool (*pf)(JSContext *, BaselineFrame *, ICToBool_Fallback *, HandleValue,
                    MutableHandleValue);
@@ -2537,69 +2534,69 @@ DoBinaryArithFallback(JSContext *cx, Bas
             return false;
         break;
       }
       default:
         MOZ_ASSUME_UNREACHABLE("Unhandled baseline arith op");
     }
 
     if (ret.isDouble())
-        stub->setSawDoubleResult(cx);
+        stub->setSawDoubleResult();
 
     // Check to see if a new stub should be generated.
     if (stub->numOptimizedStubs() >= ICBinaryArith_Fallback::MAX_OPTIMIZED_STUBS) {
-        stub->noteUnoptimizableOperands(cx);
+        stub->noteUnoptimizableOperands();
         return true;
     }
 
     // Handle string concat.
     if (op == JSOP_ADD) {
         if (lhs.isString() && rhs.isString()) {
             IonSpew(IonSpew_BaselineIC, "  Generating %s(String, String) stub", js_CodeName[op]);
             JS_ASSERT(ret.isString());
             ICBinaryArith_StringConcat::Compiler compiler(cx);
             ICStub *strcatStub = compiler.getStub(compiler.getStubSpace(script));
             if (!strcatStub)
                 return false;
-            stub->addNewStub(cx, strcatStub);
+            stub->addNewStub(strcatStub);
             return true;
         }
 
         if ((lhs.isString() && rhs.isObject()) || (lhs.isObject() && rhs.isString())) {
             IonSpew(IonSpew_BaselineIC, "  Generating %s(%s, %s) stub", js_CodeName[op],
                     lhs.isString() ? "String" : "Object",
                     lhs.isString() ? "Object" : "String");
             JS_ASSERT(ret.isString());
             ICBinaryArith_StringObjectConcat::Compiler compiler(cx, lhs.isString());
             ICStub *strcatStub = compiler.getStub(compiler.getStubSpace(script));
             if (!strcatStub)
                 return false;
-            stub->addNewStub(cx, strcatStub);
+            stub->addNewStub(strcatStub);
             return true;
         }
     }
 
     if (((lhs.isBoolean() && (rhs.isBoolean() || rhs.isInt32())) ||
          (rhs.isBoolean() && (lhs.isBoolean() || lhs.isInt32()))) &&
         (op == JSOP_ADD || op == JSOP_SUB || op == JSOP_BITOR || op == JSOP_BITAND ||
          op == JSOP_BITXOR))
     {
         IonSpew(IonSpew_BaselineIC, "  Generating %s(%s, %s) stub", js_CodeName[op],
                 lhs.isBoolean() ? "Boolean" : "Int32", rhs.isBoolean() ? "Boolean" : "Int32");
         ICBinaryArith_BooleanWithInt32::Compiler compiler(cx, op, lhs.isBoolean(), rhs.isBoolean());
         ICStub *arithStub = compiler.getStub(compiler.getStubSpace(script));
         if (!arithStub)
             return false;
-        stub->addNewStub(cx, arithStub);
+        stub->addNewStub(arithStub);
         return true;
     }
 
     // Handle only int32 or double.
     if (!lhs.isNumber() || !rhs.isNumber()) {
-        stub->noteUnoptimizableOperands(cx);
+        stub->noteUnoptimizableOperands();
         return true;
     }
 
     JS_ASSERT(ret.isNumber());
 
     if (lhs.isDouble() || rhs.isDouble() || ret.isDouble()) {
         if (!cx->runtime()->jitSupportsFloatingPoint)
             return true;
@@ -2613,17 +2610,17 @@ DoBinaryArithFallback(JSContext *cx, Bas
             // Unlink int32 stubs, it's faster to always use the double stub.
             stub->unlinkStubsWithKind(cx, ICStub::BinaryArith_Int32);
             IonSpew(IonSpew_BaselineIC, "  Generating %s(Double, Double) stub", js_CodeName[op]);
 
             ICBinaryArith_Double::Compiler compiler(cx, op);
             ICStub *doubleStub = compiler.getStub(compiler.getStubSpace(script));
             if (!doubleStub)
                 return false;
-            stub->addNewStub(cx, doubleStub);
+            stub->addNewStub(doubleStub);
             return true;
           }
           default:
             break;
         }
     }
 
     if (lhs.isInt32() && rhs.isInt32()) {
@@ -2631,17 +2628,17 @@ DoBinaryArithFallback(JSContext *cx, Bas
         if (allowDouble)
             stub->unlinkStubsWithKind(cx, ICStub::BinaryArith_Int32);
         IonSpew(IonSpew_BaselineIC, "  Generating %s(Int32, Int32%s) stub", js_CodeName[op],
                 allowDouble ? " => Double" : "");
         ICBinaryArith_Int32::Compiler compilerInt32(cx, op, allowDouble);
         ICStub *int32Stub = compilerInt32.getStub(compilerInt32.getStubSpace(script));
         if (!int32Stub)
             return false;
-        stub->addNewStub(cx, int32Stub);
+        stub->addNewStub(int32Stub);
         return true;
     }
 
     // Handle Double <BITOP> Int32 or Int32 <BITOP> Double case.
     if (((lhs.isDouble() && rhs.isInt32()) || (lhs.isInt32() && rhs.isDouble())) &&
         ret.isInt32())
     {
         switch(op) {
@@ -2650,25 +2647,25 @@ DoBinaryArithFallback(JSContext *cx, Bas
           case JSOP_BITAND: {
             IonSpew(IonSpew_BaselineIC, "  Generating %s(%s, %s) stub", js_CodeName[op],
                         lhs.isDouble() ? "Double" : "Int32",
                         lhs.isDouble() ? "Int32" : "Double");
             ICBinaryArith_DoubleWithInt32::Compiler compiler(cx, op, lhs.isDouble());
             ICStub *optStub = compiler.getStub(compiler.getStubSpace(script));
             if (!optStub)
                 return false;
-            stub->addNewStub(cx, optStub);
+            stub->addNewStub(optStub);
             return true;
           }
           default:
             break;
         }
     }
 
-    stub->noteUnoptimizableOperands(cx);
+    stub->noteUnoptimizableOperands();
     return true;
 }
 #if defined(_MSC_VER)
 # pragma optimize("", on)
 #endif
 
 typedef bool (*DoBinaryArithFallbackFn)(JSContext *, BaselineFrame *, ICBinaryArith_Fallback *,
                                         HandleValue, HandleValue, MutableHandleValue);
@@ -3053,31 +3050,31 @@ DoUnaryArithFallback(JSContext *cx, Base
     }
 
     if (val.isInt32() && res.isInt32()) {
         IonSpew(IonSpew_BaselineIC, "  Generating %s(Int32 => Int32) stub", js_CodeName[op]);
         ICUnaryArith_Int32::Compiler compiler(cx, op);
         ICStub *int32Stub = compiler.getStub(compiler.getStubSpace(script));
         if (!int32Stub)
             return false;
-        stub->addNewStub(cx, int32Stub);
+        stub->addNewStub(int32Stub);
         return true;
     }
 
     if (val.isNumber() && res.isNumber() && cx->runtime()->jitSupportsFloatingPoint) {
         IonSpew(IonSpew_BaselineIC, "  Generating %s(Number => Number) stub", js_CodeName[op]);
 
         // Unlink int32 stubs, the double stub handles both cases and TI specializes for both.
         stub->unlinkStubsWithKind(cx, ICStub::UnaryArith_Int32);
 
         ICUnaryArith_Double::Compiler compiler(cx, op);
         ICStub *doubleStub = compiler.getStub(compiler.getStubSpace(script));
         if (!doubleStub)
             return false;
-        stub->addNewStub(cx, doubleStub);
+        stub->addNewStub(doubleStub);
         return true;
     }
 
     return true;
 }
 #if defined(_MSC_VER)
 # pragma optimize("", on)
 #endif
@@ -3752,17 +3749,17 @@ static bool TryAttachNativeGetElemStub(J
         ICGetElemNativeStub::AccessType acctype = isFixedSlot ? ICGetElemNativeStub::FixedSlot
                                                               : ICGetElemNativeStub::DynamicSlot;
         ICGetElemNativeCompiler compiler(cx, kind, isCallElem, monitorStub, obj, holder, propName,
                                          acctype, needsAtomize, offset);
         ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
         if (!newStub)
             return false;
 
-        stub->addNewStub(cx, newStub);
+        stub->addNewStub(newStub);
         return true;
     }
 
     bool getterIsScripted = false;
     if (IsCacheableGetPropCall(cx, obj, holder, shape, &getterIsScripted, /*isDOMProxy=*/false)) {
         RootedFunction getter(cx, &shape->getterObject()->as<JSFunction>());
 
 #if JS_HAS_NO_SUCH_METHOD
@@ -3804,17 +3801,17 @@ static bool TryAttachNativeGetElemStub(J
                                                            ? ICGetElemNativeStub::ScriptedGetter
                                                            : ICGetElemNativeStub::NativeGetter;
         ICGetElemNativeCompiler compiler(cx, kind, monitorStub, obj, holder, propName, acctype,
                                          needsAtomize, getter, script->pcToOffset(pc), isCallElem);
         ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
         if (!newStub)
             return false;
 
-        stub->addNewStub(cx, newStub);
+        stub->addNewStub(newStub);
         return true;
     }
 
     return true;
 }
 
 static bool
 TypedArrayRequiresFloatingPoint(TypedArrayObject *tarr)
@@ -3838,17 +3835,17 @@ TryAttachGetElemStub(JSContext *cx, JSSc
         // NoSuchMethod handling doesn't apply to string targets.
 
         IonSpew(IonSpew_BaselineIC, "  Generating GetElem(String[Int32]) stub");
         ICGetElem_String::Compiler compiler(cx);
         ICStub *stringStub = compiler.getStub(compiler.getStubSpace(script));
         if (!stringStub)
             return false;
 
-        stub->addNewStub(cx, stringStub);
+        stub->addNewStub(stringStub);
         return true;
     }
 
     if (lhs.isMagic(JS_OPTIMIZED_ARGUMENTS) && rhs.isInt32() &&
         !ArgumentsGetElemStubExists(stub, ICGetElem_Arguments::Magic))
     {
         // Any script with a CALLPROP on arguments (arguments.foo())
         // should not have optimized arguments.
@@ -3856,17 +3853,17 @@ TryAttachGetElemStub(JSContext *cx, JSSc
 
         IonSpew(IonSpew_BaselineIC, "  Generating GetElem(MagicArgs[Int32]) stub");
         ICGetElem_Arguments::Compiler compiler(cx, stub->fallbackMonitorStub()->firstMonitorStub(),
                                                ICGetElem_Arguments::Magic, false);
         ICStub *argsStub = compiler.getStub(compiler.getStubSpace(script));
         if (!argsStub)
             return false;
 
-        stub->addNewStub(cx, argsStub);
+        stub->addNewStub(argsStub);
         return true;
     }
 
     // Otherwise, GetElem is only optimized on objects.
     if (!lhs.isObject())
         return true;
     RootedObject obj(cx, &lhs.toObject());
 
@@ -3878,32 +3875,32 @@ TryAttachGetElemStub(JSContext *cx, JSSc
         if (!ArgumentsGetElemStubExists(stub, which)) {
             IonSpew(IonSpew_BaselineIC, "  Generating GetElem(ArgsObj[Int32]) stub");
             ICGetElem_Arguments::Compiler compiler(
                 cx, stub->fallbackMonitorStub()->firstMonitorStub(), which, isCallElem);
             ICStub *argsStub = compiler.getStub(compiler.getStubSpace(script));
             if (!argsStub)
                 return false;
 
-            stub->addNewStub(cx, argsStub);
+            stub->addNewStub(argsStub);
             return true;
         }
     }
 
     if (obj->isNative()) {
         // Check for NativeObject[int] dense accesses.
         if (rhs.isInt32() && rhs.toInt32() >= 0) {
             IonSpew(IonSpew_BaselineIC, "  Generating GetElem(Native[Int32] dense) stub");
             ICGetElem_Dense::Compiler compiler(cx, stub->fallbackMonitorStub()->firstMonitorStub(),
                                                obj->lastProperty(), isCallElem);
             ICStub *denseStub = compiler.getStub(compiler.getStubSpace(script));
             if (!denseStub)
                 return false;
 
-            stub->addNewStub(cx, denseStub);
+            stub->addNewStub(denseStub);
             return true;
         }
 
         // Check for NativeObject[id] shape-optimizable accesses.
         if (rhs.isString()) {
             RootedScript rootedScript(cx, script);
             if (!TryAttachNativeGetElemStub(cx, rootedScript, pc, stub, obj, rhs))
                 return false;
@@ -3929,31 +3926,31 @@ TryAttachGetElemStub(JSContext *cx, JSSc
         }
 
         IonSpew(IonSpew_BaselineIC, "  Generating GetElem(TypedArray[Int32]) stub");
         ICGetElem_TypedArray::Compiler compiler(cx, tarr->lastProperty(), tarr->type());
         ICStub *typedArrayStub = compiler.getStub(compiler.getStubSpace(script));
         if (!typedArrayStub)
             return false;
 
-        stub->addNewStub(cx, typedArrayStub);
+        stub->addNewStub(typedArrayStub);
         return true;
     }
 
     // GetElem operations on non-native objects other than typed arrays cannot
     // be cached by either Baseline or Ion. Indicate this in the cache so that
     // Ion does not generate a cache for this op.
     if (!obj->isNative() && !obj->is<TypedArrayObject>())
-        stub->noteNonNativeAccess(cx);
+        stub->noteNonNativeAccess();
 
     // GetElem operations which could access negative indexes generally can't
     // be optimized without the potential for bailouts, as we can't statically
     // determine that an object has no properties on such indexes.
     if (rhs.isNumber() && rhs.toNumber() < 0)
-        stub->noteNegativeIndex(cx);
+        stub->noteNegativeIndex();
 
     return true;
 }
 
 static bool
 DoGetElemFallback(JSContext *cx, BaselineFrame *frame, ICGetElem_Fallback *stub, HandleValue lhs,
                   HandleValue rhs, MutableHandleValue res)
 {
@@ -5009,31 +5006,31 @@ DoSetElemFallback(JSContext *cx, Baselin
                         obj->lastProperty(), type.get(), protoDepth);
                 ICSetElemDenseAddCompiler compiler(cx, obj, protoDepth);
                 ICUpdatedStub *denseStub = compiler.getStub(compiler.getStubSpace(script));
                 if (!denseStub)
                     return false;
                 if (!denseStub->addUpdateStubForValue(cx, script, obj, JSID_VOIDHANDLE, rhs))
                     return false;
 
-                stub->addNewStub(cx, denseStub);
+                stub->addNewStub(denseStub);
             } else if (!addingCase &&
                        !DenseSetElemStubExists(cx, ICStub::SetElem_Dense, stub, obj))
             {
                 IonSpew(IonSpew_BaselineIC,
                         "  Generating SetElem_Dense stub (shape=%p, type=%p)",
                         obj->lastProperty(), type.get());
                 ICSetElem_Dense::Compiler compiler(cx, shape, type);
                 ICUpdatedStub *denseStub = compiler.getStub(compiler.getStubSpace(script));
                 if (!denseStub)
                     return false;
                 if (!denseStub->addUpdateStubForValue(cx, script, obj, JSID_VOIDHANDLE, rhs))
                     return false;
 
-                stub->addNewStub(cx, denseStub);
+                stub->addNewStub(denseStub);
             }
         }
 
         return true;
     }
 
     if (obj->is<TypedArrayObject>() && index.isNumber() && rhs.isNumber()) {
         Rooted<TypedArrayObject*> tarr(cx, &obj->as<TypedArrayObject>());
@@ -5056,17 +5053,17 @@ DoSetElemFallback(JSContext *cx, Baselin
                     "  Generating SetElem_TypedArray stub (shape=%p, type=%u, oob=%s)",
                     tarr->lastProperty(), tarr->type(), expectOutOfBounds ? "yes" : "no");
             ICSetElem_TypedArray::Compiler compiler(cx, tarr->lastProperty(), tarr->type(),
                                                     expectOutOfBounds);
             ICStub *typedArrayStub = compiler.getStub(compiler.getStubSpace(script));
             if (!typedArrayStub)
                 return false;
 
-            stub->addNewStub(cx, typedArrayStub);
+            stub->addNewStub(typedArrayStub);
             return true;
         }
     }
 
     return true;
 }
 
 typedef bool (*DoSetElemFallbackFn)(JSContext *, BaselineFrame *, ICSetElem_Fallback *, Value *,
@@ -5106,23 +5103,23 @@ ICSetElem_Fallback::Compiler::generateSt
 
     masm.push(BaselineStubReg);
     masm.pushBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
 
     return tailCallVM(DoSetElemFallbackInfo, masm);
 }
 
 void
-BaselineScript::noteArrayWriteHole(JSContext *cx, uint32_t pcOffset)
+BaselineScript::noteArrayWriteHole(uint32_t pcOffset)
 {
     ICEntry &entry = icEntryFromPCOffset(pcOffset);
     ICFallbackStub *stub = entry.fallbackStub();
 
     if (stub->isSetElem_Fallback())
-        stub->toSetElem_Fallback()->noteArrayWriteHole(cx);
+        stub->toSetElem_Fallback()->noteArrayWriteHole();
 }
 
 //
 // SetElem_Dense
 //
 
 bool
 ICSetElem_Dense::Compiler::generateStubCode(MacroAssembler &masm)
@@ -5634,17 +5631,17 @@ TryAttachGlobalNameStub(JSContext *cx, H
 
     ICStub *monitorStub = stub->fallbackMonitorStub()->firstMonitorStub();
     IonSpew(IonSpew_BaselineIC, "  Generating GetName(GlobalName) stub");
     ICGetName_Global::Compiler compiler(cx, monitorStub, global->lastProperty(), slot);
     ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
     if (!newStub)
         return false;
 
-    stub->addNewStub(cx, newStub);
+    stub->addNewStub(newStub);
     return true;
 }
 
 static bool
 TryAttachScopeNameStub(JSContext *cx, HandleScript script, ICGetName_Fallback *stub,
                        HandleObject initialScopeChain, HandlePropertyName name)
 {
     AutoShapeVector shapes(cx);
@@ -5724,17 +5721,17 @@ TryAttachScopeNameStub(JSContext *cx, Ha
       }
       default:
         return true;
     }
 
     if (!newStub)
         return false;
 
-    stub->addNewStub(cx, newStub);
+    stub->addNewStub(newStub);
     return true;
 }
 
 static bool
 DoGetNameFallback(JSContext *cx, BaselineFrame *frame, ICGetName_Fallback *stub,
                   HandleObject scopeChain, MutableHandleValue res)
 {
     RootedScript script(cx, frame->script());
@@ -5931,17 +5928,17 @@ DoGetIntrinsicFallback(JSContext *cx, Ba
     types::TypeScript::Monitor(cx, script, pc, res);
 
     IonSpew(IonSpew_BaselineIC, "  Generating GetIntrinsic optimized stub");
     ICGetIntrinsic_Constant::Compiler compiler(cx, res);
     ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
     if (!newStub)
         return false;
 
-    stub->addNewStub(cx, newStub);
+    stub->addNewStub(newStub);
     return true;
 }
 
 typedef bool (*DoGetIntrinsicFallbackFn)(JSContext *, BaselineFrame *, ICGetIntrinsic_Fallback *,
                                          MutableHandleValue);
 static const VMFunction DoGetIntrinsicFallbackInfo =
     FunctionInfo<DoGetIntrinsicFallbackFn>(DoGetIntrinsicFallback);
 
@@ -5979,74 +5976,74 @@ TryAttachLengthStub(JSContext *cx, JSScr
         JS_ASSERT(res.isInt32());
         IonSpew(IonSpew_BaselineIC, "  Generating GetProp(String.length) stub");
         ICGetProp_StringLength::Compiler compiler(cx);
         ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
         if (!newStub)
             return false;
 
         *attached = true;
-        stub->addNewStub(cx, newStub);
+        stub->addNewStub(newStub);
         return true;
     }
 
     if (val.isMagic(JS_OPTIMIZED_ARGUMENTS) && res.isInt32()) {
         IonSpew(IonSpew_BaselineIC, "  Generating GetProp(MagicArgs.length) stub");
         ICGetProp_ArgumentsLength::Compiler compiler(cx, ICGetProp_ArgumentsLength::Magic);
         ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
         if (!newStub)
             return false;
 
         *attached = true;
-        stub->addNewStub(cx, newStub);
+        stub->addNewStub(newStub);
         return true;
     }
 
     if (!val.isObject())
         return true;
 
     RootedObject obj(cx, &val.toObject());
 
     if (obj->is<ArrayObject>() && res.isInt32()) {
         IonSpew(IonSpew_BaselineIC, "  Generating GetProp(Array.length) stub");
         ICGetProp_ArrayLength::Compiler compiler(cx);
         ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
         if (!newStub)
             return false;
 
         *attached = true;
-        stub->addNewStub(cx, newStub);
+        stub->addNewStub(newStub);
         return true;
     }
     if (obj->is<TypedArrayObject>()) {
         JS_ASSERT(res.isInt32());
         IonSpew(IonSpew_BaselineIC, "  Generating GetProp(TypedArray.length) stub");
         ICGetProp_TypedArrayLength::Compiler compiler(cx);
         ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
         if (!newStub)
             return false;
 
         *attached = true;
-        stub->addNewStub(cx, newStub);
+        stub->addNewStub(newStub);
         return true;
     }
 
     if (obj->is<ArgumentsObject>() && res.isInt32()) {
         IonSpew(IonSpew_BaselineIC, "  Generating GetProp(ArgsObj.length %s) stub",
                 obj->is<StrictArgumentsObject>() ? "Strict" : "Normal");
         ICGetProp_ArgumentsLength::Which which = ICGetProp_ArgumentsLength::Normal;
         if (obj->is<StrictArgumentsObject>())
             which = ICGetProp_ArgumentsLength::Strict;
         ICGetProp_ArgumentsLength::Compiler compiler(cx, which);
         ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
         if (!newStub)
             return false;
 
         *attached = true;
-        stub->addNewStub(cx, newStub);
+        stub->addNewStub(newStub);
         return true;
     }
 
     return true;
 }
 
 static bool
 UpdateExistingGenerationalDOMProxyStub(ICGetProp_Fallback *stub,
@@ -6119,17 +6116,17 @@ TryAttachNativeGetPropStub(JSContext *cx
                     isDOMProxy ? "DOMProxy" : "Native",
                     (obj == holder) ? "direct" : "prototype");
         ICGetPropNativeCompiler compiler(cx, kind, isCallProp, monitorStub, obj, holder,
                                          name, isFixedSlot, offset);
         ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
         if (!newStub)
             return false;
 
-        stub->addNewStub(cx, newStub);
+        stub->addNewStub(newStub);
         *attached = true;
         return true;
     }
 
     bool isScripted = false;
     bool cacheableCall = IsCacheableGetPropCall(cx, obj, holder, shape, &isScripted, isDOMProxy);
 
     // Try handling scripted getters.
@@ -6150,17 +6147,17 @@ TryAttachNativeGetPropStub(JSContext *cx
                     callee->nonLazyScript()->filename(), callee->nonLazyScript()->lineno());
 
         ICGetProp_CallScripted::Compiler compiler(cx, monitorStub, obj, holder, callee,
                                                   script->pcToOffset(pc));
         ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
         if (!newStub)
             return false;
 
-        stub->addNewStub(cx, newStub);
+        stub->addNewStub(newStub);
         *attached = true;
         return true;
     }
 
     // Try handling JSNative getters.
     if (cacheableCall && !isScripted) {
 #if JS_HAS_NO_SUCH_METHOD
         // It's unlikely that a getter function will be used to generate functions for calling
@@ -6197,17 +6194,17 @@ TryAttachNativeGetPropStub(JSContext *cx
             newStub = compiler.getStub(compiler.getStubSpace(script));
         } else {
             ICGetProp_CallNative::Compiler compiler(cx, monitorStub, obj, holder, callee,
                                                     script->pcToOffset(pc));
             newStub = compiler.getStub(compiler.getStubSpace(script));
         }
         if (!newStub)
             return false;
-        stub->addNewStub(cx, newStub);
+        stub->addNewStub(newStub);
         *attached = true;
         return true;
     }
 
     // If it's a shadowed listbase proxy property, attach stub to call Proxy::get instead.
     if (isDOMProxy && domProxyShadowsResult == Shadows) {
         JS_ASSERT(obj == holder);
 #if JS_HAS_NO_SUCH_METHOD
@@ -6217,17 +6214,17 @@ TryAttachNativeGetPropStub(JSContext *cx
 
         IonSpew(IonSpew_BaselineIC, "  Generating GetProp(DOMProxyProxy) stub");
         Rooted<ProxyObject*> proxy(cx, &obj->as<ProxyObject>());
         ICGetProp_DOMProxyShadowed::Compiler compiler(cx, monitorStub, proxy, name,
                                                       script->pcToOffset(pc));
         ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
         if (!newStub)
             return false;
-        stub->addNewStub(cx, newStub);
+        stub->addNewStub(newStub);
         *attached = true;
         return true;
     }
 
     return true;
 }
 
 static bool
@@ -6272,17 +6269,17 @@ TryAttachPrimitiveGetPropStub(JSContext 
 
     IonSpew(IonSpew_BaselineIC, "  Generating GetProp_Primitive stub");
     ICGetProp_Primitive::Compiler compiler(cx, monitorStub, primitiveType, proto,
                                            isFixedSlot, offset);
     ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
     if (!newStub)
         return false;
 
-    stub->addNewStub(cx, newStub);
+    stub->addNewStub(newStub);
     *attached = true;
     return true;
 }
 
 static bool
 DoGetPropFallback(JSContext *cx, BaselineFrame *frame, ICGetProp_Fallback *stub,
                   MutableHandleValue val, MutableHandleValue res)
 {
@@ -6359,17 +6356,17 @@ DoGetPropFallback(JSContext *cx, Baselin
     if (val.isString() || val.isNumber() || val.isBoolean()) {
         if (!TryAttachPrimitiveGetPropStub(cx, script, pc, stub, name, val, res, &attached))
             return false;
         if (attached)
             return true;
     }
 
     JS_ASSERT(!attached);
-    stub->noteUnoptimizableAccess(cx);
+    stub->noteUnoptimizableAccess();
 
     return true;
 }
 
 typedef bool (*DoGetPropFallbackFn)(JSContext *, BaselineFrame *, ICGetProp_Fallback *,
                                     MutableHandleValue, MutableHandleValue);
 static const VMFunction DoGetPropFallbackInfo =
     FunctionInfo<DoGetPropFallbackFn>(DoGetPropFallback, PopValues(1));
@@ -7104,23 +7101,23 @@ ICGetProp_ArgumentsLength::Compiler::gen
     EmitReturnFromIC(masm);
 
     masm.bind(&failure);
     EmitStubGuardFailure(masm);
     return true;
 }
 
 void
-BaselineScript::noteAccessedGetter(JSContext *cx, uint32_t pcOffset)
+BaselineScript::noteAccessedGetter(uint32_t pcOffset)
 {
     ICEntry &entry = icEntryFromPCOffset(pcOffset);
     ICFallbackStub *stub = entry.fallbackStub();
 
     if (stub->isGetProp_Fallback())
-        stub->toGetProp_Fallback()->noteAccessedGetter(cx);
+        stub->toGetProp_Fallback()->noteAccessedGetter();
 }
 
 //
 // SetProp_Fallback
 //
 
 // Attach an optimized stub for a SETPROP/SETGNAME/SETNAME op.
 static bool
@@ -7151,17 +7148,17 @@ TryAttachSetPropStub(JSContext *cx, Hand
         IonSpew(IonSpew_BaselineIC, "  Generating SetProp(NativeObject.ADD) stub");
         ICSetPropNativeAddCompiler compiler(cx, obj, oldShape, chainDepth, isFixedSlot, offset);
         ICUpdatedStub *newStub = compiler.getStub(compiler.getStubSpace(script));
         if (!newStub)
             return false;
         if (!newStub->addUpdateStubForValue(cx, script, obj, id, rhs))
             return false;
 
-        stub->addNewStub(cx, newStub);
+        stub->addNewStub(newStub);
         *attached = true;
         return true;
     }
 
     if (IsCacheableSetPropWriteSlot(obj, oldShape, holder, shape)) {
         bool isFixedSlot;
         uint32_t offset;
         GetFixedOrDynamicSlotOffset(obj, shape->slot(), &isFixedSlot, &offset);
@@ -7169,17 +7166,17 @@ TryAttachSetPropStub(JSContext *cx, Hand
         IonSpew(IonSpew_BaselineIC, "  Generating SetProp(NativeObject.PROP) stub");
         ICSetProp_Native::Compiler compiler(cx, obj, isFixedSlot, offset);
         ICUpdatedStub *newStub = compiler.getStub(compiler.getStubSpace(script));
         if (!newStub)
             return false;
         if (!newStub->addUpdateStubForValue(cx, script, obj, id, rhs))
             return false;
 
-        stub->addNewStub(cx, newStub);
+        stub->addNewStub(newStub);
         *attached = true;
         return true;
     }
 
     bool isScripted = false;
     bool cacheableCall = IsCacheableSetPropCall(cx, obj, holder, shape, &isScripted);
 
     // Try handling scripted setters.
@@ -7191,17 +7188,17 @@ TryAttachSetPropStub(JSContext *cx, Hand
         IonSpew(IonSpew_BaselineIC, "  Generating SetProp(NativeObj/ScriptedSetter %s:%d) stub",
                     callee->nonLazyScript()->filename(), callee->nonLazyScript()->lineno());
 
         ICSetProp_CallScripted::Compiler compiler(cx, obj, holder, callee, script->pcToOffset(pc));
         ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
         if (!newStub)
             return false;
 
-        stub->addNewStub(cx, newStub);
+        stub->addNewStub(newStub);
         *attached = true;
         return true;
     }
 
     // Try handling JSNative setters.
     if (cacheableCall && !isScripted) {
         RootedFunction callee(cx, &shape->setterObject()->as<JSFunction>());
         JS_ASSERT(obj != holder);
@@ -7210,17 +7207,17 @@ TryAttachSetPropStub(JSContext *cx, Hand
         IonSpew(IonSpew_BaselineIC, "  Generating SetProp(NativeObj/NativeSetter %p) stub",
                     callee->native());
 
         ICSetProp_CallNative::Compiler compiler(cx, obj, holder, callee, script->pcToOffset(pc));
         ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
         if (!newStub)
             return false;
 
-        stub->addNewStub(cx, newStub);
+        stub->addNewStub(newStub);
         *attached = true;
         return true;
     }
 
     return true;
 }
 
 static bool
@@ -7285,17 +7282,17 @@ DoSetPropFallback(JSContext *cx, Baselin
          &attached))
     {
         return false;
     }
     if (attached)
         return true;
 
     JS_ASSERT(!attached);
-    stub->noteUnoptimizableAccess(cx);
+    stub->noteUnoptimizableAccess();
 
     return true;
 }
 
 typedef bool (*DoSetPropFallbackFn)(JSContext *, BaselineFrame *, ICSetProp_Fallback *,
                                     HandleValue, HandleValue, MutableHandleValue);
 static const VMFunction DoSetPropFallbackInfo =
     FunctionInfo<DoSetPropFallbackFn>(DoSetPropFallback, PopValues(2));
@@ -7791,34 +7788,34 @@ TryAttachFunApplyStub(JSContext *cx, ICC
             IonSpew(IonSpew_BaselineIC, "  Generating Call_ScriptedApplyArguments stub");
 
             ICCall_ScriptedApplyArguments::Compiler compiler(
                 cx, stub->fallbackMonitorStub()->firstMonitorStub(), script->pcToOffset(pc));
             ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
             if (!newStub)
                 return false;
 
-            stub->addNewStub(cx, newStub);
+            stub->addNewStub(newStub);
             return true;
         }
 
         // TODO: handle FUNAPPLY for native targets.
     }
 
     if (argv[1].isObject() && argv[1].toObject().is<ArrayObject>()) {
         if (isScripted && !stub->hasStub(ICStub::Call_ScriptedApplyArray)) {
             IonSpew(IonSpew_BaselineIC, "  Generating Call_ScriptedApplyArray stub");
 
             ICCall_ScriptedApplyArray::Compiler compiler(
                 cx, stub->fallbackMonitorStub()->firstMonitorStub(), script->pcToOffset(pc));
             ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
             if (!newStub)
                 return false;
 
-            stub->addNewStub(cx, newStub);
+            stub->addNewStub(newStub);
             return true;
         }
     }
     return true;
 }
 
 static bool
 GetTemplateObjectForNative(JSContext *cx, HandleScript script, jsbytecode *pc,
@@ -7952,17 +7949,17 @@ TryAttachCallStub(JSContext *cx, ICCall_
             ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
             if (!newStub)
                 return false;
 
             // Before adding new stub, unlink all previous Call_Scripted.
             stub->unlinkStubsWithKind(cx, ICStub::Call_Scripted);
 
             // Add new generalized stub.
-            stub->addNewStub(cx, newStub);
+            stub->addNewStub(newStub);
             return true;
         }
 
         // Keep track of the function's |prototype| property in type
         // information, for use during Ion compilation.
         if (IsIonEnabled(cx))
             types::EnsureTrackPropertyTypes(cx, fun, NameToId(cx->names().prototype));
 
@@ -7981,17 +7978,17 @@ TryAttachCallStub(JSContext *cx, ICCall_
                 constructing ? "yes" : "no");
         ICCallScriptedCompiler compiler(cx, stub->fallbackMonitorStub()->firstMonitorStub(),
                                         calleeScript, templateObject,
                                         constructing, script->pcToOffset(pc));
         ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
         if (!newStub)
             return false;
 
-        stub->addNewStub(cx, newStub);
+        stub->addNewStub(newStub);
         return true;
     }
 
     if (fun->isNative() && (!constructing || (constructing && fun->isNativeConstructor()))) {
         // Generalized native call stubs are not here yet!
         JS_ASSERT(!stub->nativeStubsAreGeneralized());
 
         // Check for JSOP_FUNAPPLY
@@ -8018,17 +8015,17 @@ TryAttachCallStub(JSContext *cx, ICCall_
         IonSpew(IonSpew_BaselineIC, "  Generating Call_Native stub (fun=%p, cons=%s)",
                 fun.get(), constructing ? "yes" : "no");
         ICCall_Native::Compiler compiler(cx, stub->fallbackMonitorStub()->firstMonitorStub(),
                                          fun, templateObject, constructing, script->pcToOffset(pc));
         ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
         if (!newStub)
             return false;
 
-        stub->addNewStub(cx, newStub);
+        stub->addNewStub(newStub);
         return true;
     }
 
     return true;
 }
 
 static bool
 MaybeCloneFunctionAtCallsite(JSContext *cx, MutableHandleValue callee, HandleScript script,
@@ -9150,17 +9147,17 @@ DoIteratorMoreFallback(JSContext *cx, Ba
 
     if (iterValue.toObject().is<PropertyIteratorObject>() &&
         !stub->hasStub(ICStub::IteratorMore_Native))
     {
         ICIteratorMore_Native::Compiler compiler(cx);
         ICStub *newStub = compiler.getStub(compiler.getStubSpace(frame->script()));
         if (!newStub)
             return false;
-        stub->addNewStub(cx, newStub);
+        stub->addNewStub(newStub);
     }
 
     return true;
 }
 
 typedef bool (*DoIteratorMoreFallbackFn)(JSContext *, BaselineFrame *, ICIteratorMore_Fallback *,
                                          HandleValue, MutableHandleValue);
 static const VMFunction DoIteratorMoreFallbackInfo =
@@ -9224,26 +9221,26 @@ DoIteratorNextFallback(JSContext *cx, Ba
 {
     FallbackICSpew(cx, stub, "IteratorNext");
 
     RootedObject iteratorObject(cx, &iterValue.toObject());
     if (!IteratorNext(cx, iteratorObject, res))
         return false;
 
     if (!res.isString() && !stub->hasNonStringResult())
-        stub->setHasNonStringResult(cx);
+        stub->setHasNonStringResult();
 
     if (iteratorObject->is<PropertyIteratorObject>() &&
         !stub->hasStub(ICStub::IteratorNext_Native))
     {
         ICIteratorNext_Native::Compiler compiler(cx);
         ICStub *newStub = compiler.getStub(compiler.getStubSpace(frame->script()));
         if (!newStub)
             return false;
-        stub->addNewStub(cx, newStub);
+        stub->addNewStub(newStub);
     }
 
     return true;
 }
 
 typedef bool (*DoIteratorNextFallbackFn)(JSContext *, BaselineFrame *, ICIteratorNext_Fallback *,
                                          HandleValue, MutableHandleValue);
 static const VMFunction DoIteratorNextFallbackInfo =
@@ -9397,17 +9394,17 @@ DoTypeOfFallback(JSContext *cx, Baseline
     JS_ASSERT(type != JSTYPE_NULL);
     if (type != JSTYPE_OBJECT && type != JSTYPE_FUNCTION) {
         // Create a new TypeOf stub.
         IonSpew(IonSpew_BaselineIC, "  Generating TypeOf stub for JSType (%d)", (int) type);
         ICTypeOf_Typed::Compiler compiler(cx, type, string);
         ICStub *typeOfStub = compiler.getStub(compiler.getStubSpace(frame->script()));
         if (!typeOfStub)
             return false;
-        stub->addNewStub(cx, typeOfStub);
+        stub->addNewStub(typeOfStub);
     }
 
     return true;
 }
 
 typedef bool (*DoTypeOfFallbackFn)(JSContext *, BaselineFrame *frame, ICTypeOf_Fallback *,
                                    HandleValue, MutableHandleValue);
 static const VMFunction DoTypeOfFallbackInfo =
@@ -9484,17 +9481,17 @@ DoRetSubFallback(JSContext *cx, Baseline
 
     // Attach an optimized stub for this pc offset.
     IonSpew(IonSpew_BaselineIC, "  Generating RetSub stub for pc offset %u", offset);
     ICRetSub_Resume::Compiler compiler(cx, offset, *resumeAddr);
     ICStub *optStub = compiler.getStub(compiler.getStubSpace(script));
     if (!optStub)
         return false;
 
-    stub->addNewStub(cx, optStub);
+    stub->addNewStub(optStub);
     return true;
 }
 
 typedef bool(*DoRetSubFallbackFn)(JSContext *cx, BaselineFrame *, ICRetSub_Fallback *,
                                   HandleValue, uint8_t **);
 static const VMFunction DoRetSubFallbackInfo = FunctionInfo<DoRetSubFallbackFn>(DoRetSubFallback);
 
 typedef bool (*ThrowFn)(JSContext *, HandleValue);
--- a/js/src/jit/BaselineIC.h
+++ b/js/src/jit/BaselineIC.h
@@ -830,18 +830,17 @@ class ICFallbackStub : public ICStub
     void fixupICEntry(ICEntry *icEntry) {
         JS_ASSERT(icEntry_ == nullptr);
         JS_ASSERT(lastStubPtrAddr_ == nullptr);
         icEntry_ = icEntry;
         lastStubPtrAddr_ = icEntry_->addressOfFirstStub();
     }
 
     // Add a new stub to the IC chain terminated by this fallback stub.
-    void addNewStub(JSContext *cx, ICStub *stub) {
-        AutoLockForCompilation lock(cx);
+    void addNewStub(ICStub *stub) {
         JS_ASSERT(*lastStubPtrAddr_ == this);
         JS_ASSERT(stub->next() == nullptr);
         stub->setNext(this);
         *lastStubPtrAddr_ = stub;
         lastStubPtrAddr_ = stub->addressOfNext();
         numOptimizedStubs_++;
     }
 
@@ -2437,25 +2436,23 @@ class ICBinaryArith_Fallback : public IC
         if (!code)
             return nullptr;
         return space->allocate<ICBinaryArith_Fallback>(code);
     }
 
     bool sawDoubleResult() const {
         return extra_ & SAW_DOUBLE_RESULT_BIT;
     }
-    void setSawDoubleResult(JSContext *cx) {
-        AutoLockForCompilation lock(cx);
+    void setSawDoubleResult() {
         extra_ |= SAW_DOUBLE_RESULT_BIT;
     }
     bool hadUnoptimizableOperands() const {
         return extra_ & UNOPTIMIZABLE_OPERANDS_BIT;
     }
-    void noteUnoptimizableOperands(JSContext *cx) {
-        AutoLockForCompilation lock(cx);
+    void noteUnoptimizableOperands() {
         extra_ |= UNOPTIMIZABLE_OPERANDS_BIT;
     }
 
     // Compiler for this stub kind.
     class Compiler : public ICStubCompiler {
       protected:
         bool generateStubCode(MacroAssembler &masm);
 
@@ -2846,26 +2843,24 @@ class ICGetElem_Fallback : public ICMoni
     static const uint32_t MAX_OPTIMIZED_STUBS = 16;
 
     static inline ICGetElem_Fallback *New(ICStubSpace *space, JitCode *code) {
         if (!code)
             return nullptr;
         return space->allocate<ICGetElem_Fallback>(code);
     }
 
-    void noteNonNativeAccess(JSContext *cx) {
-        AutoLockForCompilation lock(cx);
+    void noteNonNativeAccess() {
         extra_ |= EXTRA_NON_NATIVE;
     }
     bool hasNonNativeAccess() const {
         return extra_ & EXTRA_NON_NATIVE;
     }
 
-    void noteNegativeIndex(JSContext *cx) {
-        AutoLockForCompilation lock(cx);
+    void noteNegativeIndex() {
         extra_ |= EXTRA_NEGATIVE_INDEX;
     }
     bool hasNegativeIndex() const {
         return extra_ & EXTRA_NEGATIVE_INDEX;
     }
 
     // Compiler for this stub kind.
     class Compiler : public ICStubCompiler {
@@ -3443,18 +3438,17 @@ class ICSetElem_Fallback : public ICFall
     static const uint32_t MAX_OPTIMIZED_STUBS = 8;
 
     static inline ICSetElem_Fallback *New(ICStubSpace *space, JitCode *code) {
         if (!code)
             return nullptr;
         return space->allocate<ICSetElem_Fallback>(code);
     }
 
-    void noteArrayWriteHole(JSContext *cx) {
-        AutoLockForCompilation lock(cx);
+    void noteArrayWriteHole() {
         extra_ = 1;
     }
     bool hasArrayWriteHole() const {
         return extra_;
     }
 
     // Compiler for this stub kind.
     class Compiler : public ICStubCompiler {
@@ -4019,26 +4013,24 @@ class ICGetProp_Fallback : public ICMoni
         if (!code)
             return nullptr;
         return space->allocate<ICGetProp_Fallback>(code);
     }
 
     static const size_t UNOPTIMIZABLE_ACCESS_BIT = 0;
     static const size_t ACCESSED_GETTER_BIT = 1;
 
-    void noteUnoptimizableAccess(JSContext *cx) {
-        AutoLockForCompilation lock(cx);
+    void noteUnoptimizableAccess() {
         extra_ |= (1u << UNOPTIMIZABLE_ACCESS_BIT);
     }
     bool hadUnoptimizableAccess() const {
         return extra_ & (1u << UNOPTIMIZABLE_ACCESS_BIT);
     }
 
-    void noteAccessedGetter(JSContext *cx) {
-        AutoLockForCompilation lock(cx);
+    void noteAccessedGetter() {
         extra_ |= (1u << ACCESSED_GETTER_BIT);
     }
     bool hasAccessedGetter() const {
         return extra_ & (1u << ACCESSED_GETTER_BIT);
     }
 
     class Compiler : public ICStubCompiler {
       protected:
@@ -4835,18 +4827,17 @@ class ICSetProp_Fallback : public ICFall
 
     static inline ICSetProp_Fallback *New(ICStubSpace *space, JitCode *code) {
         if (!code)
             return nullptr;
         return space->allocate<ICSetProp_Fallback>(code);
     }
 
     static const size_t UNOPTIMIZABLE_ACCESS_BIT = 0;
-    void noteUnoptimizableAccess(JSContext *cx) {
-        AutoLockForCompilation lock(cx);
+    void noteUnoptimizableAccess() {
         extra_ |= (1u << UNOPTIMIZABLE_ACCESS_BIT);
     }
     bool hadUnoptimizableAccess() const {
         return extra_ & (1u << UNOPTIMIZABLE_ACCESS_BIT);
     }
 
     class Compiler : public ICStubCompiler {
       protected:
@@ -5737,18 +5728,17 @@ class ICIteratorNext_Fallback : public I
 
   public:
     static inline ICIteratorNext_Fallback *New(ICStubSpace *space, JitCode *code) {
         if (!code)
             return nullptr;
         return space->allocate<ICIteratorNext_Fallback>(code);
     }
 
-    void setHasNonStringResult(JSContext *cx) {
-        AutoLockForCompilation lock(cx);
+    void setHasNonStringResult() {
         JS_ASSERT(extra_ == 0);
         extra_ = 1;
     }
     bool hasNonStringResult() const {
         return extra_;
     }
 
     class Compiler : public ICStubCompiler {
--- a/js/src/jit/BaselineInspector.cpp
+++ b/js/src/jit/BaselineInspector.cpp
@@ -13,18 +13,16 @@
 using namespace js;
 using namespace js::jit;
 
 using mozilla::DebugOnly;
 
 bool
 SetElemICInspector::sawOOBDenseWrite() const
 {
-    JS_ASSERT(CurrentThreadCanReadCompilationData());
-
     if (!icEntry_)
         return false;
 
     // Check for a SetElem_DenseAdd stub.
     for (ICStub *stub = icEntry_->firstStub(); stub; stub = stub->next()) {
         if (stub->isSetElem_DenseAdd())
             return true;
     }
@@ -35,68 +33,60 @@ SetElemICInspector::sawOOBDenseWrite() c
         return stub->toSetElem_Fallback()->hasArrayWriteHole();
 
     return false;
 }
 
 bool
 SetElemICInspector::sawOOBTypedArrayWrite() const
 {
-    JS_ASSERT(CurrentThreadCanReadCompilationData());
-
     if (!icEntry_)
         return false;
 
     // Check for SetElem_TypedArray stubs with expectOutOfBounds set.
     for (ICStub *stub = icEntry_->firstStub(); stub; stub = stub->next()) {
         if (!stub->isSetElem_TypedArray())
             continue;
         if (stub->toSetElem_TypedArray()->expectOutOfBounds())
             return true;
     }
     return false;
 }
 
 bool
 SetElemICInspector::sawDenseWrite() const
 {
-    JS_ASSERT(CurrentThreadCanReadCompilationData());
-
     if (!icEntry_)
         return false;
 
     // Check for a SetElem_DenseAdd or SetElem_Dense stub.
     for (ICStub *stub = icEntry_->firstStub(); stub; stub = stub->next()) {
         if (stub->isSetElem_DenseAdd() || stub->isSetElem_Dense())
             return true;
     }
     return false;
 }
 
 bool
 SetElemICInspector::sawTypedArrayWrite() const
 {
-    JS_ASSERT(CurrentThreadCanReadCompilationData());
-
     if (!icEntry_)
         return false;
 
     // Check for a SetElem_TypedArray stub.
     for (ICStub *stub = icEntry_->firstStub(); stub; stub = stub->next()) {
         if (stub->isSetElem_TypedArray())
             return true;
     }
     return false;
 }
 
 bool
 BaselineInspector::maybeShapesForPropertyOp(jsbytecode *pc, ShapeVector &shapes)
 {
-    JS_ASSERT(CurrentThreadCanReadCompilationData());
-
     // Return a list of shapes seen by the baseline IC for the current op.
     // An empty list indicates no shapes are known, or there was an uncacheable
     // access.
     JS_ASSERT(shapes.empty());
 
     if (!hasBaselineScript())
         return true;
 
@@ -144,18 +134,16 @@ BaselineInspector::maybeShapesForPropert
         shapes.clear();
 
     return true;
 }
 
 ICStub *
 BaselineInspector::monomorphicStub(jsbytecode *pc)
 {
-    JS_ASSERT(CurrentThreadCanReadCompilationData());
-
     if (!hasBaselineScript())
         return nullptr;
 
     const ICEntry &entry = icEntryFromPC(pc);
 
     ICStub *stub = entry.firstStub();
     ICStub *next = stub->next();
 
@@ -163,18 +151,16 @@ BaselineInspector::monomorphicStub(jsbyt
         return nullptr;
 
     return stub;
 }
 
 bool
 BaselineInspector::dimorphicStub(jsbytecode *pc, ICStub **pfirst, ICStub **psecond)
 {
-    JS_ASSERT(CurrentThreadCanReadCompilationData());
-
     if (!hasBaselineScript())
         return false;
 
     const ICEntry &entry = icEntryFromPC(pc);
 
     ICStub *stub = entry.firstStub();
     ICStub *next = stub->next();
     ICStub *after = next ? next->next() : nullptr;
@@ -185,18 +171,16 @@ BaselineInspector::dimorphicStub(jsbytec
     *pfirst = stub;
     *psecond = next;
     return true;
 }
 
 MIRType
 BaselineInspector::expectedResultType(jsbytecode *pc)
 {
-    JS_ASSERT(CurrentThreadCanReadCompilationData());
-
     // Look at the IC entries for this op to guess what type it will produce,
     // returning MIRType_None otherwise.
 
     ICStub *stub = monomorphicStub(pc);
     if (!stub)
         return MIRType_None;
 
     switch (stub->kind()) {
@@ -233,18 +217,16 @@ static bool
 CanUseInt32Compare(ICStub::Kind kind)
 {
     return kind == ICStub::Compare_Int32 || kind == ICStub::Compare_Int32WithBoolean;
 }
 
 MCompare::CompareType
 BaselineInspector::expectedCompareType(jsbytecode *pc)
 {
-    JS_ASSERT(CurrentThreadCanReadCompilationData());
-
     ICStub *first = monomorphicStub(pc), *second = nullptr;
     if (!first && !dimorphicStub(pc, &first, &second))
         return MCompare::Compare_Unknown;
 
     if (CanUseInt32Compare(first->kind()) && (!second || CanUseInt32Compare(second->kind()))) {
         ICCompare_Int32WithBoolean *coerce =
             first->isCompare_Int32WithBoolean()
             ? first->toCompare_Int32WithBoolean()
@@ -317,18 +299,16 @@ TryToSpecializeBinaryArithOp(ICStub **st
     JS_ASSERT(sawInt32);
     *result = MIRType_Int32;
     return true;
 }
 
 MIRType
 BaselineInspector::expectedBinaryArithSpecialization(jsbytecode *pc)
 {
-    JS_ASSERT(CurrentThreadCanReadCompilationData());
-
     MIRType result;
     ICStub *stubs[2];
 
     const ICEntry &entry = icEntryFromPC(pc);
     ICStub *stub = entry.fallbackStub();
     if (stub->isBinaryArith_Fallback() &&
         stub->toBinaryArith_Fallback()->hadUnoptimizableOperands())
     {
@@ -347,82 +327,72 @@ BaselineInspector::expectedBinaryArithSp
     }
 
     return MIRType_None;
 }
 
 bool
 BaselineInspector::hasSeenNonNativeGetElement(jsbytecode *pc)
 {
-    JS_ASSERT(CurrentThreadCanReadCompilationData());
-
     if (!hasBaselineScript())
         return false;
 
     const ICEntry &entry = icEntryFromPC(pc);
     ICStub *stub = entry.fallbackStub();
 
     if (stub->isGetElem_Fallback())
         return stub->toGetElem_Fallback()->hasNonNativeAccess();
     return false;
 }
 
 bool
 BaselineInspector::hasSeenNegativeIndexGetElement(jsbytecode *pc)
 {
-    JS_ASSERT(CurrentThreadCanReadCompilationData());
-
     if (!hasBaselineScript())
         return false;
 
     const ICEntry &entry = icEntryFromPC(pc);
     ICStub *stub = entry.fallbackStub();
 
     if (stub->isGetElem_Fallback())
         return stub->toGetElem_Fallback()->hasNegativeIndex();
     return false;
 }
 
 bool
 BaselineInspector::hasSeenAccessedGetter(jsbytecode *pc)
 {
-    JS_ASSERT(CurrentThreadCanReadCompilationData());
-
     if (!hasBaselineScript())
         return false;
 
     const ICEntry &entry = icEntryFromPC(pc);
     ICStub *stub = entry.fallbackStub();
 
     if (stub->isGetProp_Fallback())
         return stub->toGetProp_Fallback()->hasAccessedGetter();
     return false;
 }
 
 bool
 BaselineInspector::hasSeenNonStringIterNext(jsbytecode *pc)
 {
-    JS_ASSERT(CurrentThreadCanReadCompilationData());
-
     JS_ASSERT(JSOp(*pc) == JSOP_ITERNEXT);
 
     if (!hasBaselineScript())
         return false;
 
     const ICEntry &entry = icEntryFromPC(pc);
     ICStub *stub = entry.fallbackStub();
 
     return stub->toIteratorNext_Fallback()->hasNonStringResult();
 }
 
 bool
 BaselineInspector::hasSeenDoubleResult(jsbytecode *pc)
 {
-    JS_ASSERT(CurrentThreadCanReadCompilationData());
-
     if (!hasBaselineScript())
         return false;
 
     const ICEntry &entry = icEntryFromPC(pc);
     ICStub *stub = entry.fallbackStub();
 
     JS_ASSERT(stub->isUnaryArith_Fallback() || stub->isBinaryArith_Fallback());
 
@@ -432,18 +402,16 @@ BaselineInspector::hasSeenDoubleResult(j
         return stub->toBinaryArith_Fallback()->sawDoubleResult();
 
     return false;
 }
 
 JSObject *
 BaselineInspector::getTemplateObject(jsbytecode *pc)
 {
-    JS_ASSERT(CurrentThreadCanReadCompilationData());
-
     if (!hasBaselineScript())
         return nullptr;
 
     const ICEntry &entry = icEntryFromPC(pc);
     for (ICStub *stub = entry.firstStub(); stub; stub = stub->next()) {
         switch (stub->kind()) {
           case ICStub::NewArray_Fallback:
             return stub->toNewArray_Fallback()->templateObject();
@@ -461,18 +429,16 @@ BaselineInspector::getTemplateObject(jsb
     }
 
     return nullptr;
 }
 
 JSObject *
 BaselineInspector::getTemplateObjectForNative(jsbytecode *pc, Native native)
 {
-    JS_ASSERT(CurrentThreadCanReadCompilationData());
-
     if (!hasBaselineScript())
         return nullptr;
 
     const ICEntry &entry = icEntryFromPC(pc);
     for (ICStub *stub = entry.firstStub(); stub; stub = stub->next()) {
         if (stub->isCall_Native() && stub->toCall_Native()->callee()->native() == native)
             return stub->toCall_Native()->templateObject();
     }
@@ -496,35 +462,31 @@ BaselineInspector::templateCallObject()
     JS_ASSERT(res);
 
     return &res->as<CallObject>();
 }
 
 JSObject *
 BaselineInspector::commonGetPropFunction(jsbytecode *pc, Shape **lastProperty, JSFunction **commonGetter)
 {
-    JS_ASSERT(CurrentThreadCanReadCompilationData());
-
     const ICEntry &entry = icEntryFromPC(pc);
     for (ICStub *stub = entry.firstStub(); stub; stub = stub->next()) {
         if (stub->isGetProp_CallScripted() || stub->isGetProp_CallNative()) {
             ICGetPropCallGetter *nstub = static_cast<ICGetPropCallGetter *>(stub);
             *lastProperty = nstub->holderShape();
             *commonGetter = nstub->getter();
             return nstub->holder();
         }
     }
     return nullptr;
 }
 
 JSObject *
 BaselineInspector::commonSetPropFunction(jsbytecode *pc, Shape **lastProperty, JSFunction **commonSetter)
 {
-    JS_ASSERT(CurrentThreadCanReadCompilationData());
-
     const ICEntry &entry = icEntryFromPC(pc);
     for (ICStub *stub = entry.firstStub(); stub; stub = stub->next()) {
         if (stub->isSetProp_CallScripted() || stub->isSetProp_CallNative()) {
             ICSetPropCallSetter *nstub = static_cast<ICSetPropCallSetter *>(stub);
             *lastProperty = nstub->holderShape();
             *commonSetter = nstub->setter();
             return nstub->holder();
         }
--- a/js/src/jit/BaselineJIT.h
+++ b/js/src/jit/BaselineJIT.h
@@ -289,18 +289,18 @@ struct BaselineScript
 
     // Toggle debug traps (used for breakpoints and step mode) in the script.
     // If |pc| is nullptr, toggle traps for all ops in the script. Else, only
     // toggle traps at |pc|.
     void toggleDebugTraps(JSScript *script, jsbytecode *pc);
 
     void toggleSPS(bool enable);
 
-    void noteAccessedGetter(JSContext *cx, uint32_t pcOffset);
-    void noteArrayWriteHole(JSContext *cx, uint32_t pcOffset);
+    void noteAccessedGetter(uint32_t pcOffset);
+    void noteArrayWriteHole(uint32_t pcOffset);
 
     static size_t offsetOfFlags() {
         return offsetof(BaselineScript, flags_);
     }
 
     static void writeBarrierPre(Zone *zone, BaselineScript *script);
 
     uint32_t *bytecodeTypeMap() {
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -3563,17 +3563,16 @@ static const VMFunction NewCallObjectInf
     FunctionInfo<NewCallObjectFn>(NewCallObject);
 
 bool
 CodeGenerator::visitNewCallObject(LNewCallObject *lir)
 {
     Register obj = ToRegister(lir->output());
 
     JSObject *templateObj = lir->mir()->templateObject();
-    AutoThreadSafeAccess ts(templateObj);
 
     // If we have a template object, we can inline call object creation.
     OutOfLineCode *ool;
     if (lir->slots()->isRegister()) {
         ool = oolCallVM(NewCallObjectInfo, lir,
                         (ArgList(), ImmGCPtr(lir->mir()->block()->info().script()),
                                     ImmGCPtr(templateObj->lastProperty()),
                                     ImmGCPtr(templateObj->hasSingletonType() ? nullptr : templateObj->type()),
--- a/js/src/jit/CompileWrappers.cpp
+++ b/js/src/jit/CompileWrappers.cpp
@@ -247,25 +247,16 @@ CompileCompartment::hasObjectMetadataCal
 // and this would be an unfortunate allocation, but this will not change the
 // semantics of the JavaScript code which is executed.
 void
 CompileCompartment::setSingletonsAsValues()
 {
     return JS::CompartmentOptionsRef(compartment()).setSingletonsAsValues();
 }
 
-#ifdef JS_THREADSAFE
-AutoLockForCompilation::AutoLockForCompilation(CompileCompartment *compartment
-                                               MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
-{
-    MOZ_GUARD_OBJECT_NOTIFIER_INIT;
-    init(compartment->compartment()->runtimeFromAnyThread());
-}
-#endif
-
 JitCompileOptions::JitCompileOptions()
   : cloneSingletons_(false),
     spsSlowAssertionsEnabled_(false)
 {
 }
 
 JitCompileOptions::JitCompileOptions(JSContext *cx)
 {
--- a/js/src/jit/CompileWrappers.h
+++ b/js/src/jit/CompileWrappers.h
@@ -97,18 +97,16 @@ class CompileZone
     const void *addressOfFreeListFirst(gc::AllocKind allocKind);
     const void *addressOfFreeListLast(gc::AllocKind allocKind);
 };
 
 class CompileCompartment
 {
     JSCompartment *compartment();
 
-    friend class js::AutoLockForCompilation;
-
   public:
     static CompileCompartment *get(JSCompartment *comp);
 
     CompileZone *zone();
     CompileRuntime *runtime();
 
     const void *addressOfEnumerators();
 
--- a/js/src/jit/Ion.cpp
+++ b/js/src/jit/Ion.cpp
@@ -47,17 +47,16 @@
 #include "jscompartmentinlines.h"
 #include "jsgcinlines.h"
 #include "jsinferinlines.h"
 #include "jsobjinlines.h"
 
 using namespace js;
 using namespace js::jit;
 
-using mozilla::Maybe;
 using mozilla::ThreadLocal;
 
 // Assert that JitCode is gc::Cell aligned.
 JS_STATIC_ASSERT(sizeof(JitCode) % gc::CellSize == 0);
 
 static ThreadLocal<IonContext*> TlsIonContext;
 
 static IonContext *
@@ -487,18 +486,16 @@ JitCompartment::ensureIonStubsExist(JSCo
 #endif
 
     return true;
 }
 
 void
 jit::FinishOffThreadBuilder(IonBuilder *builder)
 {
-    builder->script()->runtimeFromMainThread()->removeCompilationThread();
-
     ExecutionMode executionMode = builder->info().executionMode();
 
     // Clear the recompiling flag if it would have failed.
     if (builder->script()->hasIonScript())
         builder->script()->ionScript()->clearRecompiling();
 
     // Clean up if compilation did not succeed.
     if (CompilingOffThread(builder->script(), executionMode))
@@ -1560,19 +1557,16 @@ AttachFinishedCompilations(JSContext *cx
                 success = codegen->link(cx, builder->constraints());
             }
 
             if (!success) {
                 // Silently ignore OOM during code generation, we're at an
                 // operation callback and can't propagate failures.
                 cx->clearPendingException();
             }
-        } else {
-            if (builder->abortReason() == AbortReason_Disable)
-                SetIonScript(builder->script(), builder->info().executionMode(), ION_DISABLED_SCRIPT);
         }
 
         FinishOffThreadBuilder(builder);
     }
 #endif
 }
 
 static const size_t BUILDER_LIFO_ALLOC_PRIMARY_CHUNK_SIZE = 1 << 12;
@@ -1717,16 +1711,24 @@ IonCompile(JSContext *cx, JSScript *scri
 
     RootedScript builderScript(cx, builder->script());
 
     if (recompile) {
         JS_ASSERT(executionMode == SequentialExecution);
         builderScript->ionScript()->setRecompiling();
     }
 
+    IonSpewNewFunction(graph, builderScript);
+
+    bool succeeded = builder->build();
+    builder->clearForBackEnd();
+
+    if (!succeeded)
+        return builder->abortReason();
+
     // If possible, compile the script off thread.
     if (OffThreadCompilationAvailable(cx)) {
         if (!recompile)
             SetIonScript(builderScript, executionMode, ION_COMPILING_SCRIPT);
 
         IonSpew(IonSpew_Logs, "Can't log script %s:%d. (Compiled on background thread.)",
                               builderScript->filename(), builderScript->lineno());
 
@@ -1737,52 +1739,22 @@ IonCompile(JSContext *cx, JSScript *scri
 
         // The allocator and associated data will be destroyed after being
         // processed in the finishedOffThreadCompilations list.
         autoDelete.forget();
 
         return AbortReason_NoAbort;
     }
 
-    Maybe<AutoEnterIonCompilation> ionCompiling;
-    if (!cx->runtime()->profilingScripts && !IonSpewEnabled(IonSpew_Logs)) {
-        // Compilation with script profiling is only done on the main thread,
-        // and may modify scripts directly. Same for logging. It is only
-        // enabled when offthread compilation is disabled. So don't watch for
-        // proper use of the compilation lock.
-        ionCompiling.construct();
-    }
-
-    Maybe<AutoProtectHeapForIonCompilation> protect;
-    if (js_JitOptions.checkThreadSafety &&
-        cx->runtime()->gcIncrementalState == gc::NO_INCREMENTAL &&
-        !cx->runtime()->profilingScripts)
-    {
-        protect.construct(cx->runtime());
-    }
-
-    IonSpewNewFunction(graph, builderScript);
-
-    bool succeeded = builder->build();
-    builder->clearForBackEnd();
-
-    if (!succeeded)
-        return builder->abortReason();
-
     ScopedJSDeletePtr<CodeGenerator> codegen(CompileBackEnd(builder));
     if (!codegen) {
         IonSpew(IonSpew_Abort, "Failed during back-end compilation.");
         return AbortReason_Disable;
     }
 
-    if (!protect.empty())
-        protect.destroy();
-    if (!ionCompiling.empty())
-        ionCompiling.destroy();
-
     bool success = codegen->link(cx, builder->constraints());
 
     IonSpewEndFunction();
 
     return success ? AbortReason_NoAbort : AbortReason_Disable;
 }
 
 static bool
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -135,31 +135,23 @@ IonBuilder::IonBuilder(JSContext *analys
     failedShapeGuard_(info->script()->failedShapeGuard()),
     nonStringIteration_(false),
     lazyArguments_(nullptr),
     inlineCallInfo_(nullptr)
 {
     script_ = info->script();
     pc = info->startPC();
 
-#ifdef DEBUG
-    lock();
     JS_ASSERT(script()->hasBaselineScript());
-    unlock();
-#endif
     JS_ASSERT(!!analysisContext == (info->executionMode() == DefinitePropertiesAnalysis));
 }
 
 void
 IonBuilder::clearForBackEnd()
 {
-    // This case should only be hit if there was a failure while building.
-    if (!lock_.empty())
-        lock_.destroy();
-
     JS_ASSERT(!analysisContext);
     baselineFrame_ = nullptr;
 
     // The caches below allocate data from the malloc heap. Release this before
     // later phases of compilation to avoid leaks, as the top level IonBuilder
     // is not explicitly destroyed. Note that builders for inner scripts are
     // constructed on the stack and will release this memory on destruction.
     gsn.purge();
@@ -287,18 +279,16 @@ IonBuilder::getPolyCallTargets(types::Te
         if (obj) {
             if (!obj->is<JSFunction>()) {
                 targets.clear();
                 return true;
             }
             fun = &obj->as<JSFunction>();
         } else {
             types::TypeObject *typeObj = calleeTypes->getTypeObject(i);
-            AutoThreadSafeAccess ts(typeObj);
-
             JS_ASSERT(typeObj);
             if (!typeObj->interpretedFunction) {
                 targets.clear();
                 return true;
             }
 
             fun = typeObj->interpretedFunction;
             *gotLambda = true;
@@ -588,26 +578,22 @@ IonBuilder::pushLoop(CFGState::State ini
     state.loop.initialStopAt = stopAt;
     state.loop.loopHead = loopHead;
     return cfgStack_.append(state);
 }
 
 bool
 IonBuilder::init()
 {
-    lock();
-
     if (!types::TypeScript::FreezeTypeSets(constraints(), script(),
                                            &thisTypes, &argTypes, &typeArray))
     {
         return false;
     }
 
-    unlock();
-
     if (!analysis().init(alloc(), gsn))
         return false;
 
     return true;
 }
 
 bool
 IonBuilder::build()
@@ -716,18 +702,16 @@ IonBuilder::build()
         current->add(lazyArguments_);
     }
 
     insertRecompileCheck();
 
     if (!traverseBytecode())
         return false;
 
-    unlock();
-
     if (!maybeAddOsrTypeBarriers())
         return false;
 
     if (!processIterators())
         return false;
 
     JS_ASSERT(loopDepth_ == 0);
     abortReason_ = AbortReason_NoAbort;
@@ -877,17 +861,16 @@ IonBuilder::buildInline(IonBuilder *call
         current->add(lazyArguments_);
     }
 
     insertRecompileCheck();
 
     if (!traverseBytecode())
         return false;
 
-    unlock();
     return true;
 }
 
 void
 IonBuilder::rewriteParameter(uint32_t slotIdx, MDefinition *param, int32_t argIndex)
 {
     JS_ASSERT(param->isParameter() || param->isGetArgumentsObjectArg());
 
@@ -932,19 +915,16 @@ IonBuilder::initParameters()
 {
     if (!info().funMaybeLazy())
         return true;
 
     // If we are doing OSR on a frame which initially executed in the
     // interpreter and didn't accumulate type information, try to use that OSR
     // frame to determine possible initial types for 'this' and parameters.
 
-    // For unknownProperties() tests under addType.
-    lock();
-
     if (thisTypes->empty() && baselineFrame_) {
         if (!thisTypes->addType(baselineFrame_->thisType, alloc_->lifoAlloc()))
             return false;
     }
 
     MParameter *param = MParameter::New(alloc(), MParameter::THIS_SLOT, thisTypes);
     current->add(param);
     current->initSlot(info().thisSlot(), param);
@@ -958,18 +938,16 @@ IonBuilder::initParameters()
                 return false;
         }
 
         param = MParameter::New(alloc(), i, types);
         current->add(param);
         current->initSlot(info().argSlotUnchecked(i), param);
     }
 
-    unlock();
-
     return true;
 }
 
 bool
 IonBuilder::initScopeChain(MDefinition *callee)
 {
     MInstruction *scope = nullptr;
 
@@ -982,18 +960,16 @@ IonBuilder::initScopeChain(MDefinition *
 
     // The scope chain is only tracked in scripts that have NAME opcodes which
     // will try to access the scope. For other scripts, the scope instructions
     // will be held live by resume points and code will still be generated for
     // them, so just use a constant undefined value.
     if (!script()->compileAndGo())
         return abort("non-CNG global scripts are not supported");
 
-    lock();
-
     if (JSFunction *fun = info().funMaybeLazy()) {
         if (!callee) {
             MCallee *calleeIns = MCallee::New(alloc());
             current->add(calleeIns);
             callee = calleeIns;
         }
         scope = MFunctionEnvironment::New(alloc(), callee);
         current->add(scope);
@@ -1009,18 +985,16 @@ IonBuilder::initScopeChain(MDefinition *
             scope = createCallObject(callee, scope);
             if (!scope)
                 return false;
         }
     } else {
         scope = constant(ObjectValue(script()->global()));
     }
 
-    unlock();
-
     current->setScopeChain(scope);
     return true;
 }
 
 bool
 IonBuilder::initArgumentsObject()
 {
     IonSpew(IonSpew_MIR, "%s:%d - Emitting code to initialize arguments object! block=%p",
@@ -1204,24 +1178,16 @@ IonBuilder::maybeAddOsrTypeBarriers()
 // that there is no active block.
 //
 // For normal diamond join points, we construct Phi nodes as we add
 // predecessors. For loops, care must be taken to propagate Phi nodes back
 // through uses in the loop body.
 bool
 IonBuilder::traverseBytecode()
 {
-    // Always hold the compilation lock when traversing bytecode, though release
-    // it before reacquiring it every few opcodes so that the main thread does not
-    // block for long when updating compilation data.
-    lock();
-
-    size_t lockOpcodeCount = 0;
-    static const size_t LOCK_OPCODE_GRANULARITY = 5;
-
     for (;;) {
         JS_ASSERT(pc < info().limitPC());
 
         for (;;) {
             if (!alloc().ensureBallast())
                 return false;
 
             // Check if we've hit an expected join point or edge in the bytecode.
@@ -1286,22 +1252,16 @@ IonBuilder::traverseBytecode()
         }
 #endif
 
         // Nothing in inspectOpcode() is allowed to advance the pc.
         JSOp op = JSOp(*pc);
         if (!inspectOpcode(op))
             return false;
 
-        if (++lockOpcodeCount == LOCK_OPCODE_GRANULARITY) {
-            unlock();
-            lock();
-            lockOpcodeCount = 0;
-        }
-
 #ifdef DEBUG
         for (size_t i = 0; i < popped.length(); i++) {
             switch (op) {
               case JSOP_POP:
               case JSOP_POPN:
               case JSOP_POPNV:
               case JSOP_DUP:
               case JSOP_DUP2:
@@ -3876,74 +3836,65 @@ IonBuilder::inlineScriptedCall(CallInfo 
 
     // Pop formals again, except leave |fun| on stack for duration of call.
     callInfo.popFormals(current);
     current->push(callInfo.fun());
 
     JSScript *calleeScript = target->nonLazyScript();
     BaselineInspector inspector(calleeScript);
 
+    // Improve type information of |this| when not set.
+    if (callInfo.constructing() &&
+        !callInfo.thisArg()->resultTypeSet() &&
+        calleeScript->types)
     {
-        AutoThreadSafeAccess ts(calleeScript);
-
-        // Improve type information of |this| when not set.
-        if (callInfo.constructing() &&
-            !callInfo.thisArg()->resultTypeSet() &&
-            calleeScript->types)
-        {
-            types::StackTypeSet *types = types::TypeScript::ThisTypes(calleeScript);
-            if (!types->unknown()) {
-                MTypeBarrier *barrier =
-                    MTypeBarrier::New(alloc(), callInfo.thisArg(), types->clone(alloc_->lifoAlloc()));
-                current->add(barrier);
-                callInfo.setThis(barrier);
-            }
+        types::StackTypeSet *types = types::TypeScript::ThisTypes(calleeScript);
+        if (!types->unknown()) {
+            MTypeBarrier *barrier =
+                MTypeBarrier::New(alloc(), callInfo.thisArg(), types->clone(alloc_->lifoAlloc()));
+            current->add(barrier);
+            callInfo.setThis(barrier);
         }
     }
 
     // Start inlining.
     LifoAlloc *lifoAlloc = alloc_->lifoAlloc();
     CompileInfo *info = lifoAlloc->new_<CompileInfo>(calleeScript, target,
                                                      (jsbytecode *)nullptr, callInfo.constructing(),
                                                      this->info().executionMode(),
                                                      /* needsArgsObj = */ false);
     if (!info)
         return false;
 
     MIRGraphReturns returns(alloc());
     AutoAccumulateReturns aar(graph(), returns);
 
-    unlock();
-
     // Build the graph.
     IonBuilder inlineBuilder(analysisContext, compartment, options, &alloc(), &graph(), constraints(),
                              &inspector, info, &optimizationInfo(), nullptr, inliningDepth_ + 1,
                              loopDepth_);
     if (!inlineBuilder.buildInline(this, outerResumePoint, callInfo)) {
         if (analysisContext && analysisContext->isExceptionPending()) {
             IonSpew(IonSpew_Abort, "Inline builder raised exception.");
             abortReason_ = AbortReason_Error;
             return false;
         }
 
         // Inlining the callee failed. Mark the callee as uninlineable only if
         // the inlining was aborted for a non-exception reason.
         if (inlineBuilder.abortReason_ == AbortReason_Disable) {
-            AutoThreadSafeAccess ts(calleeScript);
             calleeScript->setUninlineable();
             abortReason_ = AbortReason_Inlining;
         } else if (inlineBuilder.abortReason_ == AbortReason_Inlining) {
             abortReason_ = AbortReason_Inlining;
         }
 
         return false;
     }
 
-    lock();
-
     // Create return block.
     jsbytecode *postCall = GetNextPc(pc);
     MBasicBlock *returnBlock = newBlock(nullptr, postCall);
     if (!returnBlock)
         return false;
     returnBlock->setCallerResumePoint(callerResumePoint_);
 
     // When profiling add Inline_Exit instruction to indicate end of inlined function.
@@ -3952,17 +3903,16 @@ IonBuilder::inlineScriptedCall(CallInfo 
 
     // Inherit the slots from current and pop |fun|.
     returnBlock->inheritSlots(current);
     returnBlock->pop();
 
     // Accumulate return values.
     if (returns.empty()) {
         // Inlining of functions that have no exit is not supported.
-        AutoThreadSafeAccess ts(calleeScript);
         calleeScript->setUninlineable();
         abortReason_ = AbortReason_Inlining;
         return false;
     }
     MDefinition *retvalDefn = patchInlinedReturns(callInfo, returns, returnBlock);
     if (!retvalDefn)
         return false;
     returnBlock->push(retvalDefn);
@@ -4613,17 +4563,16 @@ IonBuilder::inlineCalls(CallInfo &callIn
 }
 
 MInstruction *
 IonBuilder::createDeclEnvObject(MDefinition *callee, MDefinition *scope)
 {
     // Get a template CallObject that we'll use to generate inline object
     // creation.
     DeclEnvObject *templateObj = inspector->templateDeclEnvObject();
-    AutoThreadSafeAccess ts(templateObj);
 
     // One field is added to the function to handle its name.  This cannot be a
     // dynamic slot because there is still plenty of room on the DeclEnv object.
     JS_ASSERT(!templateObj->hasDynamicSlots());
 
     // Allocate the actual object. It is important that no intervening
     // instructions could potentially bailout, thus leaking the dynamic slots
     // pointer.
@@ -4641,22 +4590,21 @@ IonBuilder::createDeclEnvObject(MDefinit
 }
 
 MInstruction *
 IonBuilder::createCallObject(MDefinition *callee, MDefinition *scope)
 {
     // Get a template CallObject that we'll use to generate inline object
     // creation.
     CallObject *templateObj = inspector->templateCallObject();
-    AutoThreadSafeAccess ts(templateObj);
 
     // If the CallObject needs dynamic slots, allocate those now.
     MInstruction *slots;
     if (templateObj->hasDynamicSlots()) {
-        size_t nslots = JSObject::dynamicSlotsCount(templateObj->numFixedSlotsForCompilation(),
+        size_t nslots = JSObject::dynamicSlotsCount(templateObj->numFixedSlots(),
                                                     templateObj->lastProperty()->slotSpan(templateObj->getClass()),
                                                     templateObj->getClass());
         slots = MNewSlots::New(alloc(), nslots);
     } else {
         slots = MConstant::New(alloc(), NullValue());
     }
     current->add(slots);
 
@@ -4672,18 +4620,18 @@ IonBuilder::createCallObject(MDefinition
     current->add(MStoreFixedSlot::New(alloc(), callObj, CallObject::enclosingScopeSlot(), scope));
     current->add(MStoreFixedSlot::New(alloc(), callObj, CallObject::calleeSlot(), callee));
 
     // Initialize argument slots.
     for (AliasedFormalIter i(script()); i; i++) {
         unsigned slot = i.scopeSlot();
         unsigned formal = i.frameIndex();
         MDefinition *param = current->getSlot(info().argSlotUnchecked(formal));
-        if (slot >= templateObj->numFixedSlotsForCompilation())
-            current->add(MStoreSlot::New(alloc(), slots, slot - templateObj->numFixedSlotsForCompilation(), param));
+        if (slot >= templateObj->numFixedSlots())
+            current->add(MStoreSlot::New(alloc(), slots, slot - templateObj->numFixedSlots(), param));
         else
             current->add(MStoreFixedSlot::New(alloc(), callObj, slot, param));
     }
 
     return callObj;
 }
 
 MDefinition *
@@ -4745,23 +4693,20 @@ IonBuilder::createThisScriptedSingleton(
         return nullptr;
 
     JSObject *templateObject = inspector->getTemplateObject(pc);
     if (!templateObject || !templateObject->is<JSObject>())
         return nullptr;
     if (!templateObject->hasTenuredProto() || templateObject->getProto() != proto)
         return nullptr;
 
-    {
-        AutoThreadSafeAccess ts(target->nonLazyScript());
-        if (!target->nonLazyScript()->types)
-            return nullptr;
-        if (!types::TypeScript::ThisTypes(target->nonLazyScript())->hasType(types::Type::ObjectType(templateObject)))
-            return nullptr;
-    }
+    if (!target->nonLazyScript()->types)
+        return nullptr;
+    if (!types::TypeScript::ThisTypes(target->nonLazyScript())->hasType(types::Type::ObjectType(templateObject)))
+        return nullptr;
 
     // For template objects with NewScript info, the appropriate allocation
     // kind to use may change due to dynamic property adds. In these cases
     // calling Ion code will be invalidated, but any baseline template object
     // may be stale. Update to the correct template object in this case.
     types::TypeObject *templateType = templateObject->type();
     if (templateType->hasNewScript()) {
         templateObject = templateType->newScript()->templateObject;
@@ -5152,18 +5097,16 @@ IonBuilder::testNeedsArgumentCheck(JSFun
     // If we have a known target, check if the caller arg types are a subset of callee.
     // Since typeset accumulates and can't decrease that means we don't need to check
     // the arguments anymore.
     if (!target->hasScript())
         return true;
 
     JSScript *targetScript = target->nonLazyScript();
 
-    AutoThreadSafeAccess ts(targetScript);
-
     if (!targetScript->types)
         return true;
 
     if (!ArgumentTypesMatch(callInfo.thisArg(), types::TypeScript::ThisTypes(targetScript)))
         return true;
     uint32_t expected_args = Min<uint32_t>(callInfo.argc(), target->nargs());
     for (size_t i = 0; i < expected_args; i++) {
         if (!ArgumentTypesMatch(callInfo.getArg(i), types::TypeScript::ArgTypes(targetScript, i)))
@@ -5352,17 +5295,16 @@ IonBuilder::jsop_eval(uint32_t argc)
         // Try to pattern match 'eval(v + "()")'. In this case v is likely a
         // name on the scope chain and the eval is performing a call on that
         // value. Use a dynamic scope chain lookup rather than a full eval.
         if (string->isConcat() &&
             string->getOperand(1)->isConstant() &&
             string->getOperand(1)->toConstant()->value().isString())
         {
             JSAtom *atom = &string->getOperand(1)->toConstant()->value().toString()->asAtom();
-            AutoThreadSafeAccess ts(atom);
 
             if (StringEqualsAscii(atom, "()")) {
                 MDefinition *name = string->getOperand(0);
                 MInstruction *dynamicName = MGetDynamicName::New(alloc(), scopeChain, name);
                 current->add(dynamicName);
 
                 current->push(dynamicName);
                 current->push(thisValue);
@@ -5426,17 +5368,16 @@ IonBuilder::jsop_newarray(uint32_t count
                                     templateObject->type()->initialHeap(constraints()),
                                     MNewArray::NewArray_Allocating);
     current->add(ins);
     current->push(ins);
 
     types::TemporaryTypeSet::DoubleConversion conversion =
         ins->resultTypeSet()->convertDoubleElements(constraints());
 
-    AutoThreadSafeAccess ts(templateObject);
     if (conversion == types::TemporaryTypeSet::AlwaysConvertToDoubles)
         templateObject->setShouldConvertDoubleElements();
     else
         templateObject->clearShouldConvertDoubleElements();
     return true;
 }
 
 bool
@@ -5509,17 +5450,16 @@ IonBuilder::jsop_initelem_array()
     MConstant *id = MConstant::New(alloc(), Int32Value(GET_UINT24(pc)));
     current->add(id);
 
     // Get the elements vector.
     MElements *elements = MElements::New(alloc(), obj);
     current->add(elements);
 
     JSObject *templateObject = obj->toNewArray()->templateObject();
-    AutoThreadSafeAccess ts(templateObject);
 
     if (templateObject->shouldConvertDoubleElements()) {
         MInstruction *valueDouble = MToDouble::New(alloc(), value);
         current->add(valueDouble);
         value = valueDouble;
     }
 
     // Store the value.
@@ -5551,17 +5491,16 @@ IonBuilder::jsop_mutateproto()
 
 bool
 IonBuilder::jsop_initprop(PropertyName *name)
 {
     MDefinition *value = current->pop();
     MDefinition *obj = current->peek(-1);
 
     JSObject *templateObject = obj->toNewObject()->templateObject();
-    AutoThreadSafeAccess ts(templateObject);
 
     Shape *shape = templateObject->lastProperty()->searchLinear(NameToId(name));
 
     if (!shape) {
         // JSOP_NEWINIT becomes an MNewObject without preconfigured properties.
         MInitProp *init = MInitProp::New(alloc(), obj, name, value);
         current->add(init);
         return resumeAfter(init);
@@ -9174,19 +9113,16 @@ IonBuilder::jsop_regexp(RegExpObject *re
     // objects every time they execute. We only need to do this cloning if the
     // script could actually observe the effect of such cloning, for instance
     // by getting or setting properties on it.
     //
     // First, make sure the regex is one we can safely optimize. Lowering can
     // then check if this regex object only flows into known natives and can
     // avoid cloning in this case.
 
-    // RegExpObjects embedded in scripts are immutable.
-    AutoThreadSafeAccess ts(reobj);
-
     bool mustClone = true;
     types::TypeObjectKey *typeObj = types::TypeObjectKey::get(&script()->global());
     if (!typeObj->hasFlags(constraints(), types::OBJECT_FLAG_REGEXP_FLAGS_SET)) {
         RegExpStatics *res = script()->global().getRegExpStatics();
 
         DebugOnly<uint32_t> origFlags = reobj->getFlags();
         DebugOnly<uint32_t> staticsFlags = res->getFlags();
         JS_ASSERT((origFlags & staticsFlags) == staticsFlags);
--- a/js/src/jit/IonBuilder.h
+++ b/js/src/jit/IonBuilder.h
@@ -782,27 +782,16 @@ class IonBuilder : public MIRGenerator
     JSContext *analysisContext;
     BaselineFrameInspector *baselineFrame_;
     AbortReason abortReason_;
     TypeDescrSetHash *descrSetHash_;
 
     // Constraints for recording dependencies on type information.
     types::CompilerConstraintList *constraints_;
 
-    mozilla::Maybe<AutoLockForCompilation> lock_;
-
-    void lock() {
-        if (!analysisContext)
-            lock_.construct(compartment);
-    }
-    void unlock() {
-        if (!analysisContext)
-            lock_.destroy();
-    }
-
     // Basic analysis information about the script.
     BytecodeAnalysis analysis_;
     BytecodeAnalysis &analysis() {
         return analysis_;
     }
 
     types::TemporaryTypeSet *thisTypes, *argTypes, *typeArray;
     uint32_t typeArrayHint;
--- a/js/src/jit/IonCode.h
+++ b/js/src/jit/IonCode.h
@@ -77,17 +77,16 @@ class JitCode : public gc::BarrieredCell
         return jumpRelocTableOffset() + jumpRelocTableBytes_;
     }
     uint32_t preBarrierTableOffset() const {
         return dataRelocTableOffset() + dataRelocTableBytes_;
     }
 
   public:
     uint8_t *raw() const {
-        AutoThreadSafeAccess ts(this);
         return code_;
     }
     size_t instructionsSize() const {
         return insnSize_;
     }
     void trace(JSTracer *trc);
     void finalize(FreeOp *fop);
     void setInvalidated() {
--- a/js/src/jit/IonMacroAssembler.cpp
+++ b/js/src/jit/IonMacroAssembler.cpp
@@ -782,20 +782,16 @@ MacroAssembler::newGCShortStringPar(cons
     newGCThingPar(result, cx, tempReg1, tempReg2, js::gc::FINALIZE_SHORT_STRING, fail);
 }
 
 void
 MacroAssembler::initGCThing(const Register &obj, JSObject *templateObject)
 {
     // Fast initialization of an empty object returned by NewGCThing().
 
-    AutoThreadSafeAccess ts0(templateObject);
-    AutoThreadSafeAccess ts1(templateObject->lastProperty());
-    AutoThreadSafeAccess ts2(templateObject->lastProperty()->base()); // For isNative() assertions.
-
     JS_ASSERT(!templateObject->hasDynamicElements());
 
     storePtr(ImmGCPtr(templateObject->lastProperty()), Address(obj, JSObject::offsetOfShape()));
     storePtr(ImmGCPtr(templateObject->type()), Address(obj, JSObject::offsetOfType()));
     storePtr(ImmPtr(nullptr), Address(obj, JSObject::offsetOfSlots()));
 
     if (templateObject->is<ArrayObject>()) {
         JS_ASSERT(!templateObject->getDenseInitializedLength());
@@ -817,17 +813,17 @@ MacroAssembler::initGCThing(const Regist
                       ? ObjectElements::CONVERT_DOUBLE_ELEMENTS
                       : 0),
                 Address(obj, elementsOffset + ObjectElements::offsetOfFlags()));
     } else {
         storePtr(ImmPtr(emptyObjectElements), Address(obj, JSObject::offsetOfElements()));
 
         // Fixed slots of non-array objects are required to be initialized.
         // Use the values currently in the template object.
-        size_t nslots = Min(templateObject->numFixedSlotsForCompilation(),
+        size_t nslots = Min(templateObject->numFixedSlots(),
                             templateObject->lastProperty()->slotSpan(templateObject->getClass()));
         for (unsigned i = 0; i < nslots; i++) {
             storeValue(templateObject->getFixedSlot(i),
                        Address(obj, JSObject::getFixedSlotOffset(i)));
         }
     }
 
     if (templateObject->hasPrivate()) {
--- a/js/src/jit/JitOptions.cpp
+++ b/js/src/jit/JitOptions.cpp
@@ -28,20 +28,16 @@ JitOptions::JitOptions()
     // are not modified before its OsiPoint.
     checkOsiPointRegisters = false;
 #endif
 
     // Whether to enable extra code to perform dynamic validation of
     // RangeAnalysis results.
     checkRangeAnalysis = false;
 
-    // Whether to protect the GC heap during Ion compilation and ensure that
-    // only threadsafe operations are performed on it.
-    checkThreadSafety = false;
-
     // Whether Ion should compile try-catch statements.
     compileTryCatch = true;
 
     // Toggle whether global value numbering is globally disabled.
     disableGvn = false;
 
     // Toggles whether loop invariant code motion is globally disabled.
     disableLicm = false;
--- a/js/src/jit/JitOptions.h
+++ b/js/src/jit/JitOptions.h
@@ -40,17 +40,16 @@ enum IonGvnKind {
 
 struct JitOptions
 {
     bool checkGraphConsistency;
 #ifdef CHECK_OSIPOINT_REGISTERS
     bool checkOsiPointRegisters;
 #endif
     bool checkRangeAnalysis;
-    bool checkThreadSafety;
     bool compileTryCatch;
     bool disableGvn;
     bool disableLicm;
     bool disableInlining;
     bool disableEdgeCaseAnalysis;
     bool disableRangeAnalysis;
     bool disableUce;
     bool disableEaa;
--- a/js/src/jit/MCallOptimize.cpp
+++ b/js/src/jit/MCallOptimize.cpp
@@ -252,23 +252,20 @@ IonBuilder::inlineArray(CallInfo &callIn
         if (initLength <= ArrayObject::EagerAllocationMaxLength)
             allocating = MNewArray::NewArray_Allocating;
     }
 
     callInfo.setImplicitlyUsedUnchecked();
 
     types::TemporaryTypeSet::DoubleConversion conversion =
         getInlineReturnTypeSet()->convertDoubleElements(constraints());
-    {
-        AutoThreadSafeAccess ts(templateObject);
-        if (conversion == types::TemporaryTypeSet::AlwaysConvertToDoubles)
-            templateObject->setShouldConvertDoubleElements();
-        else
-            templateObject->clearShouldConvertDoubleElements();
-    }
+    if (conversion == types::TemporaryTypeSet::AlwaysConvertToDoubles)
+        templateObject->setShouldConvertDoubleElements();
+    else
+        templateObject->clearShouldConvertDoubleElements();
 
     MNewArray *ins = MNewArray::New(alloc(), constraints(), initLength, templateObject,
                                     templateObject->type()->initialHeap(constraints()),
                                     allocating);
     current->add(ins);
     current->push(ins);
 
     if (callInfo.argc() >= 2) {
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -783,18 +783,16 @@ MApplyArgs::New(TempAllocator &alloc, JS
 }
 
 MDefinition*
 MStringLength::foldsTo(TempAllocator &alloc, bool useValueNumbers)
 {
     if ((type() == MIRType_Int32) && (string()->isConstant())) {
         Value value = string()->toConstant()->value();
         JSAtom *atom = &value.toString()->asAtom();
-
-        AutoThreadSafeAccess ts(atom);
         return MConstant::New(alloc, Int32Value(atom->length()));
     }
 
     return this;
 }
 
 void
 MFloor::trySpecializeFloat32(TempAllocator &alloc)
@@ -2602,17 +2600,16 @@ MBeta::printOpcode(FILE *fp) const
     sp.init();
     comparison_->print(sp);
     fprintf(fp, " %s", sp.string());
 }
 
 bool
 MNewObject::shouldUseVM() const
 {
-    AutoThreadSafeAccess ts(templateObject());
     return templateObject()->hasSingletonType() ||
            templateObject()->hasDynamicSlots();
 }
 
 bool
 MNewArray::shouldUseVM() const
 {
     JS_ASSERT(count() < JSObject::NELEMENTS_LIMIT);
--- a/js/src/jit/shared/CodeGenerator-shared.cpp
+++ b/js/src/jit/shared/CodeGenerator-shared.cpp
@@ -274,17 +274,16 @@ CodeGeneratorShared::encode(LSnapshot *s
         // Ensure that all snapshot which are encoded can safely be used for
         // bailouts.
         DebugOnly<jsbytecode *> bailPC = pc;
         if (mir->mode() == MResumePoint::ResumeAfter)
           bailPC = GetNextPc(pc);
 
 #ifdef DEBUG
         if (GetIonContext()->cx) {
-            AutoThreadSafeAccess ts(script);
             uint32_t stackDepth;
             bool reachablePC;
             if (!ReconstructStackDepth(GetIonContext()->cx, script, bailPC, &stackDepth, &reachablePC))
                 return false;
 
             if (reachablePC) {
                 if (JSOp(*bailPC) == JSOP_FUNCALL) {
                     // For fun.call(this, ...); the reconstructStackDepth will
--- a/js/src/jsatominlines.h
+++ b/js/src/jsatominlines.h
@@ -26,17 +26,16 @@ js::AtomStateEntry::asPtr() const
     return atom;
 }
 
 namespace js {
 
 inline jsid
 AtomToId(JSAtom *atom)
 {
-    AutoThreadSafeAccess ts(atom);
     JS_STATIC_ASSERT(JSID_INT_MIN == 0);
 
     uint32_t index;
     if (atom->isIndex(&index) && index <= JSID_INT_MAX)
         return INT_TO_JSID(int32_t(index));
 
     return JSID_FROM_BITS(size_t(atom));
 }
--- a/js/src/jsboolinlines.h
+++ b/js/src/jsboolinlines.h
@@ -24,17 +24,15 @@ BooleanGetPrimitiveValue(HandleObject ob
         return obj->as<BooleanObject>().unbox();
 
     return BooleanGetPrimitiveValueSlow(obj, cx);
 }
 
 inline bool
 EmulatesUndefined(JSObject *obj)
 {
-    AutoThreadSafeAccess ts0(obj);
-    AutoThreadSafeAccess ts1(obj->typeRaw());
     JSObject *actual = MOZ_LIKELY(!obj->is<WrapperObject>()) ? obj : UncheckedUnwrap(obj);
     return actual->getClass()->emulatesUndefined();
 }
 
 } /* namespace js */
 
 #endif /* jsboolinlines_h */
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -111,17 +111,16 @@ JSCompartment::sweepCallsiteClones()
 
 JSFunction *
 js::ExistingCloneFunctionAtCallsite(const CallsiteCloneTable &table, JSFunction *fun,
                                     JSScript *script, jsbytecode *pc)
 {
     JS_ASSERT(fun->nonLazyScript()->shouldCloneAtCallsite());
     JS_ASSERT(!fun->nonLazyScript()->enclosingStaticScope());
     JS_ASSERT(types::UseNewTypeForClone(fun));
-    JS_ASSERT(CurrentThreadCanReadCompilationData());
 
     /*
      * If we start allocating function objects in the nursery, then the callsite
      * clone table will need a postbarrier.
      */
     JS_ASSERT(fun->isTenured());
 
     if (!table.initialized())
@@ -149,18 +148,16 @@ js::CloneFunctionAtCallsite(JSContext *c
      * Store a link back to the original for function.caller and avoid cloning
      * clones.
      */
     clone->nonLazyScript()->setIsCallsiteClone(fun);
 
     typedef CallsiteCloneKey Key;
     typedef CallsiteCloneTable Table;
 
-    AutoLockForCompilation lock(cx);
-
     Table &table = cx->compartment()->callsiteClones;
     if (!table.initialized() && !table.init())
         return nullptr;
 
     if (!table.putNew(Key(fun, script, script->pcToOffset(pc)), clone))
         return nullptr;
 
     return clone;
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -1082,78 +1082,15 @@ class AutoLockForExclusiveAccess
         // An empty destructor is needed to avoid warnings from clang about
         // unused local variables of this type.
     }
 #endif // JS_THREADSAFE
 
     MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
 };
 
-class AutoLockForCompilation
-{
-#ifdef JS_THREADSAFE
-    JSRuntime *runtime;
-
-    void init(JSRuntime *rt) {
-        runtime = rt;
-        if (runtime->numCompilationThreads) {
-            runtime->assertCanLock(CompilationLock);
-            PR_Lock(runtime->compilationLock);
-#ifdef DEBUG
-            runtime->compilationLockOwner = PR_GetCurrentThread();
-#endif
-        } else {
-#ifdef DEBUG
-            JS_ASSERT(!runtime->mainThreadHasCompilationLock);
-            runtime->mainThreadHasCompilationLock = true;
-#endif
-        }
-    }
-
-  public:
-    AutoLockForCompilation(ExclusiveContext *cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) {
-        MOZ_GUARD_OBJECT_NOTIFIER_INIT;
-        if (cx->isJSContext())
-            init(cx->asJSContext()->runtime());
-        else
-            runtime = nullptr;
-    }
-    AutoLockForCompilation(jit::CompileCompartment *compartment MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
-    ~AutoLockForCompilation() {
-        if (runtime) {
-            if (runtime->numCompilationThreads) {
-                JS_ASSERT(runtime->compilationLockOwner == PR_GetCurrentThread());
-#ifdef DEBUG
-                runtime->compilationLockOwner = nullptr;
-#endif
-                PR_Unlock(runtime->compilationLock);
-            } else {
-#ifdef DEBUG
-                JS_ASSERT(runtime->mainThreadHasCompilationLock);
-                runtime->mainThreadHasCompilationLock = false;
-#endif
-            }
-        }
-    }
-#else // JS_THREADSAFE
-  public:
-    AutoLockForCompilation(ExclusiveContext *cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) {
-        MOZ_GUARD_OBJECT_NOTIFIER_INIT;
-    }
-    AutoLockForCompilation(jit::CompileCompartment *compartment MOZ_GUARD_OBJECT_NOTIFIER_PARAM) {
-        MOZ_GUARD_OBJECT_NOTIFIER_INIT;
-    }
-    ~AutoLockForCompilation() {
-        // An empty destructor is needed to avoid warnings from clang about
-        // unused local variables of this type.
-    }
-#endif // JS_THREADSAFE
-
-    MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
-};
-
 } /* namespace js */
 
 #ifdef _MSC_VER
 #pragma warning(pop)
 #endif
 
 #endif /* jscntxt_h */
--- a/js/src/jscompartmentinlines.h
+++ b/js/src/jscompartmentinlines.h
@@ -17,24 +17,17 @@ JSCompartment::initGlobal(js::GlobalObje
     JS_ASSERT(global.compartment() == this);
     JS_ASSERT(!global_);
     global_ = &global;
 }
 
 js::GlobalObject *
 JSCompartment::maybeGlobal() const
 {
-#ifdef DEBUG
-    if (global_) {
-        js::AutoThreadSafeAccess ts0(global_);
-        js::AutoThreadSafeAccess ts1(global_->lastProperty());
-        js::AutoThreadSafeAccess ts2(global_->lastProperty()->base());
-        JS_ASSERT(global_->compartment() == this);
-    }
-#endif
+    JS_ASSERT_IF(global_, global_->compartment() == this);
     return global_;
 }
 
 js::AutoCompartment::AutoCompartment(ExclusiveContext *cx, JSObject *target)
   : cx_(cx),
     origin_(cx->compartment_)
 {
     cx_->enterCompartment(target->compartment());
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -1145,34 +1145,32 @@ JSFunction::createScriptForLazilyInterpr
         // Suppress GC for now although we should be able to remove this by
         // making 'lazy' a Rooted<LazyScript*> (which requires adding a
         // THING_ROOT_LAZY_SCRIPT).
         AutoSuppressGC suppressGC(cx);
 
         RootedScript script(cx, lazy->maybeScript());
 
         if (script) {
-            AutoLockForCompilation lock(cx);
             fun->setUnlazifiedScript(script);
             // Remember the lazy script on the compiled script, so it can be
             // stored on the function again in case of re-lazification.
             // Only functions without inner functions are re-lazified.
             if (!lazy->numInnerFunctions())
                 script->setLazyScript(lazy);
             return true;
         }
 
         if (fun != lazy->functionNonDelazifying()) {
             if (!lazy->functionDelazifying(cx))
                 return false;
             script = lazy->functionNonDelazifying()->nonLazyScript();
             if (!script)
                 return false;
 
-            AutoLockForCompilation lock(cx);
             fun->setUnlazifiedScript(script);
             return true;
         }
 
         // Lazy script caching is only supported for leaf functions. If a
         // script with inner functions was returned by the cache, those inner
         // functions would be delazified when deep cloning the script, even if
         // they have never executed.
@@ -1191,20 +1189,17 @@ JSFunction::createScriptForLazilyInterpr
             if (!clonedScript)
                 return false;
 
             clonedScript->setSourceObject(lazy->sourceObject());
 
             fun->initAtom(script->functionNonDelazifying()->displayAtom());
             clonedScript->setFunction(fun);
 
-            {
-                AutoLockForCompilation lock(cx);
-                fun->setUnlazifiedScript(clonedScript);
-            }
+            fun->setUnlazifiedScript(clonedScript);
 
             CallNewScriptHook(cx, clonedScript, fun);
 
             if (!lazy->maybeScript())
                 lazy->initScript(clonedScript);
             return true;
         }
 
--- a/js/src/jsfun.h
+++ b/js/src/jsfun.h
@@ -100,22 +100,20 @@ class JSFunction : public JSObject
         // Note: this should be kept in sync with FunctionBox::isHeavyweight().
         return nonLazyScript()->hasAnyAliasedBindings() ||
                nonLazyScript()->funHasExtensibleScope() ||
                nonLazyScript()->funNeedsDeclEnvObject() ||
                isGenerator();
     }
 
     size_t nargs() const {
-        js::AutoThreadSafeAccess ts(this);
         return nargs_;
     }
 
     uint16_t flags() const {
-        js::AutoThreadSafeAccess ts(this);
         return flags_;
     }
 
     /* A function can be classified as either native (C++) or interpreted (JS): */
     bool isInterpreted()            const { return flags() & (INTERPRETED | INTERPRETED_LAZY); }
     bool isNative()                 const { return !isInterpreted(); }
 
     /* Possible attributes of a native function: */
@@ -129,24 +127,20 @@ class JSFunction : public JSObject
     bool isSelfHostedBuiltin()      const { return flags() & SELF_HOSTED; }
     bool isSelfHostedConstructor()  const { return flags() & SELF_HOSTED_CTOR; }
     bool hasRest()                  const { return flags() & HAS_REST; }
     bool isWrappable()              const {
         JS_ASSERT_IF(flags() & SH_WRAPPABLE, isSelfHostedBuiltin());
         return flags() & SH_WRAPPABLE;
     }
 
-    // Functions can change between being lazily interpreted and having scripts
-    // when under the compilation lock.
     bool isInterpretedLazy()        const {
-        JS_ASSERT(js::CurrentThreadCanReadCompilationData());
         return flags() & INTERPRETED_LAZY;
     }
     bool hasScript()                const {
-        JS_ASSERT(js::CurrentThreadCanReadCompilationData());
         return flags() & INTERPRETED;
     }
 
     bool hasJITCode() const {
         if (!hasScript())
             return false;
 
         return nonLazyScript()->hasBaselineScript() || nonLazyScript()->hasIonScript();
@@ -233,17 +227,16 @@ class JSFunction : public JSObject
         flags_ |= ARROW;
     }
 
     JSAtom *atom() const { return hasGuessedAtom() ? nullptr : atom_.get(); }
     js::PropertyName *name() const { return hasGuessedAtom() || !atom_ ? nullptr : atom_->asPropertyName(); }
     void initAtom(JSAtom *atom) { atom_.init(atom); }
 
     JSAtom *displayAtom() const {
-        js::AutoThreadSafeAccess ts(this);
         return atom_;
     }
 
     void setGuessedAtom(JSAtom *atom) {
         JS_ASSERT(atom_ == nullptr);
         JS_ASSERT(atom != nullptr);
         JS_ASSERT(!hasGuessedAtom());
         atom_ = atom;
@@ -253,17 +246,16 @@ class JSFunction : public JSObject
     /* uint16_t representation bounds number of call object dynamic slots. */
     enum { MAX_ARGS_AND_VARS = 2 * ((1U << 16) - 1) };
 
     /*
      * For an interpreted function, accessors for the initial scope object of
      * activations (stack frames) of the function.
      */
     JSObject *environment() const {
-        js::AutoThreadSafeAccess ts(this);
         JS_ASSERT(isInterpreted());
         return u.i.env_;
     }
 
     void setEnvironment(JSObject *obj) {
         JS_ASSERT(isInterpreted());
         *(js::HeapPtrObject *)&u.i.env_ = obj;
     }
@@ -327,18 +319,16 @@ class JSFunction : public JSObject
             flags_ &= ~INTERPRETED_LAZY;
             flags_ |= INTERPRETED;
             initScript(script);
         }
         return nonLazyScript();
     }
 
     JSScript *nonLazyScript() const {
-        js::AutoThreadSafeAccess ts(this);
-        JS_ASSERT(js::CurrentThreadCanReadCompilationData());
         JS_ASSERT(hasScript());
         JS_ASSERT(u.i.s.script_);
         return u.i.s.script_;
     }
 
     // Returns non-callsited-clone version of this.  Use when return
     // value can flow to arbitrary JS (see Bug 944975).
     JSFunction* originalFunction() {
@@ -350,26 +340,22 @@ class JSFunction : public JSObject
     }
 
     js::HeapPtrScript &mutableScript() {
         JS_ASSERT(isInterpreted());
         return *(js::HeapPtrScript *)&u.i.s.script_;
     }
 
     js::LazyScript *lazyScript() const {
-        js::AutoThreadSafeAccess ts(this);
         JS_ASSERT(isInterpretedLazy() && u.i.s.lazy_);
-        JS_ASSERT(js::CurrentThreadCanReadCompilationData());
         return u.i.s.lazy_;
     }
 
     js::LazyScript *lazyScriptOrNull() const {
-        js::AutoThreadSafeAccess ts(this);
         JS_ASSERT(isInterpretedLazy());
-        JS_ASSERT(js::CurrentThreadCanReadCompilationData());
         return u.i.s.lazy_;
     }
 
     js::GeneratorKind generatorKind() const {
         if (!isInterpreted())
             return js::NotGenerator;
         if (hasScript())
             return nonLazyScript()->generatorKind();
@@ -393,34 +379,32 @@ class JSFunction : public JSObject
     void initScript(JSScript *script_) {
         JS_ASSERT(hasScript());
         mutableScript().init(script_);
     }
 
     void setUnlazifiedScript(JSScript *script) {
         // Note: createScriptForLazilyInterpretedFunction triggers a barrier on
         // lazy script before it is overwritten here.
-        JS_ASSERT(js::CurrentThreadCanWriteCompilationData());
         JS_ASSERT(isInterpretedLazy());
         if (!lazyScript()->maybeScript())
             lazyScript()->initScript(script);
         flags_ &= ~INTERPRETED_LAZY;
         flags_ |= INTERPRETED;
         initScript(script);
     }
 
     void initLazyScript(js::LazyScript *lazy) {
         JS_ASSERT(isInterpreted());
         flags_ &= ~INTERPRETED;
         flags_ |= INTERPRETED_LAZY;
         u.i.s.lazy_ = lazy;
     }
 
     JSNative native() const {
-        js::AutoThreadSafeAccess ts(this);
         JS_ASSERT(isNative());
         return u.n.native;
     }
 
     JSNative maybeNative() const {
         return isInterpreted() ? nullptr : native();
     }
 
@@ -435,17 +419,16 @@ class JSFunction : public JSObject
 
     void initNative(js::Native native, const JSJitInfo *jitinfo) {
         JS_ASSERT(native);
         u.n.native = native;
         u.n.jitinfo = jitinfo;
     }
 
     const JSJitInfo *jitInfo() const {
-        js::AutoThreadSafeAccess ts(this);
         JS_ASSERT(isNative());
         return u.n.jitinfo;
     }
 
     void setJitInfo(const JSJitInfo *data) {
         JS_ASSERT(isNative());
         u.n.jitinfo = data;
     }
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -683,19 +683,16 @@ types::NewCompilerConstraintList(jit::Te
 }
 
 /* static */ bool
 TypeScript::FreezeTypeSets(CompilerConstraintList *constraints, JSScript *script,
                            TemporaryTypeSet **pThisTypes,
                            TemporaryTypeSet **pArgTypes,
                            TemporaryTypeSet **pBytecodeTypes)
 {
-    JS_ASSERT(CurrentThreadCanReadCompilationData());
-    AutoThreadSafeAccess ts(script);
-
     LifoAlloc *alloc = constraints->alloc();
     StackTypeSet *existing = script->types->typeArray();
 
     size_t count = NumTypeSets(script);
     TemporaryTypeSet *types = alloc->newArrayUninitialized<TemporaryTypeSet>(count);
     if (!types)
         return false;
     PodZero(types, count);
@@ -805,17 +802,16 @@ TypeObjectKey::proto()
 {
     JS_ASSERT(hasTenuredProto());
     return isTypeObject() ? asTypeObject()->proto() : asSingleObject()->getTaggedProto();
 }
 
 bool
 ObjectImpl::hasTenuredProto() const
 {
-    AutoThreadSafeAccess ts(this);
     return type_->hasTenuredProto();
 }
 
 bool
 TypeObjectKey::hasTenuredProto()
 {
     return isTypeObject() ? asTypeObject()->hasTenuredProto() : asSingleObject()->hasTenuredProto();
 }
@@ -851,17 +847,16 @@ TypeObjectKey::unknownProperties()
         return type->unknownProperties();
     return false;
 }
 
 HeapTypeSetKey
 TypeObjectKey::property(jsid id)
 {
     JS_ASSERT(!unknownProperties());
-    JS_ASSERT(CurrentThreadCanReadCompilationData());
 
     HeapTypeSetKey property;
     property.object_ = this;
     property.id_ = id;
     if (TypeObject *type = maybeType())
         property.maybeTypes_ = type->maybeGetProperty(id);
 
     return property;
@@ -1508,20 +1503,18 @@ ObjectStateChange(ExclusiveContext *cxAr
 {
     if (object->unknownProperties())
         return;
 
     /* All constraints listening to state changes are on the empty id. */
     HeapTypeSet *types = object->maybeGetProperty(JSID_EMPTY);
 
     /* Mark as unknown after getting the types, to avoid assertion. */
-    if (markingUnknown) {
-        AutoLockForCompilation lock(cxArg);
+    if (markingUnknown)
         object->addFlags(OBJECT_FLAG_DYNAMIC_MASK | OBJECT_FLAG_UNKNOWN_PROPERTIES);
-    }
 
     if (types) {
         if (JSContext *cx = cxArg->maybeJSContext()) {
             TypeConstraint *constraint = types->constraintList;
             while (constraint) {
                 constraint->newObjectState(cx, object);
                 constraint = constraint->next;
             }
@@ -2331,17 +2324,16 @@ TypeCompartment::markSetsUnknown(JSConte
             StackTypeSet *typeArray = script->types->typeArray();
             for (unsigned i = 0; i < count; i++) {
                 if (typeArray[i].hasType(Type::ObjectType(target)))
                     typeArray[i].addType(cx, Type::AnyObjectType());
             }
         }
     }
 
-    AutoLockForCompilation lock(cx);
     target->addFlags(OBJECT_FLAG_SETS_MARKED_UNKNOWN);
 }
 
 void
 TypeCompartment::print(JSContext *cx, bool force)
 {
 #ifdef DEBUG
     gc::AutoSuppressGC suppressGC(cx);
@@ -2751,38 +2743,19 @@ TypeCompartment::newTypedObject(JSContex
     obj->setType(p->value().object);
     return obj;
 }
 
 /////////////////////////////////////////////////////////////////////
 // TypeObject
 /////////////////////////////////////////////////////////////////////
 
-#ifdef DEBUG
-void
-TypeObject::assertCanAccessProto() const
-{
-    // The proto pointer for type objects representing singletons may move.
-    JS_ASSERT_IF(singleton(), CurrentThreadCanReadCompilationData());
-
-    // Any proto pointer which is in the nursery may be moved, and may not be
-    // accessed during off thread compilation.
-#if defined(JSGC_GENERATIONAL) && defined(JS_THREADSAFE)
-    PerThreadData *pt = TlsPerThreadData.get();
-    TaggedProto proto(proto_);
-    JS_ASSERT_IF(proto.isObject() && !proto.toObject()->isTenured(),
-                 !pt || !pt->ionCompiling);
-#endif
-}
-#endif // DEBUG
-
 void
 TypeObject::setProto(JSContext *cx, TaggedProto proto)
 {
-    JS_ASSERT(CurrentThreadCanWriteCompilationData());
     JS_ASSERT(singleton());
 
     if (proto.isObject() && IsInsideNursery(cx->runtime(), proto.toObject()))
         addFlags(OBJECT_FLAG_NURSERY_PROTO);
 
     setProtoUnchecked(proto);
 }
 
@@ -3051,20 +3024,17 @@ TypeObject::setFlags(ExclusiveContext *c
     AutoEnterAnalysis enter(cx);
 
     if (singleton()) {
         /* Make sure flags are consistent with persistent object state. */
         JS_ASSERT_IF(flags & OBJECT_FLAG_ITERATED,
                      singleton()->lastProperty()->hasObjectFlag(BaseShape::ITERATED_SINGLETON));
     }
 
-    {
-        AutoLockForCompilation lock(cx);
-        addFlags(flags);
-    }
+    addFlags(flags);
 
     InferSpew(ISpewOps, "%s: setFlags 0x%x", TypeObjectString(this), flags);
 
     ObjectStateChange(cx, this, false);
 }
 
 void
 TypeObject::markUnknown(ExclusiveContext *cx)
@@ -3099,20 +3069,18 @@ TypeObject::markUnknown(ExclusiveContext
         }
     }
 }
 
 void
 TypeObject::clearAddendum(ExclusiveContext *cx)
 {
     JS_ASSERT(!(flags() & OBJECT_FLAG_ADDENDUM_CLEARED));
-    {
-        AutoLockForCompilation lock(cx);
-        addFlags(OBJECT_FLAG_ADDENDUM_CLEARED);
-    }
+
+    addFlags(OBJECT_FLAG_ADDENDUM_CLEARED);
 
     /*
      * It is possible for the object to not have a new script or other
      * addendum yet, but to have one added in the future. When
      * analyzing properties of new scripts we mix in adding
      * constraints to trigger clearNewScript with changes to the type
      * sets themselves (from breakTypeBarriers). It is possible that
      * we could trigger one of these constraints before
@@ -3516,20 +3484,17 @@ CheckNewScriptProperties(JSContext *cx, 
         p = cx->calloc_(numBytes);
     } while (IsPoisonedPtr(p));
     newScript = (TypeNewScript *) p;
 #else
     newScript = (TypeNewScript *) cx->calloc_(numBytes);
 #endif
     new (newScript) TypeNewScript();
 
-    {
-        AutoLockForCompilation lock(cx);
-        type->setAddendum(newScript);
-    }
+    type->setAddendum(newScript);
 
     if (!newScript) {
         cx->compartment()->types.setPendingNukeTypes(cx);
         return;
     }
 
     newScript->fun = fun;
     newScript->templateObject = baseobj;
@@ -3687,20 +3652,17 @@ JSScript::makeTypes(JSContext *cx)
 
     new(typeScript) TypeScript();
 
     TypeSet *typeArray = typeScript->typeArray();
 
     for (unsigned i = 0; i < count; i++)
         new (&typeArray[i]) StackTypeSet();
 
-    {
-        AutoLockForCompilation lock(cx);
-        types = typeScript;
-    }
+    types = typeScript;
 
 #ifdef DEBUG
     for (unsigned i = 0; i < nTypeSets(); i++) {
         InferSpew(ISpewOps, "typeSet: %sT%p%s bytecode%u #%u",
                   InferSpewColor(&typeArray[i]), &typeArray[i], InferSpewColorReset(),
                   i, id());
     }
     TypeSet *thisTypes = TypeScript::ThisTypes(this);
@@ -3820,22 +3782,18 @@ JSObject::splicePrototype(JSContext *cx,
     if (!cx->typeInferenceEnabled()) {
         TypeObject *type = cx->getNewType(clasp, proto);
         if (!type)
             return false;
         self->type_ = type;
         return true;
     }
 
-    {
-        AutoLockForCompilation lock(cx);
-        type->setClasp(clasp);
-        type->setProto(cx, proto);
-    }
-
+    type->setClasp(clasp);
+    type->setProto(cx, proto);
     return true;
 }
 
 /* static */ TypeObject *
 JSObject::makeLazyType(JSContext *cx, HandleObject obj)
 {
     JS_ASSERT(obj->hasLazyType());
     JS_ASSERT(cx->compartment() == obj->compartment());
@@ -3878,20 +3836,17 @@ JSObject::makeLazyType(JSContext *cx, Ha
 
     /* Fill in the type according to the state of this object. */
 
     type->initSingleton(obj);
 
     if (obj->is<JSFunction>() && obj->as<JSFunction>().isInterpreted())
         type->interpretedFunction = &obj->as<JSFunction>();
 
-    {
-        AutoLockForCompilation lock(cx);
-        obj->type_ = type;
-    }
+    obj->type_ = type;
 
     return type;
 }
 
 /* static */ inline HashNumber
 TypeObjectWithNewScriptEntry::hash(const Lookup &lookup)
 {
     return PointerHasher<JSObject *, 3>::hash(lookup.hashProto.raw()) ^
@@ -4623,17 +4578,16 @@ TypeScript::printTypes(JSContext *cx, Ha
 
 /////////////////////////////////////////////////////////////////////
 // Binary data
 /////////////////////////////////////////////////////////////////////
 
 void
 TypeObject::setAddendum(TypeObjectAddendum *addendum)
 {
-    JS_ASSERT(CurrentThreadCanWriteCompilationData());
     this->addendum = addendum;
 }
 
 bool
 TypeObject::addTypedObjectAddendum(JSContext *cx, Handle<TypeDescr*> descr)
 {
     if (!cx->typeInferenceEnabled())
         return true;
--- a/js/src/jsinfer.h
+++ b/js/src/jsinfer.h
@@ -22,21 +22,16 @@
 #include "gc/Marking.h"
 #include "js/Utility.h"
 #include "js/Vector.h"
 
 namespace js {
 
 class TypeDescr;
 
-#ifdef DEBUG
-bool CurrentThreadCanWriteCompilationData();
-bool CurrentThreadCanReadCompilationData();
-#endif
-
 class TaggedProto
 {
   public:
     static JSObject * const LazyProto;
 
     TaggedProto() : proto(nullptr) {}
     TaggedProto(JSObject *proto) : proto(proto) {}
 
@@ -885,50 +880,39 @@ struct TypeObject : gc::BarrieredCell<Ty
 {
   private:
     /* Class shared by object using this type. */
     const Class *clasp_;
 
     /* Prototype shared by objects using this type. */
     HeapPtrObject proto_;
 
-#ifdef DEBUG
-    void assertCanAccessProto() const;
-#else
-    void assertCanAccessProto() const {}
-#endif
-
     /*
      * Whether there is a singleton JS object with this type. That JS object
      * must appear in type sets instead of this; we include the back reference
      * here to allow reverting the JS object to a lazy type.
      */
     HeapPtrObject singleton_;
 
   public:
 
     const Class *clasp() const {
-        AutoThreadSafeAccess ts(this);
         return clasp_;
     }
 
     void setClasp(const Class *clasp) {
-        JS_ASSERT(CurrentThreadCanWriteCompilationData());
         JS_ASSERT(singleton());
         clasp_ = clasp;
     }
 
     TaggedProto proto() const {
-        AutoThreadSafeAccess ts(this);
-        assertCanAccessProto();
         return TaggedProto(proto_);
     }
 
     JSObject *singleton() const {
-        AutoThreadSafeAccess ts(this);
         return singleton_;
     }
 
     // For use during marking, don't call otherwise.
     HeapPtrObject &protoRaw() { return proto_; }
     HeapPtrObject &singletonRaw() { return singleton_; }
 
     void setProto(JSContext *cx, TaggedProto proto);
@@ -960,52 +944,40 @@ struct TypeObject : gc::BarrieredCell<Ty
      *   constructed using 'new' on the specified script, which adds
      *   some number of properties to the object in a definite order
      *   before the object escapes.
      */
     HeapPtr<TypeObjectAddendum> addendum;
   public:
 
     TypeObjectFlags flags() const {
-        JS_ASSERT(CurrentThreadCanReadCompilationData());
-        AutoThreadSafeAccess ts(this);
         return flags_;
     }
 
     void addFlags(TypeObjectFlags flags) {
-        JS_ASSERT(CurrentThreadCanWriteCompilationData());
         flags_ |= flags;
     }
 
     void clearFlags(TypeObjectFlags flags) {
-        JS_ASSERT(CurrentThreadCanWriteCompilationData());
         flags_ &= ~flags;
     }
 
     bool hasNewScript() const {
-        JS_ASSERT(CurrentThreadCanReadCompilationData());
-        AutoThreadSafeAccess ts(this);
         return addendum && addendum->isNewScript();
     }
 
     TypeNewScript *newScript() {
-        JS_ASSERT(CurrentThreadCanReadCompilationData());
-        AutoThreadSafeAccess ts(this);
         return addendum->asNewScript();
     }
 
     bool hasTypedObject() {
-        JS_ASSERT(CurrentThreadCanReadCompilationData());
-        AutoThreadSafeAccess ts(this);
         return addendum && addendum->isTypedObject();
     }
 
     TypeTypedObject *typedObject() {
-        JS_ASSERT(CurrentThreadCanReadCompilationData());
-        AutoThreadSafeAccess ts(this);
         return addendum->asTypedObject();
     }
 
     void setAddendum(TypeObjectAddendum *addendum);
 
     /*
      * Tag the type object for a binary data type descriptor, instance,
      * or handle with the type representation of the data it points at.
--- a/js/src/jsinferinlines.h
+++ b/js/src/jsinferinlines.h
@@ -82,17 +82,16 @@ Type::ObjectType(JSObject *obj)
     if (obj->hasSingletonType())
         return Type(uintptr_t(obj) | 1);
     return Type(uintptr_t(obj->type()));
 }
 
 /* static */ inline Type
 Type::ObjectType(TypeObject *obj)
 {
-    AutoThreadSafeAccess ts(obj);
     if (obj->singleton())
         return Type(uintptr_t(obj->singleton()) | 1);
     return Type(uintptr_t(obj));
 }
 
 /* static */ inline Type
 Type::ObjectType(TypeObjectKey *obj)
 {
@@ -173,17 +172,16 @@ IdToTypeId(jsid id)
         return JSID_VOID;
 
     /*
      * Check for numeric strings, as in js_StringIsIndex, but allow negative
      * and overflowing integers.
      */
     if (JSID_IS_STRING(id)) {
         JSAtom *atom = JSID_TO_ATOM(id);
-        js::AutoThreadSafeAccess ts(atom);
         JS::TwoByteChars cp = atom->range();
         if (cp.length() > 0 && (JS7_ISDEC(cp[0]) || cp[0] == '-')) {
             for (size_t i = 1; i < cp.length(); ++i) {
                 if (!JS7_ISDEC(cp[i]))
                     return id;
             }
             return JSID_VOID;
         }
@@ -560,31 +558,29 @@ extern void TypeDynamicResult(JSContext 
 TypeScript::NumTypeSets(JSScript *script)
 {
     return script->nTypeSets() + analyze::LocalSlot(script, 0);
 }
 
 /* static */ inline StackTypeSet *
 TypeScript::ThisTypes(JSScript *script)
 {
-    JS_ASSERT(CurrentThreadCanReadCompilationData());
     return script->types->typeArray() + script->nTypeSets() + analyze::ThisSlot();
 }
 
 /*
  * Note: for non-escaping arguments and locals, argTypes/localTypes reflect
  * only the initial type of the variable (e.g. passed values for argTypes,
  * or undefined for localTypes) and not types from subsequent assignments.
  */
 
 /* static */ inline StackTypeSet *
 TypeScript::ArgTypes(JSScript *script, unsigned i)
 {
     JS_ASSERT(i < script->functionNonDelazifying()->nargs());
-    JS_ASSERT(CurrentThreadCanReadCompilationData());
     return script->types->typeArray() + script->nTypeSets() + analyze::ArgSlot(i);
 }
 
 template <typename TYPESET>
 /* static */ inline TYPESET *
 TypeScript::BytecodeTypes(JSScript *script, jsbytecode *pc, uint32_t *hint, TYPESET *typeArray)
 {
     JS_ASSERT(js_CodeSpec[*pc].format & JOF_TYPESET);
@@ -1123,22 +1119,19 @@ TypeSet::addType(Type type, LifoAlloc *a
 inline void
 ConstraintTypeSet::addType(ExclusiveContext *cxArg, Type type)
 {
     JS_ASSERT(cxArg->compartment()->activeAnalysis);
 
     if (hasType(type))
         return;
 
-    {
-        AutoLockForCompilation lock(cxArg);
-        if (!TypeSet::addType(type, &cxArg->typeLifoAlloc())) {
-            cxArg->compartment()->types.setPendingNukeTypes(cxArg);
-            return;
-        }
+    if (!TypeSet::addType(type, &cxArg->typeLifoAlloc())) {
+        cxArg->compartment()->types.setPendingNukeTypes(cxArg);
+        return;
     }
 
     InferSpew(ISpewOps, "addType: %sT%p%s %s",
               InferSpewColor(this), this, InferSpewColorReset(),
               TypeString(type));
 
     /* Propagate the type to all constraints. */
     if (JSContext *cx = cxArg->maybeJSContext()) {
@@ -1272,17 +1265,16 @@ inline TypeObject::TypeObject(const Clas
     this->flags_ = initialFlags;
 
     InferSpew(ISpewOps, "newObject: %s", TypeObjectString(this));
 }
 
 inline uint32_t
 TypeObject::basePropertyCount() const
 {
-    JS_ASSERT(CurrentThreadCanReadCompilationData());
     return (flags() & OBJECT_FLAG_PROPERTY_COUNT_MASK) >> OBJECT_FLAG_PROPERTY_COUNT_SHIFT;
 }
 
 inline void
 TypeObject::setBasePropertyCount(uint32_t count)
 {
     // Note: Callers must ensure they are performing threadsafe operations.
     JS_ASSERT(count <= OBJECT_FLAG_PROPERTY_COUNT_LIMIT);
@@ -1297,37 +1289,31 @@ TypeObject::getProperty(ExclusiveContext
 
     JS_ASSERT(JSID_IS_VOID(id) || JSID_IS_EMPTY(id) || JSID_IS_STRING(id));
     JS_ASSERT_IF(!JSID_IS_EMPTY(id), id == IdToTypeId(id));
     JS_ASSERT(!unknownProperties());
 
     if (HeapTypeSet *types = maybeGetProperty(id))
         return types;
 
-    uint32_t propertyCount;
-    Property **pprop;
-    {
-        AutoLockForCompilation lock(cx);
+    uint32_t propertyCount = basePropertyCount();
+    Property **pprop = HashSetInsert<jsid,Property,Property>
+        (cx->typeLifoAlloc(), propertySet, propertyCount, id);
+    if (!pprop) {
+        cx->compartment()->types.setPendingNukeTypes(cx);
+        return nullptr;
+    }
 
-        propertyCount = basePropertyCount();
-        pprop = HashSetInsert<jsid,Property,Property>
-            (cx->typeLifoAlloc(), propertySet, propertyCount, id);
-        if (!pprop) {
-            cx->compartment()->types.setPendingNukeTypes(cx);
-            return nullptr;
-        }
+    JS_ASSERT(!*pprop);
 
-        JS_ASSERT(!*pprop);
-
-        setBasePropertyCount(propertyCount);
-        if (!addProperty(cx, id, pprop)) {
-            setBasePropertyCount(0);
-            propertySet = nullptr;
-            return nullptr;
-        }
+    setBasePropertyCount(propertyCount);
+    if (!addProperty(cx, id, pprop)) {
+        setBasePropertyCount(0);
+        propertySet = nullptr;
+        return nullptr;
     }
 
     if (propertyCount == OBJECT_FLAG_PROPERTY_COUNT_LIMIT) {
         markUnknown(cx);
 
         /*
          * Return an arbitrary property in the object, as all have unknown
          * type and are treated as non-data properties.
@@ -1345,19 +1331,16 @@ TypeObject::getProperty(ExclusiveContext
 }
 
 inline HeapTypeSet *
 TypeObject::maybeGetProperty(jsid id)
 {
     JS_ASSERT(JSID_IS_VOID(id) || JSID_IS_EMPTY(id) || JSID_IS_STRING(id));
     JS_ASSERT_IF(!JSID_IS_EMPTY(id), id == IdToTypeId(id));
     JS_ASSERT(!unknownProperties());
-    JS_ASSERT(CurrentThreadCanReadCompilationData());
-
-    AutoThreadSafeAccess ts(this);
 
     Property *prop = HashSetLookup<jsid,Property,Property>
         (propertySet, basePropertyCount(), id);
 
     return prop ? &prop->types : nullptr;
 }
 
 inline unsigned
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -2043,17 +2043,16 @@ GlobalObject::initIteratorClasses(JSCont
         RootedObject genFunction(cx, NewFunctionWithProto(cx, NullPtr(), Generator, 1,
                                                           JSFunction::NATIVE_CTOR, global, name,
                                                           &function.toObject()));
         if (!genFunction)
             return false;
         if (!LinkConstructorAndPrototype(cx, genFunction, genFunctionProto))
             return false;
 
-        AutoLockForCompilation lock(cx);
         global->setSlot(STAR_GENERATOR_OBJECT_PROTO, ObjectValue(*genObjectProto));
         global->setConstructor(JSProto_GeneratorFunction, ObjectValue(*genFunction));
         global->setPrototype(JSProto_GeneratorFunction, ObjectValue(*genFunctionProto));
     }
 
     if (global->getPrototype(JSProto_StopIteration).isUndefined()) {
         proto = global->createBlankPrototype(cx, &StopIterationObject::class_);
         if (!proto || !JSObject::freeze(cx, proto))
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -2245,22 +2245,19 @@ JSObject::TradeGuts(JSContext *cx, JSObj
 {
     JS_ASSERT(a->compartment() == b->compartment());
     JS_ASSERT(a->is<JSFunction>() == b->is<JSFunction>());
 
     /*
      * Swap the object's types, to restore their initial type information.
      * The prototypes and classes of the objects were swapped in ReserveForTradeGuts.
      */
-    {
-        AutoLockForCompilation lock(cx);
-        TypeObject *tmp = a->type_;
-        a->type_ = b->type_;
-        b->type_ = tmp;
-    }
+    TypeObject *tmp = a->type_;
+    a->type_ = b->type_;
+    b->type_ = tmp;
 
     /* Don't try to swap a JSFunction for a plain function JSObject. */
     JS_ASSERT_IF(a->is<JSFunction>(), a->tenuredSizeOfThis() == b->tenuredSizeOfThis());
 
     /*
      * Regexp guts are more complicated -- we would need to migrate the
      * refcounted JIT code blob for them across compartments instead of just
      * swapping guts.
@@ -2282,22 +2279,19 @@ JSObject::TradeGuts(JSContext *cx, JSObj
         /*
          * If the objects are the same size, then we make no assumptions about
          * whether they have dynamically allocated slots and instead just copy
          * them over wholesale.
          */
         char tmp[mozilla::tl::Max<sizeof(JSFunction), sizeof(JSObject_Slots16)>::value];
         JS_ASSERT(size <= sizeof(tmp));
 
-        {
-            AutoLockForCompilation lock(cx);
-            js_memcpy(tmp, a, size);
-            js_memcpy(a, b, size);
-            js_memcpy(b, tmp, size);
-        }
+        js_memcpy(tmp, a, size);
+        js_memcpy(a, b, size);
+        js_memcpy(b, tmp, size);
 
 #ifdef JSGC_GENERATIONAL
         /*
          * Trigger post barriers for fixed slots. JSObject bits are barriered
          * below, in common with the other case.
          */
         for (size_t i = 0; i < a->numFixedSlots(); ++i) {
             HeapSlot::writeBarrierPost(cx->runtime(), a, HeapSlot::Slot, i, a->getSlot(i));
@@ -2325,22 +2319,19 @@ JSObject::TradeGuts(JSContext *cx, JSObj
             js_free(a->slots);
         if (b->hasDynamicSlots())
             js_free(b->slots);
 
         void *apriv = a->hasPrivate() ? a->getPrivate() : nullptr;
         void *bpriv = b->hasPrivate() ? b->getPrivate() : nullptr;
 
         char tmp[sizeof(JSObject)];
-        {
-            AutoLockForCompilation lock(cx);
-            js_memcpy(&tmp, a, sizeof tmp);
-            js_memcpy(a, b, sizeof tmp);
-            js_memcpy(b, &tmp, sizeof tmp);
-        }
+        js_memcpy(&tmp, a, sizeof tmp);
+        js_memcpy(a, b, sizeof tmp);
+        js_memcpy(b, &tmp, sizeof tmp);
 
         if (a->isNative())
             a->shape_->setNumFixedSlots(reserved.newafixed);
         else
             a->shape_ = reserved.newashape;
 
         a->slots = reserved.newaslots;
         a->initSlotRange(0, reserved.bvals.begin(), bcap);
@@ -2780,22 +2771,16 @@ JSObject::growSlots(ThreadSafeContext *c
             if (!reshapedObj)
                 return false;
 
             typeObj->newScript()->templateObject = reshapedObj;
             typeObj->markStateChange(ncx);
         }
     }
 
-    // Global slots may be read during off thread compilation, and updates to
-    // their slot pointers need to be synchronized.
-    Maybe<AutoLockForCompilation> lock;
-    if (obj->is<GlobalObject>())
-        lock.construct(cx->asExclusiveContext());
-
     if (!oldCount) {
         obj->slots = AllocateSlots(cx, obj, newCount);
         if (!obj->slots)
             return false;
         Debug_SetSlotRangeToCrashOnTouch(obj->slots, newCount);
         return true;
     }
 
@@ -2830,22 +2815,16 @@ JSObject::shrinkSlots(ThreadSafeContext 
     if (newCount == 0) {
         FreeSlots(cx, obj->slots);
         obj->slots = nullptr;
         return;
     }
 
     JS_ASSERT_IF(!obj->is<ArrayObject>(), newCount >= SLOT_CAPACITY_MIN);
 
-    // Global slots may be read during off thread compilation, and updates to
-    // their slot pointers need to be synchronized.
-    Maybe<AutoLockForCompilation> lock;
-    if (obj->is<GlobalObject>())
-        lock.construct(cx->asExclusiveContext());
-
     HeapSlot *newslots = ReallocateSlots(cx, obj, obj->slots, oldCount, newCount);
     if (!newslots)
         return;  /* Leave slots at its old size. */
 
     obj->slots = newslots;
 }
 
 /* static */ bool
@@ -3222,20 +3201,17 @@ js::SetClassAndProto(JSContext *cx, Hand
      * are unknown. Type sets containing this object will contain the original
      * type but not the new type of the object, so we need to go and scan the
      * entire compartment for type sets which have these objects and mark them
      * as containing generic objects.
      */
     MarkTypeObjectUnknownProperties(cx, obj->type(), true);
     MarkTypeObjectUnknownProperties(cx, type, true);
 
-    {
-        AutoLockForCompilation lock(cx);
-        obj->setType(type);
-    }
+    obj->setType(type);
 
     *succeeded = true;
     return true;
 }
 
 static bool
 MaybeResolveConstructor(ExclusiveContext *cxArg, Handle<GlobalObject*> global, JSProtoKey key)
 {
@@ -4298,17 +4274,17 @@ NativeGetInline(JSContext *cx,
         jsbytecode *pc;
         JSScript *script = cx->currentScript(&pc);
 #ifdef JS_ION
         if (script && script->hasBaselineScript()) {
             switch (JSOp(*pc)) {
               case JSOP_GETPROP:
               case JSOP_CALLPROP:
               case JSOP_LENGTH:
-                script->baselineScript()->noteAccessedGetter(cx, script->pcToOffset(pc));
+                script->baselineScript()->noteAccessedGetter(script->pcToOffset(pc));
                 break;
               default:
                 break;
             }
         }
 #endif
     }
 
@@ -5692,18 +5668,16 @@ DumpProperty(JSObject *obj, Shape &shape
         fprintf(stderr, " (INVALID!)");
     }
     fprintf(stderr, "\n");
 }
 
 bool
 JSObject::uninlinedIsProxy() const
 {
-    AutoThreadSafeAccess ts0(this);
-    AutoThreadSafeAccess ts1(type_);
     return is<ProxyObject>();
 }
 
 void
 JSObject::dump()
 {
     JSObject *obj = this;
     fprintf(stderr, "object %p\n", (void *) obj);
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -284,20 +284,16 @@ class JSObject : public js::ObjectImpl
     static const uint32_t NELEMENTS_LIMIT = JS_BIT(28);
 
   public:
     bool setDelegate(js::ExclusiveContext *cx) {
         return setFlag(cx, js::BaseShape::DELEGATE, GENERATE_SHAPE);
     }
 
     bool isBoundFunction() const {
-        // Note: This function can race when it is called during off thread compilation.
-        js::AutoThreadSafeAccess ts0(this);
-        js::AutoThreadSafeAccess ts1(lastProperty());
-        js::AutoThreadSafeAccess ts2(lastProperty()->base());
         return lastProperty()->hasObjectFlag(js::BaseShape::BOUND_FUNCTION);
     }
 
     inline bool hasSpecialEquality() const;
 
     bool watched() const {
         return lastProperty()->hasObjectFlag(js::BaseShape::WATCHED);
     }
@@ -349,20 +345,16 @@ class JSObject : public js::ObjectImpl
     bool isIndexed() const {
         return lastProperty()->hasObjectFlag(js::BaseShape::INDEXED);
     }
 
     uint32_t propertyCount() const {
         return lastProperty()->entryCount();
     }
 
-    uint32_t propertyCountForCompilation() const {
-        return lastProperty()->entryCountForCompilation();
-    }
-
     bool hasShapeTable() const {
         return lastProperty()->hasTable();
     }
 
     void addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::ObjectsExtraSizes *sizes);
 
     bool hasIdempotentProtoChain() const;
 
@@ -371,23 +363,23 @@ class JSObject : public js::ObjectImpl
     static const uint32_t MAX_FIXED_SLOTS = 16;
 
   public:
 
     /* Accessors for properties. */
 
     /* Whether a slot is at a fixed offset from this object. */
     bool isFixedSlot(size_t slot) {
-        return slot < numFixedSlotsForCompilation();
+        return slot < numFixedSlots();
     }
 
     /* Index into the dynamic slots array to use for a dynamic slot. */
     size_t dynamicSlotIndex(size_t slot) {
-        JS_ASSERT(slot >= numFixedSlotsForCompilation());
-        return slot - numFixedSlotsForCompilation();
+        JS_ASSERT(slot >= numFixedSlots());
+        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(js::ThreadSafeContext *cx, js::HandleObject obj, uint32_t oldCount,
--- a/js/src/jsobjinlines.h
+++ b/js/src/jsobjinlines.h
@@ -395,19 +395,16 @@ JSObject::clearType(JSContext *cx, js::H
 
     obj->type_ = type;
     return true;
 }
 
 inline void
 JSObject::setType(js::types::TypeObject *newType)
 {
-    // Note: This is usually called for newly created objects that haven't
-    // escaped to script yet, so don't require that the compilation lock be
-    // held here.
     JS_ASSERT(newType);
     JS_ASSERT(!hasSingletonType());
     type_ = newType;
 }
 
 /* static */ inline bool
 JSObject::getProto(JSContext *cx, js::HandleObject obj, js::MutableHandleObject protop)
 {
@@ -994,21 +991,18 @@ DefineConstructorAndPrototype(JSContext 
     JS_ASSERT(!global->nativeEmpty()); /* reserved slots already allocated */
     JS_ASSERT(ctor);
     JS_ASSERT(proto);
 
     RootedId id(cx, NameToId(ClassName(key, cx)));
     JS_ASSERT(!global->nativeLookup(cx, id));
 
     /* Set these first in case AddTypePropertyId looks for this class. */
-    {
-        AutoLockForCompilation lock(cx);
-        global->setConstructor(key, ObjectValue(*ctor));
-        global->setPrototype(key, ObjectValue(*proto));
-    }
+    global->setConstructor(key, ObjectValue(*ctor));
+    global->setPrototype(key, ObjectValue(*proto));
     global->setConstructorPropertySlot(key, ObjectValue(*ctor));
 
     if (!global->addDataProperty(cx, id, GlobalObject::constructorPropertySlot(key), 0)) {
         global->setConstructor(key, UndefinedValue());
         global->setPrototype(key, UndefinedValue());
         global->setConstructorPropertySlot(key, UndefinedValue());
         return false;
     }
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -3162,20 +3162,17 @@ JSScript::argumentsOptimizationFailed(JS
      * is nothing to do; GuardFunApplySpeculation will patch in the real
      * argsobj.
      */
     if (script->needsArgsObj())
         return true;
 
     JS_ASSERT(!script->isGenerator());
 
-    {
-        AutoLockForCompilation lock(cx);
-        script->needsArgsObj_ = true;
-    }
+    script->needsArgsObj_ = true;
 
 #ifdef JS_ION
     /*
      * Since we can't invalidate baseline scripts, set a flag that's checked from
      * JIT code to indicate the arguments optimization failed and JSOP_ARGUMENTS
      * should create an arguments object next time.
      */
     if (script->hasBaselineScript())
@@ -3225,24 +3222,22 @@ JSScript::argumentsOptimizationFailed(JS
     }
 
     return true;
 }
 
 bool
 JSScript::varIsAliased(uint32_t varSlot)
 {
-    AutoThreadSafeAccess ts(this);
     return bindings.bindingIsAliased(bindings.numArgs() + varSlot);
 }
 
 bool
 JSScript::formalIsAliased(unsigned argSlot)
 {
-    AutoThreadSafeAccess ts(this);
     return bindings.bindingIsAliased(argSlot);
 }
 
 bool
 JSScript::formalLivesInArgumentsObject(unsigned argSlot)
 {
     return argsObjAliasesFormals() && !formalIsAliased(argSlot);
 }
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -244,18 +244,16 @@ class Bindings
     /* Return whether the binding at bindingIndex is aliased. */
     bool bindingIsAliased(uint32_t bindingIndex);
 
     /* Return whether this scope has any aliased bindings. */
     bool hasAnyAliasedBindings() const {
         if (!callObjShape_)
             return false;
 
-        // Binding shapes are immutable once constructed.
-        AutoThreadSafeAccess ts(callObjShape_);
         return !callObjShape_->isEmptyShape();
     }
 
     void trace(JSTracer *trc);
 };
 
 template <>
 struct GCMethods<Bindings> {
@@ -549,20 +547,16 @@ class ScriptSourceObject : public JSObje
   public:
     static const Class class_;
 
     static void finalize(FreeOp *fop, JSObject *obj);
     static ScriptSourceObject *create(ExclusiveContext *cx, ScriptSource *source,
                                       const ReadOnlyCompileOptions &options);
 
     ScriptSource *source() {
-        // Script source objects are immutable.
-        AutoThreadSafeAccess ts0(this);
-        AutoThreadSafeAccess ts1(lastProperty());
-        AutoThreadSafeAccess ts2(lastProperty()->base());
         return static_cast<ScriptSource *>(getReservedSlot(SOURCE_SLOT).toPrivate());
     }
 
     void setSource(ScriptSource *source);
 
     JSObject *element() const;
     void initElement(HandleObject element);
     const Value &elementAttributeName() const;
@@ -633,32 +627,28 @@ class JSScript : public js::gc::Barriere
 
     // Larger-than-word-sized fields.
 
   public:
     js::Bindings    bindings;   /* names of top-level variables in this script
                                    (and arguments if this is a function script) */
 
     bool hasAnyAliasedBindings() const {
-        js::AutoThreadSafeAccess ts(this);
         return bindings.hasAnyAliasedBindings();
     }
 
     js::Binding *bindingArray() const {
-        js::AutoThreadSafeAccess ts(this);
         return bindings.bindingArray();
     }
 
     unsigned numArgs() const {
-        js::AutoThreadSafeAccess ts(this);
         return bindings.numArgs();
     }
 
     js::Shape *callObjShape() const {
-        js::AutoThreadSafeAccess ts(this);
         return bindings.callObjShape();
     }
 
     // Word-sized fields.
 
   private:
     jsbytecode      *code_;     /* bytecodes and their immediate operands */
   public:
@@ -884,21 +874,19 @@ class JSScript : public js::gc::Barriere
     inline JSPrincipals *principals();
 
     JSCompartment *compartment() const { return compartment_; }
 
     void setVersion(JSVersion v) { version = v; }
 
     // Script bytecode is immutable after creation.
     jsbytecode *code() const {
-        js::AutoThreadSafeAccess ts(this);
         return code_;
     }
     size_t length() const {
-        js::AutoThreadSafeAccess ts(this);
         return length_;
     }
 
     void setCode(jsbytecode *code) { code_ = code; }
     void setLength(size_t length) { length_ = length; }
 
     jsbytecode *codeEnd() const { return code() + length(); }
 
@@ -912,104 +900,87 @@ class JSScript : public js::gc::Barriere
     }
 
     jsbytecode *offsetToPC(size_t offset) const {
         JS_ASSERT(offset < length());
         return code() + offset;
     }
 
     size_t mainOffset() const {
-        js::AutoThreadSafeAccess ts(this);
         return mainOffset_;
     }
 
     size_t lineno() const {
-        js::AutoThreadSafeAccess ts(this);
         return lineno_;
     }
 
     size_t column() const {
-        js::AutoThreadSafeAccess ts(this);
         return column_;
     }
 
     void setColumn(size_t column) { column_ = column; }
 
     size_t nfixed() const {
-        js::AutoThreadSafeAccess ts(this);
         return function_ ? bindings.numVars() : 0;
     }
 
     size_t nslots() const {
-        js::AutoThreadSafeAccess ts(this);
         return nslots_;
     }
 
     size_t staticLevel() const {
-        js::AutoThreadSafeAccess ts(this);
         return staticLevel_;
     }
 
     size_t nTypeSets() const {
-        js::AutoThreadSafeAccess ts(this);
         return nTypeSets_;
     }
 
     size_t funLength() const {
-        js::AutoThreadSafeAccess ts(this);
         return funLength_;
     }
 
     size_t sourceStart() const {
-        js::AutoThreadSafeAccess ts(this);
         return sourceStart_;
     }
 
     size_t sourceEnd() const {
-        js::AutoThreadSafeAccess ts(this);
         return sourceEnd_;
     }
 
     bool noScriptRval() const {
-        js::AutoThreadSafeAccess ts(this);
         return noScriptRval_;
     }
 
     bool savedCallerFun() const { return savedCallerFun_; }
 
     bool strict() const {
-        js::AutoThreadSafeAccess ts(this);
         return strict_;
     }
 
     bool explicitUseStrict() const { return explicitUseStrict_; }
 
     bool compileAndGo() const {
-        js::AutoThreadSafeAccess ts(this);
         return compileAndGo_;
     }
 
     bool selfHosted() const { return selfHosted_; }
     bool bindingsAccessedDynamically() const { return bindingsAccessedDynamically_; }
     bool funHasExtensibleScope() const {
-        js::AutoThreadSafeAccess ts(this);
         return funHasExtensibleScope_;
     }
     bool funNeedsDeclEnvObject() const {
-        js::AutoThreadSafeAccess ts(this);
         return funNeedsDeclEnvObject_;
     }
     bool funHasAnyAliasedFormal() const {
-        js::AutoThreadSafeAccess ts(this);
         return funHasAnyAliasedFormal_;
     }
 
     bool hasSingletons() const { return hasSingletons_; }
     bool treatAsRunOnce() const {
-        js::AutoThreadSafeAccess ts(this);
         return treatAsRunOnce_;
     }
     bool hasRunOnce() const { return hasRunOnce_; }
     bool hasBeenCloned() const { return hasBeenCloned_; }
 
     void setTreatAsRunOnce() { treatAsRunOnce_ = true; }
     void setHasRunOnce() { hasRunOnce_ = true; }
     void setHasBeenCloned() { hasBeenCloned_ = true; }
@@ -1029,57 +1000,48 @@ class JSScript : public js::gc::Barriere
         isCachedEval_ = false;
         isActiveEval_ = true;
     }
 
     void setActiveEval() { isActiveEval_ = true; }
     void setDirectlyInsideEval() { directlyInsideEval_ = true; }
 
     bool usesArgumentsAndApply() const {
-        js::AutoThreadSafeAccess ts(this);
         return usesArgumentsAndApply_;
     }
     void setUsesArgumentsAndApply() { usesArgumentsAndApply_ = true; }
 
     bool shouldCloneAtCallsite() const {
-        js::AutoThreadSafeAccess ts(this);
         return shouldCloneAtCallsite_;
     }
     bool shouldInline() const {
-        js::AutoThreadSafeAccess ts(this);
         return shouldInline_;
     }
 
     void setShouldCloneAtCallsite() { shouldCloneAtCallsite_ = true; }
     void setShouldInline() { shouldInline_ = true; }
 
     bool isCallsiteClone() const {
-        js::AutoThreadSafeAccess ts(this);
         return isCallsiteClone_;
     }
     bool isGeneratorExp() const { return isGeneratorExp_; }
 
     bool failedBoundsCheck() const {
-        js::AutoThreadSafeAccess ts(this);
         return failedBoundsCheck_;
     }
     bool failedShapeGuard() const {
-        js::AutoThreadSafeAccess ts(this);
         return failedShapeGuard_;
     }
     bool hadFrequentBailouts() const {
-        js::AutoThreadSafeAccess ts(this);
         return hadFrequentBailouts_;
     }
     bool uninlineable() const {
-        js::AutoThreadSafeAccess ts(this);
         return uninlineable_;
     }
     bool invalidatedIdempotentCache() const {
-        js::AutoThreadSafeAccess ts(this);
         return invalidatedIdempotentCache_;
     }
 
     void setFailedBoundsCheck() { failedBoundsCheck_ = true; }
     void setFailedShapeGuard() { failedShapeGuard_ = true; }
     void setHadFrequentBailouts() { hadFrequentBailouts_ = true; }
     void setUninlineable() { uninlineable_ = true; }
     void setInvalidatedIdempotentCache() { invalidatedIdempotentCache_ = true; }
@@ -1090,27 +1052,25 @@ class JSScript : public js::gc::Barriere
     void setHasFreezeConstraints() { hasFreezeConstraints_ = true; }
     void clearHasFreezeConstraints() { hasFreezeConstraints_ = false; }
 
     bool warnedAboutUndefinedProp() const { return warnedAboutUndefinedProp_; }
     void setWarnedAboutUndefinedProp() { warnedAboutUndefinedProp_ = true; }
 
     /* See ContextFlags::funArgumentsHasLocalBinding comment. */
     bool argumentsHasVarBinding() const {
-        js::AutoThreadSafeAccess ts(this);
         return argsHasVarBinding_;
     }
     jsbytecode *argumentsBytecode() const { JS_ASSERT(code()[0] == JSOP_ARGUMENTS); return code(); }
     void setArgumentsHasVarBinding();
     bool argumentsAliasesFormals() const {
         return argumentsHasVarBinding() && !strict();
     }
 
     js::GeneratorKind generatorKind() const {
-        js::AutoThreadSafeAccess ts(this);
         return js::GeneratorKindFromBits(generatorKindBits_);
     }
     bool isGenerator() const { return generatorKind() != js::NotGenerator; }
     bool isLegacyGenerator() const { return generatorKind() == js::LegacyGenerator; }
     bool isStarGenerator() const { return generatorKind() == js::StarGenerator; }
     void setGeneratorKind(js::GeneratorKind kind) {
         // A script only gets its generator kind set as part of initialization,
         // so it can only transition from not being a generator.
@@ -1125,18 +1085,16 @@ class JSScript : public js::gc::Barriere
      * the script the first time. When !needsArgsObj, the prologue may simply
      * write MagicValue(JS_OPTIMIZED_ARGUMENTS) to 'arguments's slot and any
      * uses of 'arguments' will be guaranteed to handle this magic value.
      * So avoid spurious arguments object creation, we maintain the invariant
      * that needsArgsObj is only called after the script has been analyzed.
      */
     bool analyzedArgsUsage() const { return !needsArgsAnalysis_; }
     bool needsArgsObj() const {
-        js::AutoThreadSafeAccess ts(this);
-        JS_ASSERT(js::CurrentThreadCanReadCompilationData());
         JS_ASSERT(analyzedArgsUsage());
         return needsArgsObj_;
     }
     void setNeedsArgsObj(bool needsArgsObj);
     static bool argumentsOptimizationFailed(JSContext *cx, js::HandleScript script);
 
     /*
      * Arguments access (via JSOP_*ARG* opcodes) must access the canonical
@@ -1151,27 +1109,19 @@ class JSScript : public js::gc::Barriere
         return needsArgsObj() && !strict();
     }
 
     bool hasAnyIonScript() const {
         return hasIonScript() || hasParallelIonScript();
     }
 
     bool hasIonScript() const {
-        // Note: While a script's baseline script is protected by the
-        // compilation lock, writes to the ion script are not. This helps lock
-        // ordering issues in CodeGenerator::link. Tests of script->ion during
-        // off thread compilation can therefore race, though these are fairly
-        // benign and the IonScript itself is never accessed.
-        js::AutoThreadSafeAccess ts(this);
         return ion && ion != ION_DISABLED_SCRIPT && ion != ION_COMPILING_SCRIPT;
     }
     bool canIonCompile() const {
-        // Note: see above comment.
-        js::AutoThreadSafeAccess ts(this);
         return ion != ION_DISABLED_SCRIPT;
     }
 
     bool isIonCompilingOffThread() const {
         return ion == ION_COMPILING_SCRIPT;
     }
 
     js::jit::IonScript *ionScript() const {
@@ -1187,38 +1137,34 @@ class JSScript : public js::gc::Barriere
     void setIonScript(js::jit::IonScript *ionScript) {
         if (hasIonScript())
             js::jit::IonScript::writeBarrierPre(tenuredZone(), ion);
         ion = ionScript;
         updateBaselineOrIonRaw();
     }
 
     bool hasBaselineScript() const {
-        JS_ASSERT(js::CurrentThreadCanReadCompilationData());
-        js::AutoThreadSafeAccess ts(this);
         return baseline && baseline != BASELINE_DISABLED_SCRIPT;
     }
     bool canBaselineCompile() const {
         return baseline != BASELINE_DISABLED_SCRIPT;
     }
     js::jit::BaselineScript *baselineScript() const {
         JS_ASSERT(hasBaselineScript());
-        js::AutoThreadSafeAccess ts(this);
         return baseline;
     }
     inline void setBaselineScript(JSContext *maybecx, js::jit::BaselineScript *baselineScript);
 
     void updateBaselineOrIonRaw();
 
     bool hasParallelIonScript() const {
         return parallelIon && parallelIon != ION_DISABLED_SCRIPT && parallelIon != ION_COMPILING_SCRIPT;
     }
 
     bool canParallelIonCompile() const {
-        js::AutoThreadSafeAccess ts(this);
         return parallelIon != ION_DISABLED_SCRIPT;
     }
 
     bool isParallelIonCompilingOffThread() const {
         return parallelIon == ION_COMPILING_SCRIPT;
     }
 
     js::jit::IonScript *parallelIonScript() const {
@@ -1259,47 +1205,44 @@ class JSScript : public js::gc::Barriere
     }
     js::LazyScript *maybeLazyScript() {
         return lazyScript;
     }
 
     /*
      * Original compiled function for the script, if it has a function.
      * nullptr for global and eval scripts.
-     * The delazifying variant ensures that the function isn't lazy, but can
-     * only be used under a compilation lock. The non-delazifying variant
-     * can be used off-thread and without the lock, but must only be used
-     * after earlier code has called ensureNonLazyCanonicalFunction and
-     * while the function can't have been relazified.
+     * The delazifying variant ensures that the function isn't lazy. The
+     * non-delazifying variant must only be used after earlier code has
+     * called ensureNonLazyCanonicalFunction and while the function can't
+     * have been relazified.
      */
     inline JSFunction *functionDelazifying() const;
     JSFunction *functionNonDelazifying() const {
-        js::AutoThreadSafeAccess ts(this);
         return function_;
     }
     inline void setFunction(JSFunction *fun);
     /*
-     * Takes a compilation lock and de-lazifies the canonical function. Must
-     * be called before entering code that expects the function to be non-lazy.
+     * De-lazifies the canonical function. Must be called before entering code
+     * that expects the function to be non-lazy.
      */
     inline void ensureNonLazyCanonicalFunction(JSContext *cx);
 
     /*
      * Donor provided itself to callsite clone; null if this is non-clone.
      */
     JSFunction *donorFunction() const;
     void setIsCallsiteClone(JSObject *fun);
 
     JSFlatString *sourceData(JSContext *cx);
 
     static bool loadSource(JSContext *cx, js::ScriptSource *ss, bool *worked);
 
     void setSourceObject(JSObject *object);
     JSObject *sourceObject() const {
-        js::AutoThreadSafeAccess ts(this);
         return sourceObject_;
     }
     js::ScriptSource *scriptSource() const;
     JSPrincipals *originPrincipals() const { return scriptSource()->originPrincipals(); }
     const char *filename() const { return scriptSource()->filename(); }
 
   public:
 
@@ -1330,28 +1273,25 @@ class JSScript : public js::gc::Barriere
 
     inline js::GlobalObject &global() const;
     js::GlobalObject &uninlinedGlobal() const;
 
     /* See StaticScopeIter comment. */
     JSObject *enclosingStaticScope() const {
         if (isCallsiteClone())
             return nullptr;
-        js::AutoThreadSafeAccess ts(this);
         return enclosingScopeOrOriginalFunction_;
     }
 
   private:
     bool makeTypes(JSContext *cx);
     bool makeAnalysis(JSContext *cx);
 
   public:
     uint32_t getUseCount() const {
-        // Note: We ignore races when reading the use count of a script off thread.
-        js::AutoThreadSafeAccess ts(this);
         return useCount;
     }
     uint32_t incUseCount(uint32_t amount = 1) { return useCount += amount; }
     uint32_t *addressOfUseCount() { return &useCount; }
     static size_t offsetOfUseCount() { return offsetof(JSScript, useCount); }
     void resetUseCount() { useCount = 0; }
 
   public:
@@ -1376,17 +1316,16 @@ class JSScript : public js::gc::Barriere
     size_t sizeOfTypeScript(mozilla::MallocSizeOf mallocSizeOf) const;
 
     uint32_t numNotes();  /* Number of srcnote slots in the srcnotes section */
 
     /* Script notes are allocated right after the code. */
     jssrcnote *notes() { return (jssrcnote *)(code() + length()); }
 
     bool hasArray(ArrayKind kind) {
-        js::AutoThreadSafeAccess ts(this);
         return (hasArrayBits & (1 << kind));
     }
     void setHasArray(ArrayKind kind) { hasArrayBits |= (1 << kind); }
     void cloneHasArray(JSScript *script) { hasArrayBits = script->hasArrayBits; }
 
     bool hasConsts()        { return hasArray(CONSTS);      }
     bool hasObjects()       { return hasArray(OBJECTS);     }
     bool hasRegexps()       { return hasArray(REGEXPS);     }
@@ -1400,50 +1339,44 @@ class JSScript : public js::gc::Barriere
     size_t regexpsOffset()    { return OFF(objectsOffset,    hasObjects,    js::ObjectArray);     }
     size_t trynotesOffset()   { return OFF(regexpsOffset,    hasRegexps,    js::ObjectArray);     }
     size_t blockScopesOffset(){ return OFF(trynotesOffset,   hasTrynotes,   js::TryNoteArray);    }
 
     size_t dataSize() const { return dataSize_; }
 
     js::ConstArray *consts() {
         JS_ASSERT(hasConsts());
-        js::AutoThreadSafeAccess ts(this);
         return reinterpret_cast<js::ConstArray *>(data + constsOffset());
     }
 
     js::ObjectArray *objects() {
         JS_ASSERT(hasObjects());
-        js::AutoThreadSafeAccess ts(this);
         return reinterpret_cast<js::ObjectArray *>(data + objectsOffset());
     }
 
     js::ObjectArray *regexps() {
         JS_ASSERT(hasRegexps());
-        js::AutoThreadSafeAccess ts(this);
         return reinterpret_cast<js::ObjectArray *>(data + regexpsOffset());
     }
 
     js::TryNoteArray *trynotes() {
         JS_ASSERT(hasTrynotes());
-        js::AutoThreadSafeAccess ts(this);
         return reinterpret_cast<js::TryNoteArray *>(data + trynotesOffset());
     }
 
     js::BlockScopeArray *blockScopes() {
         JS_ASSERT(hasBlockScopes());
-        js::AutoThreadSafeAccess ts(this);
         return reinterpret_cast<js::BlockScopeArray *>(data + blockScopesOffset());
     }
 
     bool hasLoops();
 
     size_t natoms() const { return natoms_; }
 
     js::HeapPtrAtom &getAtom(size_t index) const {
-        js::AutoThreadSafeAccess ts(this);
         JS_ASSERT(index < natoms());
         return atoms[index];
     }
 
     js::HeapPtrAtom &getAtom(jsbytecode *pc) const {
         JS_ASSERT(containsPC(pc) && containsPC(pc + sizeof(uint32_t)));
         return getAtom(GET_UINT32_INDEX(pc));
     }
@@ -1790,17 +1723,16 @@ class LazyScript : public gc::BarrieredC
     bool directlyInsideEval() const {
         return directlyInsideEval_;
     }
     void setDirectlyInsideEval() {
         directlyInsideEval_ = true;
     }
 
     bool usesArgumentsAndApply() const {
-        AutoThreadSafeAccess ts(this);
         return usesArgumentsAndApply_;
     }
     void setUsesArgumentsAndApply() {
         usesArgumentsAndApply_ = true;
     }
 
     bool hasBeenCloned() const {
         return hasBeenCloned_;
@@ -1815,21 +1747,19 @@ class LazyScript : public gc::BarrieredC
     void setTreatAsRunOnce() {
         treatAsRunOnce_ = true;
     }
 
     ScriptSource *source() const {
         return sourceObject()->source();
     }
     uint32_t begin() const {
-        AutoThreadSafeAccess ts(this);
         return begin_;
     }
     uint32_t end() const {
-        AutoThreadSafeAccess ts(this);
         return end_;
     }
     uint32_t lineno() const {
         return lineno_;
     }
     uint32_t column() const {
         return column_;
     }
--- a/js/src/jsscriptinlines.h
+++ b/js/src/jsscriptinlines.h
@@ -53,18 +53,16 @@ LazyScript::functionDelazifying(JSContex
     return function_;
 }
 
 } // namespace js
 
 inline JSFunction *
 JSScript::functionDelazifying() const
 {
-    js::AutoThreadSafeAccess ts(this);
-    JS_ASSERT(js::CurrentThreadCanWriteCompilationData());
     if (function_ && function_->isInterpretedLazy()) {
         function_->setUnlazifiedScript(const_cast<JSScript *>(this));
         // If this script has a LazyScript, make sure the LazyScript has a
         // reference to the script when delazifying its canonical function.
         if (lazyScript && !lazyScript->maybeScript())
             lazyScript->initScript(const_cast<JSScript *>(this));
     }
     return function_;
@@ -76,29 +74,25 @@ JSScript::setFunction(JSFunction *fun)
     JS_ASSERT(fun->isTenured());
     function_ = fun;
 }
 
 inline void
 JSScript::ensureNonLazyCanonicalFunction(JSContext *cx)
 {
     // Infallibly delazify the canonical script.
-    if (function_ && function_->isInterpretedLazy()) {
-        js::AutoLockForCompilation lock(cx);
+    if (function_ && function_->isInterpretedLazy())
         functionDelazifying();
-    }
 }
 
 inline JSFunction *
 JSScript::getFunction(size_t index)
 {
     JSFunction *fun = &getObject(index)->as<JSFunction>();
-#ifdef DEBUG
     JS_ASSERT_IF(fun->isNative(), IsAsmJSModuleNative(fun->native()));
-#endif
     return fun;
 }
 
 inline JSFunction *
 JSScript::getCallerFunction()
 {
     JS_ASSERT(savedCallerFun());
     return getFunction(0);
@@ -133,49 +127,48 @@ JSScript::getRegExp(jsbytecode *pc)
 
 inline js::GlobalObject &
 JSScript::global() const
 {
     /*
      * A JSScript always marks its compartment's global (via bindings) so we
      * can assert that maybeGlobal is non-null here.
      */
-    js::AutoThreadSafeAccess ts(this);
     return *compartment()->maybeGlobal();
 }
 
 inline JSPrincipals *
 JSScript::principals()
 {
     return compartment()->principals;
 }
 
 inline JSFunction *
-JSScript::donorFunction() const {
+JSScript::donorFunction() const
+{
     if (!isCallsiteClone())
         return nullptr;
     return &enclosingScopeOrOriginalFunction_->as<JSFunction>();
 }
 
 inline void
-JSScript::setIsCallsiteClone(JSObject *fun) {
+JSScript::setIsCallsiteClone(JSObject *fun)
+{
     JS_ASSERT(shouldCloneAtCallsite());
     shouldCloneAtCallsite_ = false;
     isCallsiteClone_ = true;
     JS_ASSERT(isCallsiteClone());
     JS_ASSERT(fun->is<JSFunction>());
     enclosingScopeOrOriginalFunction_ = fun;
 }
 
 inline void
-JSScript::setBaselineScript(JSContext *maybecx, js::jit::BaselineScript *baselineScript) {
+JSScript::setBaselineScript(JSContext *maybecx, js::jit::BaselineScript *baselineScript)
+{
 #ifdef JS_ION
     if (hasBaselineScript())
         js::jit::BaselineScript::writeBarrierPre(tenuredZone(), baseline);
 #endif
-    mozilla::Maybe<js::AutoLockForCompilation> lock;
-    if (maybecx)
-        lock.construct(maybecx);
     baseline = baselineScript;
     updateBaselineOrIonRaw();
 }
 
 #endif /* jsscriptinlines_h */
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -4249,18 +4249,16 @@ bool
 js::CompareStrings(JSContext *cx, JSString *str1, JSString *str2, int32_t *result)
 {
     return CompareStringsImpl(cx, str1, str2, result);
 }
 
 int32_t
 js::CompareAtoms(JSAtom *atom1, JSAtom *atom2)
 {
-    AutoThreadSafeAccess ts0(atom1);
-    AutoThreadSafeAccess ts1(atom2);
     return CompareChars(atom1->chars(), atom1->length(), atom2->chars(), atom2->length());
 }
 
 bool
 js::StringEqualsAscii(JSLinearString *str, const char *asciiBytes)
 {
     size_t length = strlen(asciiBytes);
 #ifdef DEBUG
--- a/js/src/jsworkers.cpp
+++ b/js/src/jsworkers.cpp
@@ -88,18 +88,16 @@ js::StartOffThreadIonCompile(JSContext *
     if (!EnsureWorkerThreadsInitialized(cx))
         return false;
 
     AutoLockWorkerThreadState lock;
 
     if (!WorkerThreadState().ionWorklist().append(builder))
         return false;
 
-    cx->runtime()->addCompilationThread();
-
     WorkerThreadState().notifyAll(GlobalWorkerThreadState::PRODUCER);
     return true;
 }
 
 /*
  * Move an IonBuilder for which compilation has either finished, failed, or
  * been cancelled into the global finished compilation list. All off thread
  * compilations which are started must eventually be finished.
@@ -644,18 +642,16 @@ GlobalWorkerThreadState::finishParseTask
 
         JSProtoKey key = js_IdentifyClassPrototype(proto.toObject());
         if (key == JSProto_Null)
             continue;
 
         JSObject *newProto = GetClassPrototypePure(&parseTask->scopeChain->global(), key);
         JS_ASSERT(newProto);
 
-        // Note: this is safe to do without requiring the compilation lock, as
-        // the new type is not yet available to compilation threads.
         object->setProtoUnchecked(newProto);
     }
 
     // Move the parsed script and all its contents into the desired compartment.
     gc::MergeCompartments(parseTask->cx->compartment(), parseTask->scopeChain->compartment());
     parseTask->finish();
 
     RootedScript script(rt, parseTask->script);
@@ -786,21 +782,17 @@ WorkerThread::handleIonWorkload()
 
     {
         AutoUnlockWorkerThreadState unlock;
         PerThreadData::AutoEnterRuntime enter(threadData.addr(),
                                               ionBuilder->script()->runtimeFromAnyThread());
         jit::IonContext ictx(jit::CompileRuntime::get(rt),
                              jit::CompileCompartment::get(ionBuilder->script()->compartment()),
                              &ionBuilder->alloc());
-        AutoEnterIonCompilation ionCompiling;
-        bool succeeded = ionBuilder->build();
-        ionBuilder->clearForBackEnd();
-        if (succeeded)
-            ionBuilder->setBackgroundCodegen(jit::CompileBackEnd(ionBuilder));
+        ionBuilder->setBackgroundCodegen(jit::CompileBackEnd(ionBuilder));
     }
 
     FinishOffThreadIonCompile(ionBuilder);
     ionBuilder = nullptr;
 
     // Ping the main thread so that the compiled code can be incorporated
     // at the next operation callback. Don't interrupt Ion code for this, as
     // this incorporation can be delayed indefinitely without affecting
--- a/js/src/jswrapper.cpp
+++ b/js/src/jswrapper.cpp
@@ -78,19 +78,16 @@ Wrapper::wrappedObject(JSObject *wrapper
     return wrapper->as<ProxyObject>().target();
 }
 
 JS_FRIEND_API(JSObject *)
 js::UncheckedUnwrap(JSObject *wrapped, bool stopAtOuter, unsigned *flagsp)
 {
     unsigned flags = 0;
     while (true) {
-        AutoThreadSafeAccess ts0(wrapped);
-        AutoThreadSafeAccess ts1(wrapped->typeRaw());
-        AutoThreadSafeAccess ts2(wrapped->lastProperty());
         if (!wrapped->is<WrapperObject>() ||
             MOZ_UNLIKELY(stopAtOuter && wrapped->getClass()->ext.innerObject))
         {
             break;
         }
         flags |= Wrapper::wrapperHandler(wrapped)->flags();
         wrapped = wrapped->as<ProxyObject>().private_().toObjectOrNull();
     }
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -5506,19 +5506,16 @@ ProcessArgs(JSContext *cx, JSObject *obj
              jit::js_JitOptions.disableRangeAnalysis = true;
          else
              return OptionFailure("ion-range-analysis", str);
      }
 
     if (op->getBoolOption("ion-check-range-analysis"))
         jit::js_JitOptions.checkRangeAnalysis = true;
 
-    if (op->getBoolOption("ion-check-thread-safety"))
-        jit::js_JitOptions.checkThreadSafety = true;
-
     if (const char *str = op->getStringOption("ion-inlining")) {
         if (strcmp(str, "on") == 0)
             jit::js_JitOptions.disableInlining = false;
         else if (strcmp(str, "off") == 0)
             jit::js_JitOptions.disableInlining = true;
         else
             return OptionFailure("ion-inlining", str);
     }
@@ -5783,18 +5780,16 @@ main(int argc, char **argv, char **envp)
         || !op.addStringOption('\0', "ion-licm", "on/off",
                                "Loop invariant code motion (default: on, off to disable)")
         || !op.addStringOption('\0', "ion-edgecase-analysis", "on/off",
                                "Find edge cases where Ion can avoid bailouts (default: on, off to disable)")
         || !op.addStringOption('\0', "ion-range-analysis", "on/off",
                                "Range analysis (default: on, off to disable)")
         || !op.addBoolOption('\0', "ion-check-range-analysis",
                                "Range analysis checking")
-        || !op.addBoolOption('\0', "ion-check-thread-safety",
-                             "IonBuilder thread safety checking")
         || !op.addStringOption('\0', "ion-inlining", "on/off",
                                "Inline methods where possible (default: on, off to disable)")
         || !op.addStringOption('\0', "ion-osr", "on/off",
                                "On-Stack Replacement (default: on, off to disable)")
         || !op.addStringOption('\0', "ion-limit-script-size", "on/off",
                                "Don't compile very large scripts (default: on, off to disable)")
         || !op.addIntOption('\0', "ion-uses-before-compile", "COUNT",
                             "Wait for COUNT calls or iterations before compiling "
@@ -5893,25 +5888,18 @@ main(int argc, char **argv, char **envp)
     if (stopAt >= 0)
         jit::Simulator::StopSimAt = stopAt;
 #endif
 
     // Start the engine.
     if (!JS_Init())
         return 1;
 
-    // When doing thread safety checks for VM accesses made during Ion compilation,
-    // we rely on protected memory and only the main thread should be active.
-    JSUseHelperThreads useHelperThreads =
-        op.getBoolOption("ion-check-thread-safety")
-        ? JS_NO_HELPER_THREADS
-        : JS_USE_HELPER_THREADS;
-
     /* Use the same parameters as the browser in xpcjsruntime.cpp. */
-    rt = JS_NewRuntime(32L * 1024L * 1024L, useHelperThreads);
+    rt = JS_NewRuntime(32L * 1024L * 1024L, JS_USE_HELPER_THREADS);
     if (!rt)
         return 1;
     gTimeoutFunc = NullValue();
     if (!JS_AddNamedValueRootRT(rt, &gTimeoutFunc, "gTimeoutFunc"))
         return 1;
 
     JS_SetGCParameter(rt, JSGC_MAX_BYTES, 0xffffffff);
 #ifdef JSGC_GENERATIONAL
--- a/js/src/vm/GlobalObject.cpp
+++ b/js/src/vm/GlobalObject.cpp
@@ -549,24 +549,24 @@ GlobalObject::create(JSContext *cx, cons
 }
 
 /* static */ bool
 GlobalObject::getOrCreateEval(JSContext *cx, Handle<GlobalObject*> global,
                               MutableHandleObject eval)
 {
     if (!global->getOrCreateObjectPrototype(cx))
         return false;
-    eval.set(&global->getSlotForCompilation(EVAL).toObject());
+    eval.set(&global->getSlot(EVAL).toObject());
     return true;
 }
 
 bool
 GlobalObject::valueIsEval(Value val)
 {
-    Value eval = getSlotForCompilation(EVAL);
+    Value eval = getSlot(EVAL);
     return eval.isObject() && eval == val;
 }
 
 /* static */ bool
 GlobalObject::initStandardClasses(JSContext *cx, Handle<GlobalObject*> global)
 {
     /* Define a top-level property 'undefined' with the undefined value. */
     if (!JSObject::defineProperty(cx, global, cx->names().undefined, UndefinedHandleValue,
@@ -783,28 +783,23 @@ GlobalObject::getSelfHostedFunction(JSCo
     return cx->global()->addIntrinsicValue(cx, shId, funVal);
 }
 
 bool
 GlobalObject::addIntrinsicValue(JSContext *cx, HandleId id, HandleValue value)
 {
     RootedObject holder(cx, intrinsicsHolder());
 
-    // Work directly with the shape machinery underlying the object, so that we
-    // don't take the compilation lock until we are ready to update the object
-    // without triggering a GC.
-
     uint32_t slot = holder->slotSpan();
     RootedShape last(cx, holder->lastProperty());
     Rooted<UnownedBaseShape*> base(cx, last->base()->unowned());
 
     StackShape child(base, id, slot, 0, 0, 0);
     RootedShape shape(cx, cx->compartment()->propertyTree.getChild(cx, last, child));
     if (!shape)
         return false;
 
-    AutoLockForCompilation lock(cx);
     if (!JSObject::setLastProperty(cx, holder, shape))
         return false;
 
     holder->setSlot(shape->slot(), value);
     return true;
 }
--- a/js/src/vm/GlobalObject.h
+++ b/js/src/vm/GlobalObject.h
@@ -153,29 +153,29 @@ class GlobalObject : public JSObject
     // for each global object it's called on, and every other call does
     // nothing.
     static bool
     warnOnceAbout(JSContext *cx, HandleObject obj, uint32_t slot, unsigned errorNumber);
 
   public:
     Value getConstructor(JSProtoKey key) const {
         JS_ASSERT(key <= JSProto_LIMIT);
-        return getSlotForCompilation(APPLICATION_SLOTS + key);
+        return getSlot(APPLICATION_SLOTS + key);
     }
     static bool ensureConstructor(JSContext *cx, Handle<GlobalObject*> global, JSProtoKey key);
     static bool initConstructor(JSContext *cx, Handle<GlobalObject*> global, JSProtoKey key);
 
     void setConstructor(JSProtoKey key, const Value &v) {
         JS_ASSERT(key <= JSProto_LIMIT);
         setSlot(APPLICATION_SLOTS + key, v);
     }
 
     Value getPrototype(JSProtoKey key) const {
         JS_ASSERT(key <= JSProto_LIMIT);
-        return getSlotForCompilation(APPLICATION_SLOTS + JSProto_LIMIT + key);
+        return getSlot(APPLICATION_SLOTS + JSProto_LIMIT + key);
     }
 
     void setPrototype(JSProtoKey key, const Value &value) {
         JS_ASSERT(key <= JSProto_LIMIT);
         setSlot(APPLICATION_SLOTS + JSProto_LIMIT + key, value);
     }
 
     static uint32_t constructorPropertySlot(JSProtoKey key) {
@@ -452,29 +452,16 @@ class GlobalObject : public JSObject
         if (v.isObject())
             return &v.toObject();
         Rooted<GlobalObject*> self(cx, this);
         if (!init(cx, self))
             return nullptr;
         return &self->getSlot(slot).toObject();
     }
 
-    Value getSlotForCompilation(uint32_t slot) const {
-        // This method should only be used for slots that are either eagerly
-        // initialized on creation of the global or only change under the
-        // compilation lock. Note that the dynamic slots pointer for global
-        // objects can only change under the compilation lock.
-        JS_ASSERT(slot < JSCLASS_RESERVED_SLOTS(getClass()));
-        uint32_t fixed = numFixedSlotsForCompilation();
-        AutoThreadSafeAccess ts(this);
-        if (slot < fixed)
-            return fixedSlots()[slot];
-        return slots[slot - fixed];
-    }
-
   public:
     static JSObject *getOrCreateIteratorPrototype(JSContext *cx,
                                                   Handle<GlobalObject*> global)
     {
         if (!ensureConstructor(cx, global, JSProto_Iterator))
             return nullptr;
         return &global->getSlot(APPLICATION_SLOTS + JSProto_LIMIT + JSProto_Iterator).toObject();
     }
@@ -542,28 +529,23 @@ class GlobalObject : public JSObject
     JSObject *getOrCreateDataViewPrototype(JSContext *cx) {
         Rooted<GlobalObject*> self(cx, this);
         if (!ensureConstructor(cx, self, JSProto_DataView))
             return nullptr;
         return &self->getPrototype(JSProto_DataView).toObject();
     }
 
     JSObject *intrinsicsHolder() {
-        JS_ASSERT(!getSlotForCompilation(INTRINSICS).isUndefined());
-        return &getSlotForCompilation(INTRINSICS).toObject();
+        JS_ASSERT(!getSlot(INTRINSICS).isUndefined());
+        return &getSlot(INTRINSICS).toObject();
     }
 
     bool maybeGetIntrinsicValue(jsid id, Value *vp) {
-        JS_ASSERT(CurrentThreadCanReadCompilationData());
         JSObject *holder = intrinsicsHolder();
 
-        AutoThreadSafeAccess ts0(holder);
-        AutoThreadSafeAccess ts1(holder->lastProperty());
-        AutoThreadSafeAccess ts2(holder->lastProperty()->base());
-
         if (Shape *shape = holder->nativeLookupPure(id)) {
             *vp = holder->getSlot(shape->slot());
             return true;
         }
         return false;
     }
     bool maybeGetIntrinsicValue(PropertyName *name, Value *vp) {
         return maybeGetIntrinsicValue(NameToId(name), vp);
@@ -591,18 +573,17 @@ class GlobalObject : public JSObject
         RootedValue valCopy(cx, value);
         return JSObject::setProperty(cx, holder, holder, name, &valCopy, false);
     }
 
     bool getSelfHostedFunction(JSContext *cx, HandleAtom selfHostedName, HandleAtom name,
                                unsigned nargs, MutableHandleValue funVal);
 
     RegExpStatics *getRegExpStatics() const {
-        JSObject &resObj = getSlotForCompilation(REGEXP_STATICS).toObject();
-        AutoThreadSafeAccess ts(&resObj);
+        JSObject &resObj = getSlot(REGEXP_STATICS).toObject();
         return static_cast<RegExpStatics *>(resObj.getPrivate(/* nfixed = */ 1));
     }
 
     JSObject *getThrowTypeError() const {
         JS_ASSERT(functionObjectClassesInitialized());
         return &getSlot(THROWTYPEERROR).toObject();
     }
 
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -1315,17 +1315,17 @@ SetObjectElementOperation(JSContext *cx,
 
 #ifdef JS_ION
     if (obj->isNative() && JSID_IS_INT(id)) {
         uint32_t length = obj->getDenseInitializedLength();
         int32_t i = JSID_TO_INT(id);
         if ((uint32_t)i >= length) {
             // Annotate script if provided with information (e.g. baseline)
             if (script && script->hasBaselineScript() && *pc == JSOP_SETELEM)
-                script->baselineScript()->noteArrayWriteHole(cx, script->pcToOffset(pc));
+                script->baselineScript()->noteArrayWriteHole(script->pcToOffset(pc));
         }
     }
 #endif
 
     if (obj->isNative() && !JSID_IS_INT(id) && !obj->setHadElementsAccess(cx))
         return false;
 
     RootedValue tmp(cx, value);
--- a/js/src/vm/ObjectImpl.cpp
+++ b/js/src/vm/ObjectImpl.cpp
@@ -330,35 +330,16 @@ js::ObjectImpl::nativeLookup(ExclusiveCo
 Shape *
 js::ObjectImpl::nativeLookupPure(jsid id)
 {
     MOZ_ASSERT(isNative());
     return Shape::searchNoHashify(lastProperty(), id);
 }
 
 uint32_t
-js::ObjectImpl::numFixedSlotsForCompilation() const
-{
-    // This is an alternative method for getting the number of fixed slots
-    // in an object. It requires more logic and memory accesses than
-    // numFixedSlots() but is safe to be called from the compilation thread,
-    // even if the main thread is actively mutating the VM.
-    if (static_cast<const JSObject *>(this)->is<ArrayObject>())
-        return 0;
-#ifdef JSGC_GENERATIONAL
-    // The compiler does not have access to nursery things, so if this object
-    // is in the nursery we can fall back to numFixedSlots().
-    if (IsInsideNursery(GetGCThingRuntime(this), this))
-        return numFixedSlots();
-#endif
-    gc::AllocKind kind = tenuredGetAllocKind();
-    return gc::GetGCKindSlots(kind, getClass());
-}
-
-uint32_t
 js::ObjectImpl::dynamicSlotsCount(uint32_t nfixed, uint32_t span, const Class *clasp)
 {
     if (span <= nfixed)
         return 0;
     span -= nfixed;
 
     // Increase the slots to SLOT_CAPACITY_MIN to decrease the likelihood
     // the dynamic slots need to get increased again. ArrayObjects ignore
--- a/js/src/vm/ObjectImpl.h
+++ b/js/src/vm/ObjectImpl.h
@@ -979,24 +979,22 @@ class ObjectImpl : public gc::BarrieredC
     const JSObject * asObjectPtr() const { return reinterpret_cast<const JSObject *>(this); }
 
     friend inline Value ObjectValue(ObjectImpl &obj);
 
     /* These functions are public, and they should remain public. */
 
   public:
     TaggedProto getTaggedProto() const {
-        AutoThreadSafeAccess ts(this);
         return type_->proto();
     }
 
     bool hasTenuredProto() const;
 
     const Class *getClass() const {
-        AutoThreadSafeAccess ts(this);
         return type_->clasp();
     }
 
     static inline bool
     isExtensible(ExclusiveContext *cx, Handle<ObjectImpl*> obj, bool *extensible);
 
     // Indicates whether a non-proxy is extensible.  Don't call on proxies!
     // This method really shouldn't exist -- but there are a few internal
@@ -1201,42 +1199,36 @@ class ObjectImpl : public gc::BarrieredC
     }
 
     types::TypeObject *type() const {
         MOZ_ASSERT(!hasLazyType());
         return typeRaw();
     }
 
     types::TypeObject *typeRaw() const {
-        AutoThreadSafeAccess ts0(this);
-        AutoThreadSafeAccess ts1(type_);
         return type_;
     }
 
     uint32_t numFixedSlots() const {
         return reinterpret_cast<const shadow::Object *>(this)->numFixedSlots();
     }
 
-    uint32_t numFixedSlotsForCompilation() const;
-
     /*
      * Whether this is the only object which has its specified type. This
      * object will have its type constructed lazily as needed by analysis.
      */
     bool hasSingletonType() const {
-        AutoThreadSafeAccess ts(this);
         return !!type_->singleton();
     }
 
     /*
      * Whether the object's type has not been constructed yet. If an object
      * might have a lazy type, use getType() below, otherwise type().
      */
     bool hasLazyType() const {
-        AutoThreadSafeAccess ts(this);
         return type_->lazy();
     }
 
     uint32_t slotSpan() const {
         if (inDictionaryMode())
             return lastProperty()->base()->slotSpan();
         return lastProperty()->slotSpan();
     }
@@ -1386,17 +1378,17 @@ class ObjectImpl : public gc::BarrieredC
     /* For slots which are known to always be fixed, due to the way they are allocated. */
 
     HeapSlot &getFixedSlotRef(uint32_t slot) {
         MOZ_ASSERT(slot < numFixedSlots());
         return fixedSlots()[slot];
     }
 
     const Value &getFixedSlot(uint32_t slot) const {
-        MOZ_ASSERT(slot < numFixedSlotsForCompilation());
+        MOZ_ASSERT(slot < numFixedSlots());
         return fixedSlots()[slot];
     }
 
     void setFixedSlot(uint32_t slot, const Value &value) {
         MOZ_ASSERT(slot < numFixedSlots());
         fixedSlots()[slot].set(this->asObjectPtr(), HeapSlot::Slot, slot, value);
     }
 
@@ -1473,17 +1465,17 @@ class ObjectImpl : public gc::BarrieredC
     /* Private data accessors. */
 
     inline void *&privateRef(uint32_t nfixed) const { /* XXX should be private, not protected! */
         /*
          * The private pointer of an object can hold any word sized value.
          * Private pointers are stored immediately after the last fixed slot of
          * the object.
          */
-        MOZ_ASSERT(nfixed == numFixedSlotsForCompilation());
+        MOZ_ASSERT(nfixed == numFixedSlots());
         MOZ_ASSERT(hasPrivate());
         HeapSlot *end = &fixedSlots()[nfixed];
         return *reinterpret_cast<void**>(end);
     }
 
     bool hasPrivate() const {
         return getClass()->hasPrivate();
     }
@@ -1550,20 +1542,16 @@ BarrieredCell<ObjectImpl>::zone() const
     return zone;
 }
 
 template <>
 MOZ_ALWAYS_INLINE Zone *
 BarrieredCell<ObjectImpl>::zoneFromAnyThread() const
 {
     const ObjectImpl* obj = static_cast<const ObjectImpl*>(this);
-
-    // Note: This read of obj->shape_ may race, though the zone fetched will be the same.
-    AutoThreadSafeAccess ts(obj->shape_);
-
     return obj->shape_->zoneFromAnyThread();
 }
 
 // TypeScript::global uses 0x1 as a special value.
 template<>
 /* static */ inline bool
 BarrieredCell<ObjectImpl>::isNullLike(ObjectImpl *obj)
 {
--- a/js/src/vm/Runtime.cpp
+++ b/js/src/vm/Runtime.cpp
@@ -75,19 +75,16 @@ PerThreadData::PerThreadData(JSRuntime *
     activation_(nullptr),
     asmJSActivationStack_(nullptr),
 #ifdef JS_ARM_SIMULATOR
     simulator_(nullptr),
     simulatorStackLimit_(0),
 #endif
     dtoaState(nullptr),
     suppressGC(0),
-#ifdef DEBUG
-    ionCompiling(false),
-#endif
     activeCompilations(0)
 {}
 
 PerThreadData::~PerThreadData()
 {
     if (dtoaState)
         js_DestroyDtoaState(dtoaState);
 
@@ -127,22 +124,16 @@ JSRuntime::JSRuntime(JSUseHelperThreads 
     operationCallback(nullptr),
 #ifdef JS_THREADSAFE
     operationCallbackLock(nullptr),
     operationCallbackOwner(nullptr),
     exclusiveAccessLock(nullptr),
     exclusiveAccessOwner(nullptr),
     mainThreadHasExclusiveAccess(false),
     numExclusiveThreads(0),
-    compilationLock(nullptr),
-#ifdef DEBUG
-    compilationLockOwner(nullptr),
-    mainThreadHasCompilationLock(false),
-#endif
-    numCompilationThreads(0),
 #else
     operationCallbackLockTaken(false),
 #endif
     systemZone(nullptr),
     numCompartments(0),
     localeCallbacks(nullptr),
     defaultLocale(nullptr),
     defaultVersion_(JSVERSION_DEFAULT),
@@ -275,17 +266,16 @@ JSRuntime::JSRuntime(JSUseHelperThreads 
     structuredCloneCallbacks(nullptr),
     telemetryCallback(nullptr),
     propertyRemovals(0),
 #if !EXPOSE_INTL_API
     thousandsSeparator(0),
     decimalSeparator(0),
     numGrouping(0),
 #endif
-    heapProtected_(false),
     mathCache_(nullptr),
     activeCompilations_(0),
     keepAtoms_(0),
     trustedPrincipals_(nullptr),
     atomsCompartment_(nullptr),
     beingDestroyed_(false),
     wrapObjectCallbacks(&DefaultWrapObjectCallbacks),
     preserveWrapperCallback(nullptr),
@@ -355,20 +345,16 @@ JSRuntime::init(uint32_t maxbytes)
 
     gcLock = PR_NewLock();
     if (!gcLock)
         return false;
 
     exclusiveAccessLock = PR_NewLock();
     if (!exclusiveAccessLock)
         return false;
-
-    compilationLock = PR_NewLock();
-    if (!compilationLock)
-        return false;
 #endif
 
     if (!mainThread.init())
         return false;
 
     js::TlsPerThreadData.set(&mainThread);
 
     if (!threadPool.init())
@@ -490,20 +476,16 @@ JSRuntime::~JSRuntime()
     JS_ASSERT(!exclusiveAccessOwner);
     if (exclusiveAccessLock)
         PR_DestroyLock(exclusiveAccessLock);
 
     // Avoid bogus asserts during teardown.
     JS_ASSERT(!numExclusiveThreads);
     mainThreadHasExclusiveAccess = true;
 
-    JS_ASSERT(!compilationLockOwner);
-    if (compilationLock)
-        PR_DestroyLock(compilationLock);
-
     JS_ASSERT(!operationCallbackOwner);
     if (operationCallbackLock)
         PR_DestroyLock(operationCallbackLock);
 #endif
 
     /*
      * Even though all objects in the compartment are dead, we may have keep
      * some filenames around because of gcKeepAtoms.
@@ -854,86 +836,16 @@ JSRuntime::onOutOfMemory(void *p, size_t
 
 bool
 JSRuntime::activeGCInAtomsZone()
 {
     Zone *zone = atomsCompartment_->zone();
     return zone->needsBarrier() || zone->isGCScheduled() || zone->wasGCStarted();
 }
 
-#ifdef JS_CAN_CHECK_THREADSAFE_ACCESSES
-
-AutoProtectHeapForIonCompilation::AutoProtectHeapForIonCompilation(JSRuntime *rt MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
-  : runtime(rt)
-{
-    MOZ_GUARD_OBJECT_NOTIFIER_INIT;
-
-    JS_ASSERT(!runtime->heapProtected_);
-    runtime->heapProtected_ = true;
-
-    for (GCChunkSet::Range r(rt->gcChunkSet.all()); !r.empty(); r.popFront()) {
-        Chunk *chunk = r.front();
-        // Note: Don't protect the last page in the chunk, which stores
-        // immutable info and needs to be accessible for runtimeFromAnyThread()
-        // in AutoThreadSafeAccess.
-        if (mprotect(chunk, ChunkSize - sizeof(Arena), PROT_NONE))
-            MOZ_CRASH();
-    }
-}
-
-AutoProtectHeapForIonCompilation::~AutoProtectHeapForIonCompilation()
-{
-    JS_ASSERT(runtime->heapProtected_);
-    JS_ASSERT(runtime->unprotectedArenas.empty());
-    runtime->heapProtected_ = false;
-
-    for (GCChunkSet::Range r(runtime->gcChunkSet.all()); !r.empty(); r.popFront()) {
-        Chunk *chunk = r.front();
-        if (mprotect(chunk, ChunkSize - sizeof(Arena), PROT_READ | PROT_WRITE))
-            MOZ_CRASH();
-    }
-}
-
-AutoThreadSafeAccess::AutoThreadSafeAccess(const Cell *cell MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
-  : runtime(cell->runtimeFromAnyThread()), arena(nullptr)
-{
-    MOZ_GUARD_OBJECT_NOTIFIER_INIT;
-
-    if (!runtime->heapProtected_)
-        return;
-
-    ArenaHeader *base = cell->arenaHeader();
-    for (size_t i = 0; i < runtime->unprotectedArenas.length(); i++) {
-        if (base == runtime->unprotectedArenas[i])
-            return;
-    }
-
-    arena = base;
-
-    if (mprotect(arena, sizeof(Arena), PROT_READ | PROT_WRITE))
-        MOZ_CRASH();
-
-    if (!runtime->unprotectedArenas.append(arena))
-        MOZ_CRASH();
-}
-
-AutoThreadSafeAccess::~AutoThreadSafeAccess()
-{
-    if (!arena)
-        return;
-
-    if (mprotect(arena, sizeof(Arena), PROT_NONE))
-        MOZ_CRASH();
-
-    JS_ASSERT(arena == runtime->unprotectedArenas.back());
-    runtime->unprotectedArenas.popBack();
-}
-
-#endif // JS_CAN_CHECK_THREADSAFE_ACCESSES
-
 #ifdef JS_THREADSAFE
 
 void
 JSRuntime::setUsedByExclusiveThread(Zone *zone)
 {
     JS_ASSERT(!zone->usedByExclusiveThread);
     zone->usedByExclusiveThread = true;
     numExclusiveThreads++;
@@ -988,87 +900,27 @@ JSRuntime::assertCanLock(RuntimeLock whi
     // In the switch below, each case falls through to the one below it. None
     // of the runtime locks are reentrant, and when multiple locks are acquired
     // it must be done in the order below.
     switch (which) {
       case ExclusiveAccessLock:
         JS_ASSERT(exclusiveAccessOwner != PR_GetCurrentThread());
       case WorkerThreadStateLock:
         JS_ASSERT(!WorkerThreadState().isLocked());
-      case CompilationLock:
-        JS_ASSERT(compilationLockOwner != PR_GetCurrentThread());
       case OperationCallbackLock:
         JS_ASSERT(!currentThreadOwnsOperationCallbackLock());
       case GCLock:
         JS_ASSERT(gcLockOwner != PR_GetCurrentThread());
         break;
       default:
         MOZ_CRASH();
     }
 #endif // JS_THREADSAFE
 }
 
-AutoEnterIonCompilation::AutoEnterIonCompilation(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_IN_IMPL)
-{
-    MOZ_GUARD_OBJECT_NOTIFIER_INIT;
-
-#ifdef JS_THREADSAFE
-    PerThreadData *pt = js::TlsPerThreadData.get();
-    JS_ASSERT(!pt->ionCompiling);
-    pt->ionCompiling = true;
-#endif
-}
-
-AutoEnterIonCompilation::~AutoEnterIonCompilation()
-{
-#ifdef JS_THREADSAFE
-    PerThreadData *pt = js::TlsPerThreadData.get();
-    JS_ASSERT(pt->ionCompiling);
-    pt->ionCompiling = false;
-#endif
-}
-
-bool
-js::CurrentThreadCanWriteCompilationData()
-{
-#ifdef JS_THREADSAFE
-    PerThreadData *pt = TlsPerThreadData.get();
-
-    // Data can only be read from during compilation.
-    if (pt->ionCompiling)
-        return false;
-
-    // Ignore what threads with exclusive contexts are doing; these never have
-    // run scripts or have associated compilation threads.
-    JSRuntime *rt = pt->runtimeIfOnOwnerThread();
-    if (!rt)
-        return true;
-
-    return rt->currentThreadHasCompilationLock();
-#else
-    return true;
-#endif
-}
-
-bool
-js::CurrentThreadCanReadCompilationData()
-{
-#ifdef JS_THREADSAFE
-    PerThreadData *pt = TlsPerThreadData.get();
-
-    // Data can always be read from freely outside of compilation.
-    if (!pt || !pt->ionCompiling)
-        return true;
-
-    return pt->runtime_->currentThreadHasCompilationLock();
-#else
-    return true;
-#endif
-}
-
 void
 js::AssertCurrentThreadCanLock(RuntimeLock which)
 {
 #ifdef JS_THREADSAFE
     PerThreadData *pt = TlsPerThreadData.get();
     if (pt && pt->runtime_)
         pt->runtime_->assertCanLock(which);
 #endif
--- a/js/src/vm/Runtime.h
+++ b/js/src/vm/Runtime.h
@@ -478,17 +478,16 @@ AtomStateOffsetToName(const JSAtomState 
 }
 
 // There are several coarse locks in the enum below. These may be either
 // per-runtime or per-process. When acquiring more than one of these locks,
 // the acquisition must be done in the order below to avoid deadlocks.
 enum RuntimeLock {
     ExclusiveAccessLock,
     WorkerThreadStateLock,
-    CompilationLock,
     OperationCallbackLock,
     GCLock
 };
 
 #ifdef DEBUG
 void AssertCurrentThreadCanLock(RuntimeLock which);
 #else
 inline void AssertCurrentThreadCanLock(RuntimeLock which) {}
@@ -548,17 +547,16 @@ class PerThreadData : public PerThreadDa
      * synchronized (by rt->operationCallbackLock).
      */
   private:
     friend class js::Activation;
     friend class js::ActivationIterator;
     friend class js::jit::JitActivation;
     friend class js::AsmJSActivation;
 #ifdef DEBUG
-    friend bool js::CurrentThreadCanReadCompilationData();
     friend void js::AssertCurrentThreadCanLock(RuntimeLock which);
 #endif
 
     /*
      * Points to the most recent activation running on the thread.
      * See Activation comment in vm/Stack.h.
      */
     js::Activation *activation_;
@@ -598,21 +596,16 @@ class PerThreadData : public PerThreadDa
      * to suppress GC when reporting an OOM (see js_ReportOutOfMemory) and in
      * debugging facilities that cannot tolerate a GC and would rather OOM
      * immediately, such as utilities exposed to GDB. Setting this flag is
      * extremely dangerous and should only be used when in an OOM situation or
      * in non-exposed debugging facilities.
      */
     int32_t suppressGC;
 
-#ifdef DEBUG
-    // Whether this thread is actively Ion compiling.
-    bool ionCompiling;
-#endif
-
     // Number of active bytecode compilation on this thread.
     unsigned activeCompilations;
 
     PerThreadData(JSRuntime *runtime);
     ~PerThreadData();
 
     bool init();
 
@@ -653,18 +646,16 @@ class PerThreadData : public PerThreadDa
 
 namespace gc {
 class MarkingValidator;
 } // namespace gc
 
 typedef Vector<JS::Zone *, 4, SystemAllocPolicy> ZoneVector;
 
 class AutoLockForExclusiveAccess;
-class AutoLockForCompilation;
-class AutoProtectHeapForIonCompilation;
 
 void RecomputeStackLimit(JSRuntime *rt, StackKind kind);
 
 } // namespace js
 
 struct JSRuntime : public JS::shadow::Runtime,
                    public js::MallocProvider<JSRuntime>
 {
@@ -769,38 +760,16 @@ struct JSRuntime : public JS::shadow::Ru
     mozilla::DebugOnly<PRThread *> exclusiveAccessOwner;
     mozilla::DebugOnly<bool> mainThreadHasExclusiveAccess;
 
     /* Number of non-main threads with an ExclusiveContext. */
     size_t numExclusiveThreads;
 
     friend class js::AutoLockForExclusiveAccess;
 
-    /*
-     * Lock taken when using data that can be modified by the main thread but
-     * read by Ion compilation threads. Any time either the main thread writes
-     * such data or the compilation thread reads it, this lock must be taken.
-     * Note that no externally visible data is modified by the compilation
-     * thread, so the main thread never needs to take this lock when reading.
-     */
-    PRLock *compilationLock;
-#ifdef DEBUG
-    PRThread *compilationLockOwner;
-    bool mainThreadHasCompilationLock;
-#endif
-
-    /* Number of in flight Ion compilations. */
-    size_t numCompilationThreads;
-
-    friend class js::AutoLockForCompilation;
-#ifdef DEBUG
-    friend bool js::CurrentThreadCanWriteCompilationData();
-    friend bool js::CurrentThreadCanReadCompilationData();
-#endif
-
   public:
     void setUsedByExclusiveThread(JS::Zone *zone);
     void clearUsedByExclusiveThread(JS::Zone *zone);
 
 #endif // JS_THREADSAFE
 
 #ifdef DEBUG
     bool currentThreadHasExclusiveAccess() {
@@ -816,51 +785,16 @@ struct JSRuntime : public JS::shadow::Ru
     bool exclusiveThreadsPresent() const {
 #ifdef JS_THREADSAFE
         return numExclusiveThreads > 0;
 #else
         return false;
 #endif
     }
 
-    void addCompilationThread() {
-#ifdef JS_THREADSAFE
-        numCompilationThreads++;
-#else
-        MOZ_ASSUME_UNREACHABLE("No threads");
-#endif
-    }
-    void removeCompilationThread() {
-#ifdef JS_THREADSAFE
-        JS_ASSERT(numCompilationThreads);
-        numCompilationThreads--;
-#else
-        MOZ_ASSUME_UNREACHABLE("No threads");
-#endif
-    }
-
-    bool compilationThreadsPresent() const {
-#ifdef JS_THREADSAFE
-        return numCompilationThreads > 0;
-#else
-        return false;
-#endif
-    }
-
-#ifdef DEBUG
-    bool currentThreadHasCompilationLock() {
-#ifdef JS_THREADSAFE
-        return (!numCompilationThreads && mainThreadHasCompilationLock) ||
-               compilationLockOwner == PR_GetCurrentThread();
-#else
-        return true;
-#endif
-    }
-#endif // DEBUG
-
     /* Embedders can use this zone however they wish. */
     JS::Zone            *systemZone;
 
     /* List of compartments and zones (protected by the GC lock). */
     js::ZoneVector      zones;
 
     /* How many compartments there are across all zones. */
     size_t              numCompartments;
@@ -1469,28 +1403,16 @@ struct JSRuntime : public JS::shadow::Ru
 
 #if !EXPOSE_INTL_API
     /* Number localization, used by jsnum.cpp. */
     const char          *thousandsSeparator;
     const char          *decimalSeparator;
     const char          *numGrouping;
 #endif
 
-    friend class js::AutoProtectHeapForIonCompilation;
-    friend class js::AutoThreadSafeAccess;
-    mozilla::DebugOnly<bool> heapProtected_;
-#ifdef DEBUG
-    js::Vector<js::gc::ArenaHeader *, 0, js::SystemAllocPolicy> unprotectedArenas;
-
-  public:
-    bool heapProtected() {
-        return heapProtected_;
-    }
-#endif
-
   private:
     js::MathCache *mathCache_;
     js::MathCache *createMathCache(JSContext *cx);
   public:
     js::MathCache *getMathCache(JSContext *cx) {
         return mathCache_ ? mathCache_ : createMathCache(cx);
     }
     js::MathCache *maybeGetMathCache() {
@@ -2078,52 +2000,15 @@ class RuntimeAllocPolicy
     void *calloc_(size_t bytes) { return runtime->calloc_(bytes); }
     void *realloc_(void *p, size_t bytes) { return runtime->realloc_(p, bytes); }
     void free_(void *p) { js_free(p); }
     void reportAllocOverflow() const {}
 };
 
 extern const JSSecurityCallbacks NullSecurityCallbacks;
 
-// Debugging RAII class which marks the current thread as performing an Ion
-// compilation, for use by CurrentThreadCan{Read,Write}CompilationData
-class AutoEnterIonCompilation
-{
-  public:
-#ifdef DEBUG
-    AutoEnterIonCompilation(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM);
-    ~AutoEnterIonCompilation();
-#else
-    AutoEnterIonCompilation(MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
-    {
-        MOZ_GUARD_OBJECT_NOTIFIER_INIT;
-    }
-#endif
-    MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
-};
-
-// Debugging RAII class which protects the entire GC heap for the duration of an
-// Ion compilation. When used only the main thread will be active and all
-// accesses to GC things must be wrapped by an AutoThreadSafeAccess instance.
-class AutoProtectHeapForIonCompilation
-{
-  public:
-#ifdef JS_CAN_CHECK_THREADSAFE_ACCESSES
-    JSRuntime *runtime;
-
-    AutoProtectHeapForIonCompilation(JSRuntime *rt MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
-    ~AutoProtectHeapForIonCompilation();
-#else
-    AutoProtectHeapForIonCompilation(JSRuntime *rt MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
-    {
-        MOZ_GUARD_OBJECT_NOTIFIER_INIT;
-    }
-#endif
-    MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
-};
-
 } /* namespace js */
 
 #ifdef _MSC_VER
 #pragma warning(pop)
 #endif
 
 #endif /* vm_Runtime_h */
--- a/js/src/vm/ScopeObject-inl.h
+++ b/js/src/vm/ScopeObject-inl.h
@@ -71,20 +71,18 @@ StaticScopeIter<allowGC>::hasDynamicScop
 }
 
 template <AllowGC allowGC>
 inline Shape *
 StaticScopeIter<allowGC>::scopeShape() const
 {
     JS_ASSERT(hasDynamicScopeObject());
     JS_ASSERT(type() != NAMED_LAMBDA);
-    if (type() == BLOCK) {
-        AutoThreadSafeAccess ts(&block());
+    if (type() == BLOCK)
         return block().lastProperty();
-    }
     return funScript()->callObjShape();
 }
 
 template <AllowGC allowGC>
 inline typename StaticScopeIter<allowGC>::Type
 StaticScopeIter<allowGC>::type() const
 {
     if (onNamedLambda)
--- a/js/src/vm/ScopeObject.h
+++ b/js/src/vm/ScopeObject.h
@@ -195,17 +195,16 @@ class ScopeObject : public JSObject
 
   public:
     /*
      * Since every scope chain terminates with a global object and GlobalObject
      * does not derive ScopeObject (it has a completely different layout), the
      * enclosing scope of a ScopeObject is necessarily non-null.
      */
     inline JSObject &enclosingScope() const {
-        AutoThreadSafeAccess ts(this);
         return getFixedSlot(SCOPE_CHAIN_SLOT).toObject();
     }
 
     void setEnclosingScope(HandleObject obj);
 
     /*
      * Get or set an aliased variable contained in this scope. Unaliased
      * variables should instead access the StackFrame. Aliased variable access
@@ -247,29 +246,27 @@ class CallObject : public ScopeObject
 
     static CallObject *createForFunction(JSContext *cx, HandleObject enclosing, HandleFunction callee);
 
     static CallObject *createForFunction(JSContext *cx, AbstractFramePtr frame);
     static CallObject *createForStrictEval(JSContext *cx, AbstractFramePtr frame);
 
     /* True if this is for a strict mode eval frame. */
     bool isForEval() const {
-        AutoThreadSafeAccess ts(this);
         JS_ASSERT(getFixedSlot(CALLEE_SLOT).isObjectOrNull());
         JS_ASSERT_IF(getFixedSlot(CALLEE_SLOT).isObject(),
                      getFixedSlot(CALLEE_SLOT).toObject().is<JSFunction>());
         return getFixedSlot(CALLEE_SLOT).isNull();
     }
 
     /*
      * Returns the function for which this CallObject was created. (This may
      * only be called if !isForEval.)
      */
     JSFunction &callee() const {
-        AutoThreadSafeAccess ts(this);
         return getFixedSlot(CALLEE_SLOT).toObject().as<JSFunction>();
     }
 
     /* Get/set the aliased variable referred to by 'bi'. */
     const Value &aliasedVar(AliasedFormalIter fi) {
         return getSlot(fi.scopeSlot());
     }
 
@@ -405,17 +402,17 @@ class BlockObject : public NestedScopeOb
 
     /* Return the abstract stack depth right before entering this nested scope. */
     uint32_t stackDepth() const {
         return getReservedSlot(DEPTH_SLOT).toPrivateUint32();
     }
 
     /* Return the number of variables associated with this block. */
     uint32_t slotCount() const {
-        return propertyCountForCompilation();
+        return propertyCount();
     }
 
     /*
      * Return the local corresponding to the ith binding where i is in the
      * range [0, slotCount()) and the return local index is in the range
      * [script->nfixed, script->nfixed + script->nslots).
      */
     uint32_t slotToLocalIndex(const Bindings &bindings, uint32_t slot) {
@@ -459,19 +456,16 @@ class StaticBlockObject : public BlockOb
         return slotValue(i).isTrue();
     }
 
     /*
      * A static block object is cloned (when entering the block) iff some
      * variable of the block isAliased.
      */
     bool needsClone() {
-        // The first variable slot will always indicate whether the object has
-        // any aliased vars. Bypass slotValue() to allow testing this off thread.
-        AutoThreadSafeAccess ts(this);
         return !getFixedSlot(RESERVED_SLOTS).isFalse();
     }
 
     /* Frontend-only functions ***********************************************/
 
     /* Initialization functions for above fields. */
     void setAliased(unsigned i, bool aliased) {
         JS_ASSERT_IF(i > 0, slotValue(i-1).isBoolean());
--- a/js/src/vm/Shape.h
+++ b/js/src/vm/Shape.h
@@ -1021,23 +1021,21 @@ class Shape : public gc::BarrieredCell<S
 
         Shape &front() const {
             JS_ASSERT(!empty());
             return *cursor;
         }
 
         void popFront() {
             JS_ASSERT(!empty());
-            AutoThreadSafeAccess ts(cursor);
             cursor = cursor->parent;
         }
     };
 
     const Class *getObjectClass() const {
-        AutoThreadSafeAccess ts(base());
         return base()->clasp;
     }
     JSObject *getObjectParent() const { return base()->parent; }
     JSObject *getObjectMetadata() const { return base()->metadata; }
 
     static Shape *setObjectParent(ExclusiveContext *cx,
                                   JSObject *obj, TaggedProto proto, Shape *last);
     static Shape *setObjectMetadata(JSContext *cx,
@@ -1087,17 +1085,16 @@ class Shape : public gc::BarrieredCell<S
   public:
     /* Public bits stored in shape->flags. */
     enum {
         HAS_SHORTID     = 0x40,
         PUBLIC_FLAGS    = HAS_SHORTID
     };
 
     bool inDictionary() const {
-        AutoThreadSafeAccess ts(this);
         return (flags & IN_DICTIONARY) != 0;
     }
     unsigned getFlags() const { return flags & PUBLIC_FLAGS; }
     bool hasShortID() const { return (flags & HAS_SHORTID) != 0; }
 
     PropertyOp getter() const { return base()->rawGetter; }
     bool hasDefaultGetter() const {return !base()->rawGetter; }
     PropertyOp getterOp() const { JS_ASSERT(!hasGetterValue()); return base()->rawGetter; }
@@ -1153,30 +1150,24 @@ class Shape : public gc::BarrieredCell<S
     }
 
     bool get(JSContext* cx, HandleObject receiver, JSObject *obj, JSObject *pobj, MutableHandleValue vp);
     bool set(JSContext* cx, HandleObject obj, HandleObject receiver, bool strict, MutableHandleValue vp);
 
     BaseShape *base() const { return base_.get(); }
 
     bool hasSlot() const {
-        AutoThreadSafeAccess ts(this);
         return (attrs & JSPROP_SHARED) == 0;
     }
     uint32_t slot() const { JS_ASSERT(hasSlot() && !hasMissingSlot()); return maybeSlot(); }
     uint32_t maybeSlot() const {
-        // Note: Reading a shape's slot off thread can race against main thread
-        // updates to the number of linear searches on the shape, which is
-        // stored in the same slotInfo field. We tolerate this.
-        AutoThreadSafeAccess ts(this);
         return slotInfo & SLOT_MASK;
     }
 
     bool isEmptyShape() const {
-        AutoThreadSafeAccess ts(this);
         JS_ASSERT_IF(JSID_IS_EMPTY(propid_), hasMissingSlot());
         return JSID_IS_EMPTY(propid_);
     }
 
     uint32_t slotSpan(const Class *clasp) const {
         JS_ASSERT(!inDictionary());
         uint32_t free = JSSLOT_FREE(clasp);
         return hasMissingSlot() ? free : Max(free, maybeSlot() + 1);
@@ -1188,18 +1179,16 @@ class Shape : public gc::BarrieredCell<S
 
     void setSlot(uint32_t slot) {
         JS_ASSERT(slot <= SHAPE_INVALID_SLOT);
         slotInfo = slotInfo & ~Shape::SLOT_MASK;
         slotInfo = slotInfo | slot;
     }
 
     uint32_t numFixedSlots() const {
-        // Note: The same race applies here as in maybeSlot().
-        AutoThreadSafeAccess ts(this);
         return (slotInfo >> FIXED_SLOTS_SHIFT);
     }
 
     void setNumFixedSlots(uint32_t nfixed) {
         JS_ASSERT(nfixed < FIXED_SLOTS_MAX);
         slotInfo = slotInfo & ~FIXED_SLOTS_MASK;
         slotInfo = slotInfo | (nfixed << FIXED_SLOTS_SHIFT);
     }
@@ -1211,43 +1200,39 @@ class Shape : public gc::BarrieredCell<S
     void incrementNumLinearSearches() {
         uint32_t count = numLinearSearches();
         JS_ASSERT(count < LINEAR_SEARCHES_MAX);
         slotInfo = slotInfo & ~LINEAR_SEARCHES_MASK;
         slotInfo = slotInfo | ((count + 1) << LINEAR_SEARCHES_SHIFT);
     }
 
     const EncapsulatedId &propid() const {
-        AutoThreadSafeAccess ts(this);
         JS_ASSERT(!isEmptyShape());
         JS_ASSERT(!JSID_IS_VOID(propid_));
         return propid_;
     }
     EncapsulatedId &propidRef() { JS_ASSERT(!JSID_IS_VOID(propid_)); return propid_; }
     jsid propidRaw() const {
         // Return the actual jsid, not an internal reference.
-        AutoThreadSafeAccess ts(this);
         return propid();
     }
 
     int16_t shortid() const { JS_ASSERT(hasShortID()); return maybeShortid(); }
     int16_t maybeShortid() const { return shortid_; }
 
     /*
      * If SHORTID is set in shape->flags, we use shape->shortid rather
      * than id when calling shape's getter or setter.
      */
     inline bool getUserId(JSContext *cx, MutableHandleId idp) const;
 
     uint8_t attributes() const { return attrs; }
     bool configurable() const { return (attrs & JSPROP_PERMANENT) == 0; }
     bool enumerable() const { return (attrs & JSPROP_ENUMERATE) != 0; }
     bool writable() const {
-        // JS_ASSERT(isDataDescriptor());
-        AutoThreadSafeAccess ts(this);
         return (attrs & JSPROP_READONLY) == 0;
     }
     bool hasGetterValue() const { return attrs & JSPROP_GETTER; }
     bool hasSetterValue() const { return attrs & JSPROP_SETTER; }
 
     bool isDataDescriptor() const {
         return (attrs & (JSPROP_SETTER | JSPROP_GETTER)) == 0;
     }
@@ -1274,20 +1259,16 @@ class Shape : public gc::BarrieredCell<S
     bool shadowable() const {
         JS_ASSERT_IF(isDataDescriptor(), writable());
         return hasSlot() || (attrs & JSPROP_SHADOWABLE);
     }
 
     uint32_t entryCount() {
         if (hasTable())
             return table().entryCount;
-        return entryCountForCompilation();
-    }
-
-    uint32_t entryCountForCompilation() {
         uint32_t count = 0;
         for (Shape::Range<NoGC> r(this); !r.empty(); r.popFront())
             ++count;
         return count;
     }
 
     bool isBigEnoughForAShapeTable() {
         JS_ASSERT(!hasTable());
@@ -1644,17 +1625,16 @@ Shape::searchLinear(jsid id)
      * Non-dictionary shapes can acquire a table at any point the main thread
      * is operating on it, so other threads inspecting such shapes can't use
      * their table without racing. This function can be called from any thread
      * on any non-dictionary shape.
      */
     JS_ASSERT(!inDictionary());
 
     for (Shape *shape = this; shape; ) {
-        AutoThreadSafeAccess ts(shape);
         if (shape->propidRef() == id)
             return shape;
         shape = shape->parent;
     }
 
     return nullptr;
 }
 
--- a/js/src/vm/String.h
+++ b/js/src/vm/String.h
@@ -377,17 +377,16 @@ class JSString : public js::gc::Barriere
 
     MOZ_ALWAYS_INLINE
     bool isAtom() const {
         return (d.lengthAndFlags & ATOM_BIT);
     }
 
     MOZ_ALWAYS_INLINE
     JSAtom &asAtom() const {
-        js::AutoThreadSafeAccess ts(this);
         JS_ASSERT(isAtom());
         return *(JSAtom *)this;
     }
 
     /* Only called by the GC for dependent or undepended strings. */
 
     inline bool hasBase() const {
         JS_STATIC_ASSERT((DEPENDENT_FLAGS | JS_BIT(1)) == UNDEPENDED_FLAGS);
@@ -1010,17 +1009,16 @@ JSString::base() const
     JS_ASSERT(hasBase());
     JS_ASSERT(!d.s.u2.base->isInline());
     return d.s.u2.base;
 }
 
 inline js::PropertyName *
 JSAtom::asPropertyName()
 {
-    js::AutoThreadSafeAccess ts(this);
 #ifdef DEBUG
     uint32_t dummy;
     JS_ASSERT(!isIndex(&dummy));
 #endif
     return static_cast<js::PropertyName *>(this);
 }
 
 #endif /* vm_String_h */
--- a/js/src/vm/TypedArrayObject.cpp
+++ b/js/src/vm/TypedArrayObject.cpp
@@ -1190,18 +1190,16 @@ TypedArrayObject::isArrayIndex(jsid id, 
     }
 
     return false;
 }
 
 void
 TypedArrayObject::neuter(JSContext *cx)
 {
-    AutoLockForCompilation lock(cx);
-
     setSlot(LENGTH_SLOT, Int32Value(0));
     setSlot(BYTELENGTH_SLOT, Int32Value(0));
     setSlot(BYTEOFFSET_SLOT, Int32Value(0));
     setPrivate(nullptr);
 }
 
 bool
 TypedArrayObject::obj_lookupGeneric(JSContext *cx, HandleObject tarray, HandleId id,
--- a/js/src/vm/TypedArrayObject.h
+++ b/js/src/vm/TypedArrayObject.h
@@ -306,21 +306,19 @@ class TypedArrayObject : public ArrayBuf
 
     static Value bufferValue(TypedArrayObject *tarr) {
         return tarr->getFixedSlot(BUFFER_SLOT);
     }
     static Value byteOffsetValue(TypedArrayObject *tarr) {
         return tarr->getFixedSlot(BYTEOFFSET_SLOT);
     }
     static Value byteLengthValue(TypedArrayObject *tarr) {
-        AutoThreadSafeAccess ts(tarr);
         return tarr->getFixedSlot(BYTELENGTH_SLOT);
     }
     static Value lengthValue(TypedArrayObject *tarr) {
-        AutoThreadSafeAccess ts(tarr);
         return tarr->getFixedSlot(LENGTH_SLOT);
     }
 
     ArrayBufferObject *buffer() const {
         return &bufferValue(const_cast<TypedArrayObject*>(this)).toObject().as<ArrayBufferObject>();
     }
     uint32_t byteOffset() const {
         return byteOffsetValue(const_cast<TypedArrayObject*>(this)).toInt32();
@@ -328,21 +326,19 @@ class TypedArrayObject : public ArrayBuf
     uint32_t byteLength() const {
         return byteLengthValue(const_cast<TypedArrayObject*>(this)).toInt32();
     }
     uint32_t length() const {
         return lengthValue(const_cast<TypedArrayObject*>(this)).toInt32();
     }
 
     uint32_t type() const {
-        AutoThreadSafeAccess ts(this);
         return getFixedSlot(TYPE_SLOT).toInt32();
     }
     void *viewData() const {
-        AutoThreadSafeAccess ts(this);
         return static_cast<void*>(getPrivate(DATA_SLOT));
     }
 
     inline bool isArrayIndex(jsid id, uint32_t *ip = nullptr);
     void copyTypedArrayElement(uint32_t index, MutableHandleValue vp);
 
     void neuter(JSContext *cx);