Bug 625199 - s/JSAutoEnterCompartment/JSAutoCompartment/ and make it infallible (r=bholley)
authorLuke Wagner <luke@mozilla.com>
Tue, 21 Aug 2012 18:42:53 -0700
changeset 105296 0d61ae018d9f97407a37e327ee526fb018619f62
parent 105295 986c07b3f3e68af098d7e85fd507a7d4139b4eb3
child 105297 1bed30d952cc688c1c5d7575c4bf6574aedfe570
push id55
push usershu@rfrn.org
push dateThu, 30 Aug 2012 01:33:09 +0000
reviewersbholley
bugs625199
milestone17.0a1
Bug 625199 - s/JSAutoEnterCompartment/JSAutoCompartment/ and make it infallible (r=bholley)
content/base/src/nsContentUtils.cpp
content/base/src/nsFrameMessageManager.cpp
content/base/src/nsXMLHttpRequest.cpp
content/events/src/nsEventListenerManager.cpp
content/events/src/nsEventListenerService.cpp
content/events/src/nsEventListenerService.h
content/html/content/src/nsDOMStringMap.cpp
content/xbl/src/nsXBLBinding.cpp
content/xbl/src/nsXBLProtoImplMethod.cpp
content/xbl/src/nsXBLProtoImplProperty.cpp
dom/base/nsDOMClassInfo.cpp
dom/base/nsGlobalWindow.cpp
dom/base/nsJSEnvironment.cpp
dom/base/nsLocation.cpp
dom/base/nsStructuredCloneContainer.cpp
dom/bindings/BindingUtils.cpp
dom/bindings/BindingUtils.h
dom/bindings/Codegen.py
dom/bindings/TypedArray.h
dom/bluetooth/BluetoothUtils.cpp
dom/file/ArchiveRequest.cpp
dom/file/FileRequest.cpp
dom/indexedDB/IDBFactory.cpp
dom/indexedDB/IDBRequest.cpp
dom/plugins/base/nsJSNPRuntime.cpp
dom/sms/src/SmsManager.cpp
dom/sms/src/SmsRequest.cpp
dom/src/json/nsJSON.cpp
dom/system/gonk/SystemWorkerManager.cpp
dom/telephony/Telephony.cpp
dom/workers/WorkerPrivate.cpp
dom/workers/WorkerScope.cpp
extensions/pref/autoconfig/src/nsJSConfigTriggers.cpp
ipc/testshell/TestShellParent.cpp
ipc/testshell/XPCShellEnvironment.cpp
js/ductwork/debugger/JSDebugger.cpp
js/jsd/jsd_xpc.cpp
js/src/ctypes/CTypes.cpp
js/src/jsapi-tests/testBug604087.cpp
js/src/jsapi-tests/testCallNonGenericMethodOnProxy.cpp
js/src/jsapi-tests/testChromeBuffer.cpp
js/src/jsapi-tests/testCloneScript.cpp
js/src/jsapi-tests/testContexts.cpp
js/src/jsapi-tests/testDebugger.cpp
js/src/jsapi-tests/testOriginPrincipals.cpp
js/src/jsapi-tests/tests.cpp
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jsclone.cpp
js/src/jscntxt.cpp
js/src/jscompartment.h
js/src/jsdbgapi.cpp
js/src/jsobj.cpp
js/src/jsopcode.cpp
js/src/jswrapper.cpp
js/src/shell/js.cpp
js/src/vm/Debugger.cpp
js/src/vm/Debugger.h
js/src/vm/Stack.cpp
js/xpconnect/loader/mozJSComponentLoader.cpp
js/xpconnect/loader/mozJSComponentLoader.h
js/xpconnect/loader/mozJSSubScriptLoader.cpp
js/xpconnect/shell/xpcshell.cpp
js/xpconnect/src/XPCComponents.cpp
js/xpconnect/src/XPCConvert.cpp
js/xpconnect/src/XPCDebug.cpp
js/xpconnect/src/XPCJSRuntime.cpp
js/xpconnect/src/XPCWrappedJSClass.cpp
js/xpconnect/src/XPCWrappedNative.cpp
js/xpconnect/src/XPCWrappedNativeJSOps.cpp
js/xpconnect/src/XPCWrappedNativeScope.cpp
js/xpconnect/src/dictionary_helper_gen.py
js/xpconnect/src/dombindings.cpp
js/xpconnect/src/nsXPConnect.cpp
js/xpconnect/src/xpcprivate.h
js/xpconnect/wrappers/AccessCheck.cpp
js/xpconnect/wrappers/AccessCheck.h
js/xpconnect/wrappers/ChromeObjectWrapper.cpp
js/xpconnect/wrappers/WrapperFactory.cpp
js/xpconnect/wrappers/XrayWrapper.cpp
security/manager/ssl/src/nsCrypto.cpp
toolkit/components/alerts/mac/ObserverPair.h
tools/profiler/TableTicker.cpp
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -1770,20 +1770,17 @@ nsContentUtils::GetWindowFromCaller()
 nsIDOMDocument *
 nsContentUtils::GetDocumentFromCaller()
 {
   JSContext *cx = nullptr;
   JSObject *obj = nullptr;
   sXPConnect->GetCaller(&cx, &obj);
   NS_ASSERTION(cx && obj, "Caller ensures something is running");
 
-  JSAutoEnterCompartment ac;
-  if (!ac.enter(cx, obj)) {
-    return nullptr;
-  }
+  JSAutoCompartment ac(cx, obj);
 
   nsCOMPtr<nsPIDOMWindow> win =
     do_QueryInterface(nsJSUtils::GetStaticScriptGlobal(cx, obj));
   if (!win) {
     return nullptr;
   }
 
   return win->GetExtantDocument();
@@ -6882,20 +6879,17 @@ nsContentUtils::JSArrayToAtomArray(JSCon
                                    nsCOMArray<nsIAtom>& aRetVal)
 {
   JSAutoRequest ar(aCx);
   if (!aJSArray.isObject()) {
     return NS_ERROR_ILLEGAL_VALUE;
   }
   
   JSObject* obj = &aJSArray.toObject();
-  JSAutoEnterCompartment ac;
-  if (!ac.enter(aCx, obj)) {
-    return NS_ERROR_ILLEGAL_VALUE;
-  }
+  JSAutoCompartment ac(aCx, obj);
   
   uint32_t length;
   if (!JS_IsArrayObject(aCx, obj) || !JS_GetArrayLength(aCx, obj, &length)) {
     return NS_ERROR_ILLEGAL_VALUE;
   }
 
   JSString* str = nullptr;
   JS::Anchor<JSString *> deleteProtector(str);
--- a/content/base/src/nsFrameMessageManager.cpp
+++ b/content/base/src/nsFrameMessageManager.cpp
@@ -411,20 +411,17 @@ nsFrameMessageManager::ReceiveMessage(ns
         wrappedJS->GetJSObject(&object);
         if (!object) {
           continue;
         }
         nsCxPusher pusher;
         NS_ENSURE_STATE(pusher.Push(ctx, false));
 
         JSAutoRequest ar(ctx);
-
-        JSAutoEnterCompartment ac;
-        if (!ac.enter(ctx, object))
-          return NS_ERROR_FAILURE;
+        JSAutoCompartment ac(ctx, object);
 
         // The parameter for the listener function.
         JSObject* param = JS_NewObject(ctx, NULL, NULL, NULL);
         NS_ENSURE_TRUE(param, NS_ERROR_OUT_OF_MEMORY);
 
         jsval targetv;
         nsContentUtils::WrapNative(ctx,
                                    JS_GetGlobalForObject(ctx, object),
@@ -496,22 +493,20 @@ nsFrameMessageManager::ReceiveMessage(ns
         }
 
         jsval rval = JSVAL_VOID;
 
         JS::AutoValueRooter argv(ctx);
         argv.set(OBJECT_TO_JSVAL(param));
 
         {
-          JSAutoEnterCompartment tac;
-
           JSObject* thisObject = JSVAL_TO_OBJECT(thisValue);
 
-          if (!tac.enter(ctx, thisObject) ||
-              !JS_WrapValue(ctx, argv.jsval_addr()))
+          JSAutoCompartment tac(ctx, thisObject);
+          if (!JS_WrapValue(ctx, argv.jsval_addr()))
             return NS_ERROR_UNEXPECTED;
 
           JS_CallFunctionValue(ctx, thisObject,
                                funval, 1, argv.jsval_addr(), &rval);
           if (aJSONRetVal) {
             nsString json;
             if (JS_Stringify(ctx, &rval, nullptr, JSVAL_NULL,
                              JSONCreator, &json)) {
@@ -825,18 +820,18 @@ nsFrameScriptExecutor::LoadFrameScriptIn
   if (!dataString.IsEmpty()) {
     nsContentUtils::ThreadJSContextStack()->Push(mCx);
     {
       // Need to scope JSAutoRequest to happen after Push but before Pop,
       // at least for now. See bug 584673.
       JSAutoRequest ar(mCx);
       JSObject* global = nullptr;
       mGlobal->GetJSObject(&global);
-      JSAutoEnterCompartment ac;
-      if (global && ac.enter(mCx, global)) {
+      if (global) {
+        JSAutoCompartment ac(mCx, global);
         uint32_t oldopts = JS_GetOptions(mCx);
         JS_SetOptions(mCx, oldopts | JSOPTION_NO_SCRIPT_RVAL);
 
         JSScript* script =
           JS_CompileUCScriptForPrincipals(mCx, nullptr,
                                           nsJSPrincipals::get(mPrincipal),
                                           static_cast<const jschar*>(dataString.get()),
                                           dataString.Length(),
--- a/content/base/src/nsXMLHttpRequest.cpp
+++ b/content/base/src/nsXMLHttpRequest.cpp
@@ -2660,37 +2660,37 @@ GetRequestBody(nsIVariant* aBody, nsIInp
     nsCOMPtr<nsIXHRSendable> sendable = do_QueryInterface(supports);
     if (sendable) {
       return GetRequestBody(sendable, aResult, aContentType, aCharset);
     }
 
     // ArrayBuffer?
     jsval realVal;
     nsCxPusher pusher;
-    JSAutoEnterCompartment ac;
-    JSObject* obj;
+    Maybe<JSAutoCompartment> ac;
 
     // If there's a context on the stack, we can just use it. Otherwise, we need
     // to use the safe js context (and push it into the stack, so that it's
     // visible to cx-less functions that we might call here).
     JSContext* cx = nsContentUtils::GetCurrentJSContext();
     if (!cx) {
       cx = nsContentUtils::GetSafeJSContext();
       if (!pusher.Push(cx)) {
         return NS_ERROR_FAILURE;
       }
     }
 
     nsresult rv = aBody->GetAsJSVal(&realVal);
-    if (NS_SUCCEEDED(rv) && !JSVAL_IS_PRIMITIVE(realVal) &&
-        (obj = JSVAL_TO_OBJECT(realVal)) &&
-        ac.enter(cx, obj) &&
-        (JS_IsArrayBufferObject(obj, cx))) {
-      ArrayBuffer buf(cx, obj);
-      return GetRequestBody(&buf, aResult, aContentType, aCharset);
+    if (NS_SUCCEEDED(rv) && !JSVAL_IS_PRIMITIVE(realVal)) {
+      JSObject *obj = JSVAL_TO_OBJECT(realVal);
+      ac.construct(cx, obj);
+      if (JS_IsArrayBufferObject(obj, cx)) {
+          ArrayBuffer buf(cx, obj);
+          return GetRequestBody(&buf, aResult, aContentType, aCharset);
+      }
     }
   }
   else if (dataType == nsIDataType::VTYPE_VOID ||
            dataType == nsIDataType::VTYPE_EMPTY) {
     // Makes us act as if !aBody, don't upload anything
     aContentType.AssignLiteral("text/plain");
     aCharset.AssignLiteral("UTF-8");
 
--- a/content/events/src/nsEventListenerManager.cpp
+++ b/content/events/src/nsEventListenerManager.cpp
@@ -1034,20 +1034,17 @@ nsEventListenerManager::SetJSEventListen
   JSObject *handler;
   if (JSVAL_IS_PRIMITIVE(v) ||
       !JS_ObjectIsCallable(cx, handler = JSVAL_TO_OBJECT(v))) {
     RemoveScriptEventListener(aEventName);
     return NS_OK;
   }
 
   // Now ensure that we're working in the compartment of aScope from now on.
-  JSAutoEnterCompartment ac;
-  if (!ac.enter(cx, aScope)) {
-    return NS_ERROR_UNEXPECTED;
-  }
+  JSAutoCompartment ac(cx, aScope);
 
   // Rewrap the handler into the new compartment, if needed.
   jsval tempVal = v;
   if (!JS_WrapValue(cx, &tempVal)) {
     return NS_ERROR_UNEXPECTED;
   }
   handler = &tempVal.toObject();
 
--- a/content/events/src/nsEventListenerService.cpp
+++ b/content/events/src/nsEventListenerService.cpp
@@ -62,36 +62,35 @@ nsEventListenerInfo::GetInSystemEventGro
   *aInSystemEventGroup = mInSystemEventGroup;
   return NS_OK;
 }
 
 NS_IMPL_ISUPPORTS1(nsEventListenerService, nsIEventListenerService)
 
 // Caller must root *aJSVal!
 bool
-nsEventListenerInfo::GetJSVal(JSContext* aCx, JSAutoEnterCompartment& aAc, jsval* aJSVal)
+nsEventListenerInfo::GetJSVal(JSContext* aCx, mozilla::Maybe<JSAutoCompartment>& aAc, jsval* aJSVal)
 {
   *aJSVal = JSVAL_NULL;
   nsCOMPtr<nsIXPConnectWrappedJS> wrappedJS = do_QueryInterface(mListener);
   if (wrappedJS) {
     JSObject* object = nullptr;
-    if (NS_FAILED(wrappedJS->GetJSObject(&object)) || !aAc.enter(aCx, object)) {
+    if (NS_FAILED(wrappedJS->GetJSObject(&object))) {
       return false;
     }
+    aAc.construct(aCx, object);
     *aJSVal = OBJECT_TO_JSVAL(object);
     return true;
   }
 
   nsCOMPtr<nsIJSEventListener> jsl = do_QueryInterface(mListener);
   if (jsl) {
     JSObject *handler = jsl->GetHandler();
     if (handler) {
-      if (!aAc.enter(aCx, handler)) {
-        return false;
-      }
+      aAc.construct(aCx, handler);
       *aJSVal = OBJECT_TO_JSVAL(handler);
       return true;
     }
   }
   return false;
 }
 
 NS_IMETHODIMP
@@ -102,17 +101,17 @@ nsEventListenerInfo::ToSource(nsAString&
   nsCOMPtr<nsIThreadJSContextStack> stack =
     nsContentUtils::ThreadJSContextStack();
   if (stack) {
     JSContext* cx = stack->GetSafeJSContext();
     if (cx && NS_SUCCEEDED(stack->Push(cx))) {
       {
         // Extra block to finish the auto request before calling pop
         JSAutoRequest ar(cx);
-        JSAutoEnterCompartment ac;
+        mozilla::Maybe<JSAutoCompartment> ac;
         jsval v = JSVAL_NULL;
         if (GetJSVal(cx, ac, &v)) {
           JSString* str = JS_ValueToSource(cx, v);
           if (str) {
             nsDependentJSString depStr;
             if (depStr.init(cx, str)) {
               aResult.Assign(depStr);
             }
@@ -144,17 +143,17 @@ nsEventListenerInfo::GetDebugObject(nsIS
   nsCOMPtr<nsIThreadJSContextStack> stack =
     nsContentUtils::ThreadJSContextStack();
   if (stack) {
     JSContext* cx = stack->GetSafeJSContext();
     if (cx && NS_SUCCEEDED(stack->Push(cx))) {
       {
         // Extra block to finish the auto request before calling pop
         JSAutoRequest ar(cx);
-        JSAutoEnterCompartment ac;
+        mozilla::Maybe<JSAutoCompartment> ac;
         jsval v = JSVAL_NULL;
         if (GetJSVal(cx, ac, &v)) {
           nsCOMPtr<jsdIValue> jsdValue;
           rv = jsd->WrapValue(v, getter_AddRefs(jsdValue));
           NS_ENSURE_SUCCESS(rv, rv);
           jsdValue.forget(aRetVal);
         }
       }
--- a/content/events/src/nsEventListenerService.h
+++ b/content/events/src/nsEventListenerService.h
@@ -24,17 +24,17 @@ public:
   : mType(aType), mListener(aListener), mCapturing(aCapturing),
     mAllowsUntrusted(aAllowsUntrusted),
     mInSystemEventGroup(aInSystemEventGroup) {}
   virtual ~nsEventListenerInfo() {}
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_CLASS(nsEventListenerInfo)
   NS_DECL_NSIEVENTLISTENERINFO
 protected:
-  bool GetJSVal(JSContext* aCx, JSAutoEnterCompartment& aAc, jsval* aJSVal);
+  bool GetJSVal(JSContext* aCx, mozilla::Maybe<JSAutoCompartment>& aAc, jsval* aJSVal);
 
   nsString                      mType;
   // nsReftPtr because that is what nsListenerStruct uses too.
   nsRefPtr<nsIDOMEventListener> mListener;
   bool                          mCapturing;
   bool                          mAllowsUntrusted;
   bool                          mInSystemEventGroup;
 };
--- a/content/html/content/src/nsDOMStringMap.cpp
+++ b/content/html/content/src/nsDOMStringMap.cpp
@@ -166,20 +166,17 @@ nsresult nsDOMStringMap::RemovePropInter
   NS_ENSURE_TRUE(AttrToDataProp(attr, prop), NS_OK);
 
   jsval val;
   JSContext* cx = nsContentUtils::GetCurrentJSContext();
   nsresult rv = nsContentUtils::WrapNative(cx, JS_GetGlobalForScopeChain(cx),
                                            this, &val);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  JSAutoEnterCompartment ac;
-  if (!ac.enter(cx, JSVAL_TO_OBJECT(val))) {
-    return NS_ERROR_FAILURE;
-  }
+  JSAutoCompartment ac(cx, JSVAL_TO_OBJECT(val));
 
   // Guard against infinite recursion. Prevents the stack from looking like
   // ...
   // RemoveProp
   // ...
   // RemoveDataAttr
   // ...
   // RemoveProp
--- a/content/xbl/src/nsXBLBinding.cpp
+++ b/content/xbl/src/nsXBLBinding.cpp
@@ -164,20 +164,17 @@ InstallXBLField(JSContext* cx,
   // different compartment from the callee (not to mention that this method can
   // be called with an arbitrary |this| regardless of how insane XBL is), and
   // because in this method we've entered |this|'s compartment (see in
   // Field[GS]etter where we attempt a cross-compartment call), we must enter
   // the callee's compartment to access its reserved slots.
   nsXBLPrototypeBinding* protoBinding;
   nsDependentJSString fieldName;
   {
-    JSAutoEnterCompartment ac;
-    if (!ac.enter(cx, callee)) {
-      return false;
-    }
+    JSAutoCompartment ac(cx, callee);
 
     JS::Rooted<JSObject*> xblProto(cx);
     xblProto = &js::GetFunctionNativeReserved(callee, XBLPROTO_SLOT).toObject();
 
     JS::Value name = js::GetFunctionNativeReserved(callee, FIELD_SLOT);
     JSFlatString* fieldStr = JS_ASSERT_STRING_IS_FLAT(name.toString());
     fieldName.init(fieldStr);
 
@@ -1212,20 +1209,17 @@ nsXBLBinding::ChangeDocument(nsIDocument
               // XXXbz what does that comment mean, really?  It seems to date
               // back to when there was such a thing as an <interface>, whever
               // that was...
 
               // Find the right prototype.
               JSObject* base = scriptObject;
               JSObject* proto;
               JSAutoRequest ar(cx);
-              JSAutoEnterCompartment ac;
-              if (!ac.enter(cx, scriptObject)) {
-                return;
-              }
+              JSAutoCompartment ac(cx, scriptObject);
 
               for ( ; true; base = proto) { // Will break out on null proto
                 proto = ::JS_GetPrototype(base);
                 if (!proto) {
                   break;
                 }
 
                 JSClass* clazz = ::JS_GetClass(proto);
@@ -1343,20 +1337,17 @@ nsXBLBinding::DoInitJSClass(JSContext *c
                             nsXBLPrototypeBinding* aProtoBinding,
                             JSObject** aClassObject)
 {
   // First ensure our JS class is initialized.
   nsCAutoString className(aClassName);
   JSObject* parent_proto = nullptr;  // If we have an "obj" we can set this
   JSAutoRequest ar(cx);
 
-  JSAutoEnterCompartment ac;
-  if (!ac.enter(cx, global)) {
-    return NS_ERROR_FAILURE;
-  }
+  JSAutoCompartment ac(cx, global);
 
   if (obj) {
     // Retrieve the current prototype of obj.
     parent_proto = ::JS_GetPrototype(obj);
     if (parent_proto) {
       // We need to create a unique classname based on aClassName and
       // parent_proto.  Append a space (an invalid URI character) to ensure that
       // we don't have accidental collisions with the case when parent_proto is
--- a/content/xbl/src/nsXBLProtoImplMethod.cpp
+++ b/content/xbl/src/nsXBLProtoImplMethod.cpp
@@ -113,21 +113,17 @@ nsXBLProtoImplMethod::InstallMember(nsIS
     return NS_ERROR_FAILURE;
 
   JSObject* globalObject = sgo->GetGlobalJSObject();
 
   // now we want to reevaluate our property using aContext and the script object for this window...
   if (mJSMethodObject && aTargetClassObject) {
     nsDependentString name(mName);
     JSAutoRequest ar(cx);
-    JSAutoEnterCompartment ac;
-
-    if (!ac.enter(cx, globalObject)) {
-      return NS_ERROR_UNEXPECTED;
-    }
+    JSAutoCompartment ac(cx, globalObject);
 
     JSObject * method = ::JS_CloneFunctionObject(cx, mJSMethodObject, globalObject);
     if (!method) {
       return NS_ERROR_OUT_OF_MEMORY;
     }
 
     if (!::JS_DefineUCProperty(cx, aTargetClassObject,
                                static_cast<const jschar*>(mName),
@@ -305,20 +301,17 @@ nsXBLProtoImplAnonymousMethod::Execute(n
   nsresult rv =
     nsContentUtils::WrapNative(cx, globalObject, aBoundElement, &v,
                                getter_AddRefs(wrapper));
   NS_ENSURE_SUCCESS(rv, rv);
 
   JSObject* thisObject = JSVAL_TO_OBJECT(v);
 
   JSAutoRequest ar(cx);
-  JSAutoEnterCompartment ac;
-
-  if (!ac.enter(cx, thisObject))
-    return NS_ERROR_UNEXPECTED;
+  JSAutoCompartment ac(cx, thisObject);
 
   // Clone the function object, using thisObject as the parent so "this" is in
   // the scope chain of the resulting function (for backwards compat to the
   // days when this was an event handler).
   JSObject* method = ::JS_CloneFunctionObject(cx, mJSMethodObject, thisObject);
   if (!method)
     return NS_ERROR_OUT_OF_MEMORY;
 
--- a/content/xbl/src/nsXBLProtoImplProperty.cpp
+++ b/content/xbl/src/nsXBLProtoImplProperty.cpp
@@ -150,20 +150,17 @@ nsXBLProtoImplProperty::InstallMember(ns
     return NS_ERROR_FAILURE;
 
   JSObject * globalObject = sgo->GetGlobalJSObject();
 
   // now we want to reevaluate our property using aContext and the script object for this window...
   if ((mJSGetterObject || mJSSetterObject) && aTargetClassObject) {
     JSObject * getter = nullptr;
     JSAutoRequest ar(cx);
-    JSAutoEnterCompartment ac;
-
-    if (!ac.enter(cx, globalObject))
-      return NS_ERROR_UNEXPECTED;
+    JSAutoCompartment ac(cx, globalObject);
 
     if (mJSGetterObject)
       if (!(getter = ::JS_CloneFunctionObject(cx, mJSGetterObject, globalObject)))
         return NS_ERROR_OUT_OF_MEMORY;
 
     JSObject * setter = nullptr;
     if (mJSSetterObject)
       if (!(setter = ::JS_CloneFunctionObject(cx, mJSSetterObject, globalObject)))
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -5728,21 +5728,17 @@ BaseStubConstructor(nsIWeakReference* aW
       if (!object) {
         return NS_ERROR_UNEXPECTED;
       }
 
       nsCxPusher pusher;
       NS_ENSURE_STATE(pusher.Push(cx, false));
 
       JSAutoRequest ar(cx);
-
-      JSAutoEnterCompartment ac;
-      if (!ac.enter(cx, object)) {
-        return NS_ERROR_FAILURE;
-      }
+      JSAutoCompartment ac(cx, object);
 
       JS::Value thisValue = JSVAL_VOID;
       JS::Value funval;
       if (!JS_GetProperty(cx, object, "constructor", &funval) || !funval.isObject()) {
         return NS_ERROR_UNEXPECTED;
       }
 
       // Check if the object is even callable.
@@ -6531,21 +6527,17 @@ ResolvePrototype(nsIXPConnect *aXPConnec
     primary_iid = ci_data->mProtoChainInterface;
   }
 
   nsCOMPtr<nsIInterfaceInfo> if_info;
   nsCOMPtr<nsIInterfaceInfo> parent;
   const char *class_parent_name = nullptr;
 
   if (!primary_iid->Equals(NS_GET_IID(nsISupports))) {
-    JSAutoEnterCompartment ac;
-
-    if (!ac.enter(cx, class_obj)) {
-      return NS_ERROR_FAILURE;
-    }
+    JSAutoCompartment ac(cx, class_obj);
 
     rv = DefineInterfaceConstants(cx, class_obj, primary_iid);
     NS_ENSURE_SUCCESS(rv, rv);
 
     // Special case for |IDBKeyRange| which gets funny "static" functions.
     if (primary_iid->Equals(NS_GET_IID(nsIIDBKeyRange)) &&
         !indexedDB::IDBKeyRange::DefineConstructors(cx, class_obj)) {
       return NS_ERROR_FAILURE;
@@ -6601,20 +6593,17 @@ ResolvePrototype(nsIXPConnect *aXPConnec
   }
 
   {
     JSObject *winobj = aWin->FastGetGlobalJSObject();
 
     JSObject *proto = nullptr;
 
     if (class_parent_name) {
-      JSAutoEnterCompartment ac;
-      if (!ac.enter(cx, winobj)) {
-        return NS_ERROR_UNEXPECTED;
-      }
+      JSAutoCompartment ac(cx, winobj);
 
       JS::Value val;
       if (!JS_LookupProperty(cx, winobj, CutPrefix(class_parent_name), &val)) {
         return NS_ERROR_UNEXPECTED;
       }
 
       if (val.isObject()) {
         if (!JS_LookupProperty(cx, &val.toObject(), "prototype", &val)) {
@@ -6623,49 +6612,38 @@ ResolvePrototype(nsIXPConnect *aXPConnec
 
         if (val.isObject()) {
           proto = &val.toObject();
         }
       }
     }
 
     if (dot_prototype) {
-      JSAutoEnterCompartment ac;
-      if (!ac.enter(cx, dot_prototype)) {
-        return NS_ERROR_UNEXPECTED;
-      }
-
+      JSAutoCompartment ac(cx, dot_prototype);
       JSObject *xpc_proto_proto = ::JS_GetPrototype(dot_prototype);
 
       if (proto &&
           (!xpc_proto_proto ||
            JS_GetClass(xpc_proto_proto) == sObjectClass)) {
         if (!JS_WrapObject(cx, &proto) ||
             !JS_SetPrototype(cx, dot_prototype, proto)) {
           return NS_ERROR_UNEXPECTED;
         }
       }
     } else {
-      JSAutoEnterCompartment ac;
-      if (!ac.enter(cx, winobj)) {
-        return NS_ERROR_UNEXPECTED;
-      }
-
+      JSAutoCompartment ac(cx, winobj);
       dot_prototype = ::JS_NewObject(cx, &sDOMConstructorProtoClass, proto,
                                      winobj);
       NS_ENSURE_TRUE(dot_prototype, NS_ERROR_OUT_OF_MEMORY);
     }
   }
 
   v = OBJECT_TO_JSVAL(dot_prototype);
 
-  JSAutoEnterCompartment ac;
-  if (!ac.enter(cx, class_obj)) {
-    return NS_ERROR_UNEXPECTED;
-  }
+  JSAutoCompartment ac(cx, class_obj);
 
   // Per ECMA, the prototype property is {DontEnum, DontDelete, ReadOnly}
   if (!JS_WrapValue(cx, &v) ||
       !JS_DefineProperty(cx, class_obj, "prototype", v, nullptr, nullptr,
                          JSPROP_PERMANENT | JSPROP_READONLY)) {
     return NS_ERROR_UNEXPECTED;
   }
 
@@ -7089,28 +7067,26 @@ nsWindowSH::NewResolve(nsIXPConnectWrapp
   // window's own context (not on some other window-caller's
   // context).
   if (!ObjectIsNativeWrapper(cx, obj)) {
     JSBool did_resolve = JS_FALSE;
     JSBool ok = JS_TRUE;
     JS::Value exn = JSVAL_VOID;
 
     {
-      JSAutoEnterCompartment ac;
+      Maybe<JSAutoCompartment> ac;
 
       JSContext* my_cx;
       if (!my_context) {
         my_cx = cx;
       } else {
         my_cx = my_context->GetNativeContext();
 
         if (my_cx != cx) {
-          if (!ac.enter(my_cx, obj)) {
-            return NS_ERROR_UNEXPECTED;
-          }
+          ac.construct(my_cx, obj);
         }
       }
 
       JSAutoRequest transfer(my_cx);
 
       // Don't resolve standard classes on XPCNativeWrapper etc, only
       // resolve them if we're resolving on the real global object.
       ok = JS_ResolveStandardClass(my_cx, obj, id, &did_resolve);
@@ -8328,23 +8304,17 @@ nsNamedArraySH::NewResolve(nsIXPConnectW
       JSObject *realObj;
 
       if (wrapper) {
         wrapper->GetJSObject(&realObj);
       } else {
         realObj = obj;
       }
 
-      JSAutoEnterCompartment ac;
-
-      if (!ac.enter(cx, realObj)) {
-        *_retval = false;
-        return NS_ERROR_FAILURE;
-      }
-
+      JSAutoCompartment ac(cx, realObj);
       JSObject *proto = ::JS_GetPrototype(realObj);
 
       if (proto) {
         JSBool hasProp;
         if (!::JS_HasPropertyById(cx, proto, id, &hasProp)) {
           *_retval = false;
           return NS_ERROR_FAILURE;
         }
@@ -9705,21 +9675,17 @@ nsHTMLPluginObjElementSH::SetupProtoChai
                "Shouldn't have gotten in here");
 
   nsCxPusher cxPusher;
   if (!cxPusher.Push(cx)) {
     return NS_OK;
   }
 
   JSAutoRequest ar(cx);
-
-  JSAutoEnterCompartment ac;
-  if (!ac.enter(cx, obj)) {
-    return NS_ERROR_UNEXPECTED;
-  }
+  JSAutoCompartment ac(cx, obj);
 
   nsRefPtr<nsNPAPIPluginInstance> pi;
   nsresult rv = GetPluginInstanceIfSafe(wrapper, obj, getter_AddRefs(pi));
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (!pi) {
     // No plugin around for this object.
 
@@ -9955,20 +9921,17 @@ nsHTMLPluginObjElementSH::GetPluginJSObj
   *plugin_obj = nullptr;
   *plugin_proto = nullptr;
 
   JSAutoRequest ar(cx);
 
   // NB: We need an AutoEnterCompartment because we can be called from
   // nsObjectFrame when the plugin loads after the JS object for our content
   // node has been created.
-  JSAutoEnterCompartment ac;
-  if (!ac.enter(cx, obj)) {
-    return NS_ERROR_UNEXPECTED;
-  }
+  JSAutoCompartment ac(cx, obj);
 
   if (plugin_inst) {
     plugin_inst->GetJSObject(cx, plugin_obj);
     if (*plugin_obj) {
       *plugin_proto = ::JS_GetPrototype(*plugin_obj);
     }
   }
 
@@ -10298,21 +10261,17 @@ nsStorage2SH::NewResolve(nsIXPConnectWra
 {
   if (ObjectIsNativeWrapper(cx, obj)) {
     return NS_OK;
   }
 
   JSObject *realObj;
   wrapper->GetJSObject(&realObj);
 
-  JSAutoEnterCompartment ac;
-  if (!ac.enter(cx, realObj)) {
-    *_retval = false;
-    return NS_ERROR_FAILURE;
-  }
+  JSAutoCompartment ac(cx, realObj);
 
   // First check to see if the property is defined on our prototype,
   // after converting id to a string if it's an integer.
 
   JSString *jsstr = IdToString(cx, id);
   if (!jsstr) {
     return NS_OK;
   }
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -620,21 +620,17 @@ nsOuterWindowProxy::finalize(JSFreeOp *f
 }
 
 nsOuterWindowProxy
 nsOuterWindowProxy::singleton;
 
 static JSObject*
 NewOuterWindowProxy(JSContext *cx, JSObject *parent)
 {
-  JSAutoEnterCompartment ac;
-  if (!ac.enter(cx, parent)) {
-    return nullptr;
-  }
-
+  JSAutoCompartment ac(cx, parent);
   JSObject *obj = js::Wrapper::New(cx, parent, js::GetObjectProto(parent), parent,
                                    &nsOuterWindowProxy::singleton);
   NS_ASSERTION(js::GetObjectClass(obj)->ext.innerObject, "bad class");
   return obj;
 }
 
 //*****************************************************************************
 //***    nsGlobalWindow: Object Management
@@ -1983,21 +1979,17 @@ nsGlobalWindow::SetNewDocument(nsIDocume
 
       nsIScriptGlobalObject *global = static_cast<nsIScriptGlobalObject*>(this);
       js::SetProxyExtra(outerObject, 0, js::PrivateValue(global));
 
       mJSObject = outerObject;
       SetWrapper(mJSObject);
 
       {
-        JSAutoEnterCompartment ac;
-        if (!ac.enter(cx, mJSObject)) {
-          NS_ERROR("unable to enter a compartment");
-          return NS_ERROR_FAILURE;
-        }
+        JSAutoCompartment ac(cx, mJSObject);
 
         JS_SetParent(cx, mJSObject, newInnerWindow->mJSObject);
 
         SetOuterObject(cx, mJSObject);
 
         JSCompartment *compartment = js::GetObjectCompartment(mJSObject);
         xpc::CompartmentPrivate *priv =
           static_cast<xpc::CompartmentPrivate*>(JS_GetCompartmentPrivate(compartment));
@@ -2005,21 +1997,17 @@ nsGlobalWindow::SetNewDocument(nsIDocume
           NS_ASSERTION(!JS_IsExceptionPending(cx),
                        "We might overwrite a pending exception!");
           priv->waiverWrapperMap->Reparent(cx, newInnerWindow->mJSObject);
         }
       }
     }
 
     // Enter the new global's compartment.
-    JSAutoEnterCompartment ac;
-    if (!ac.enter(cx, mJSObject)) {
-      NS_ERROR("unable to enter a compartment");
-      return NS_ERROR_FAILURE;
-    }
+    JSAutoCompartment ac(cx, mJSObject);
 
     // If we created a new inner window above, we need to do the last little bit
     // of initialization now that the dust has settled.
     if (createdInnerWindow) {
       nsIXPConnect *xpc = nsContentUtils::XPConnect();
       nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
       nsresult rv = xpc->GetWrappedNativeOfJSObject(cx, newInnerWindow->mJSObject,
                                                     getter_AddRefs(wrapper));
@@ -2035,21 +2023,17 @@ nsGlobalWindow::SetNewDocument(nsIDocume
                              JS_PropertyStub, JS_StrictPropertyStub,
                              JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT)) {
         NS_ERROR("can't create the 'window' property");
         return NS_ERROR_FAILURE;
       }
     }
   }
 
-  JSAutoEnterCompartment ac;
-  if (!ac.enter(cx, mJSObject)) {
-    NS_ERROR("unable to enter a compartment");
-    return NS_ERROR_FAILURE;
-  }
+  JSAutoCompartment ac(cx, mJSObject);
 
   if (!aState && !reUseInnerWindow) {
     // Loading a new page and creating a new inner window, *not*
     // restoring from session history.
 
     // Now that both the the inner and outer windows are initialized
     // let the script context do its magic to hook them together.
 #ifdef DEBUG
@@ -6005,20 +5989,17 @@ nsGlobalWindow::CallerInnerWindow()
   JSContext *cx = nsContentUtils::GetCurrentJSContext();
   if (!cx) {
     NS_ERROR("Please don't call this method from C++!");
 
     return nullptr;
   }
 
   JSObject *scope = CallerGlobal();
-
-  JSAutoEnterCompartment ac;
-  if (!ac.enter(cx, scope))
-    return nullptr;
+  JSAutoCompartment ac(cx, scope);
 
   nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
   nsContentUtils::XPConnect()->
     GetWrappedNativeOfJSObject(cx, scope, getter_AddRefs(wrapper));
   if (!wrapper)
     return nullptr;
 
   // The calling window must be holding a reference, so we can just return a
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -1284,22 +1284,17 @@ nsJSContext::EvaluateStringWithValue(con
   nsJSContext::TerminationFuncHolder holder(this);
 
   // SecurityManager said "ok", but don't compile if aVersion is unknown.
   // Since the caller is responsible for parsing the version strings, we just
   // check it isn't JSVERSION_UNKNOWN.
   if (ok && ((JSVersion)aVersion) != JSVERSION_UNKNOWN) {
 
     XPCAutoRequest ar(mContext);
-
-    JSAutoEnterCompartment ac;
-    if (!ac.enter(mContext, aScopeObject)) {
-      stack->Pop(nullptr);
-      return NS_ERROR_FAILURE;
-    }
+    JSAutoCompartment ac(mContext, aScopeObject);
 
     ++mExecuteDepth;
 
     ok = ::JS_EvaluateUCScriptForPrincipalsVersion(mContext,
                                                    aScopeObject,
                                                    nsJSPrincipals::get(principal),
                                                    static_cast<const jschar*>(PromiseFlatString(aScript).get()),
                                                    aScript.Length(),
@@ -1488,21 +1483,17 @@ nsJSContext::EvaluateString(const nsAStr
 
   ++mExecuteDepth;
 
   // SecurityManager said "ok", but don't compile if aVersion is unknown.
   // Since the caller is responsible for parsing the version strings, we just
   // check it isn't JSVERSION_UNKNOWN.
   if (ok && JSVersion(aVersion) != JSVERSION_UNKNOWN) {
     XPCAutoRequest ar(mContext);
-    JSAutoEnterCompartment ac;
-    if (!ac.enter(mContext, aScopeObject)) {
-      stack->Pop(nullptr);
-      return NS_ERROR_FAILURE;
-    }
+    JSAutoCompartment ac(mContext, aScopeObject);
 
     ok = JS_EvaluateUCScriptForPrincipalsVersionOrigin(
       mContext, aScopeObject,
       nsJSPrincipals::get(principal), nsJSPrincipals::get(aOriginPrincipal),
       static_cast<const jschar*>(PromiseFlatString(aScript).get()),
       aScript.Length(), aURL, aLineNo, vp, JSVersion(aVersion));
 
     if (!ok) {
@@ -1512,20 +1503,17 @@ nsJSContext::EvaluateString(const nsAStr
 
       ReportPendingException();
     }
   }
 
   // If all went well, convert val to a string if one is wanted.
   if (ok) {
     XPCAutoRequest ar(mContext);
-    JSAutoEnterCompartment ac;
-    if (!ac.enter(mContext, aScopeObject)) {
-      stack->Pop(nullptr);
-    }
+    JSAutoCompartment ac(mContext, aScopeObject);
     rv = JSValueToAString(mContext, val, aRetValue, aIsUndefined);
   }
   else {
     if (aIsUndefined) {
       *aIsUndefined = true;
     }
 
     if (aRetValue) {
@@ -1900,19 +1888,18 @@ nsJSContext::CallEventHandler(nsISupport
 
   if (NS_SUCCEEDED(rv)) {
     // Convert args to jsvals.
     uint32_t argc = 0;
     jsval *argv = nullptr;
 
     JSObject *funobj = aHandler;
     jsval funval = OBJECT_TO_JSVAL(funobj);
-    JSAutoEnterCompartment ac;
-    if (!ac.enter(mContext, funobj) ||
-        !JS_WrapObject(mContext, &target)) {
+    JSAutoCompartment ac(mContext, funobj);
+    if (!JS_WrapObject(mContext, &target)) {
       ReportPendingException();
       return NS_ERROR_FAILURE;
     }
 
     Maybe<nsRootedJSValueArray> tempStorage;
 
     // Use |target| as the scope for wrapping the arguments, since aScope is
     // the safe scope in many cases, which isn't very useful.  Wrapping aTarget
@@ -1977,31 +1964,24 @@ nsJSContext::BindCompiledEventHandler(ns
 
   // Get the jsobject associated with this target
   JSObject *target = nullptr;
   nsresult rv = JSObjectFromInterface(aTarget, aScope, &target);
   NS_ENSURE_SUCCESS(rv, rv);
 
 #ifdef DEBUG
   {
-    JSAutoEnterCompartment ac;
-    if (!ac.enter(mContext, aHandler)) {
-      return NS_ERROR_FAILURE;
-    }
-
+    JSAutoCompartment ac(mContext, aHandler);
     NS_ASSERTION(JS_TypeOfValue(mContext,
                                 OBJECT_TO_JSVAL(aHandler)) == JSTYPE_FUNCTION,
                  "Event handler object not a function");
   }
 #endif
 
-  JSAutoEnterCompartment ac;
-  if (!ac.enter(mContext, target)) {
-    return NS_ERROR_FAILURE;
-  }
+  JSAutoCompartment ac(mContext, target);
 
   JSObject* funobj;
   // Make sure the handler function is parented by its event target object
   if (aHandler) {
     funobj = JS_CloneFunctionObject(mContext, aHandler, target);
     if (!funobj) {
       rv = NS_ERROR_OUT_OF_MEMORY;
     }
--- a/dom/base/nsLocation.cpp
+++ b/dom/base/nsLocation.cpp
@@ -144,19 +144,17 @@ GetFrameDocument(JSContext *cx, JSStackF
 {
   if (!cx || !fp)
     return nullptr;
 
   JSObject* scope = JS_GetGlobalForFrame(fp);
   if (!scope)
     return nullptr;
 
-  JSAutoEnterCompartment ac;
-  if (!ac.enter(cx, scope))
-     return nullptr;
+  JSAutoCompartment ac(cx, scope);
 
   nsCOMPtr<nsIDOMWindow> window =
     do_QueryInterface(nsJSUtils::GetStaticScriptGlobal(cx, scope));
   if (!window)
     return nullptr;
 
   // If it's a window, get its document.
   nsCOMPtr<nsIDOMDocument> domDoc;
--- a/dom/base/nsStructuredCloneContainer.cpp
+++ b/dom/base/nsStructuredCloneContainer.cpp
@@ -46,18 +46,17 @@ nsStructuredCloneContainer::InitFromVari
   // First, try to extract a jsval from the variant |aData|.  This works only
   // if the variant implements GetAsJSVal.
   jsval jsData;
   nsresult rv = aData->GetAsJSVal(&jsData);
   NS_ENSURE_SUCCESS(rv, NS_ERROR_UNEXPECTED);
 
   // Make sure that we serialize in the right context.
   JSAutoRequest ar(aCx);
-  JSAutoEnterCompartment ac;
-  NS_ENSURE_STATE(ac.enter(aCx, JS_GetGlobalObject(aCx)));
+ JSAutoCompartment ac(aCx, JS_GetGlobalObject(aCx));
   JS_WrapValue(aCx, &jsData);
 
   nsCxPusher cxPusher;
   cxPusher.Push(aCx);
 
   uint64_t* jsBytes = nullptr;
   bool success = JS_WriteStructuredClone(aCx, jsData, &jsBytes, &mSize,
                                            nullptr, nullptr);
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -609,22 +609,20 @@ GetPropertyOnPrototype(JSContext* cx, JS
 
   return JS_ForwardGetPropertyTo(cx, proto, id, proxy, vp);
 }
 
 bool
 HasPropertyOnPrototype(JSContext* cx, JSObject* proxy, DOMProxyHandler* handler,
                        jsid id)
 {
-  JSAutoEnterCompartment ac;
+  Maybe<JSAutoCompartment> ac;
   if (xpc::WrapperFactory::IsXrayWrapper(proxy)) {
     proxy = js::UnwrapObject(proxy);
-    if (!ac.enter(cx, proxy)) {
-      return false;
-    }
+    ac.construct(cx, proxy);
   }
   MOZ_ASSERT(js::IsProxy(proxy) && js::GetProxyHandler(proxy) == handler);
 
   bool found;
   // We ignore an error from GetPropertyOnPrototype.
   return !GetPropertyOnPrototype(cx, proxy, id, &found, NULL) || found;
 }
 
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -219,27 +219,25 @@ UnwrapObject(JSContext* cx, JSObject* ob
 
 inline bool
 IsArrayLike(JSContext* cx, JSObject* obj)
 {
   MOZ_ASSERT(obj);
   // For simplicity, check for security wrappers up front.  In case we
   // have a security wrapper, don't forget to enter the compartment of
   // the underlying object after unwrapping.
-  JSAutoEnterCompartment ac;
+  Maybe<JSAutoCompartment> ac;
   if (js::IsWrapper(obj)) {
     obj = xpc::Unwrap(cx, obj, false);
     if (!obj) {
       // Let's say it's not
       return false;
     }
 
-    if (!ac.enter(cx, obj)) {
-      return false;
-    }
+    ac.construct(cx, obj);
   }
 
   // XXXbz need to detect platform objects (including listbinding
   // ones) with indexGetters here!
   return JS_IsArrayObject(cx, obj) || JS_IsTypedArrayObject(obj, cx);
 }
 
 inline bool
@@ -435,24 +433,24 @@ WrapNewBindingObject(JSContext* cx, JSOb
 template <class T>
 inline bool
 WrapNewBindingNonWrapperCachedObject(JSContext* cx, JSObject* scope, T* value,
                                      JS::Value* vp)
 {
   // We try to wrap in the compartment of the underlying object of "scope"
   JSObject* obj;
   {
-    // scope for the JSAutoEnterCompartment so that we restore the
-    // compartment before we call JS_WrapValue.
-    JSAutoEnterCompartment ac;
+    // scope for the JSAutoCompartment so that we restore the compartment
+    // before we call JS_WrapValue.
+    Maybe<JSAutoCompartment> ac;
     if (js::IsWrapper(scope)) {
       scope = xpc::Unwrap(cx, scope, false);
-      if (!scope || !ac.enter(cx, scope)) {
+      if (!scope)
         return false;
-      }
+      ac.construct(cx, scope);
     }
 
     obj = value->WrapObject(cx, scope);
   }
 
   // We can end up here in all sorts of compartments, per above.  Make
   // sure to JS_WrapValue!
   *vp = JS::ObjectValue(*obj);
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -1376,23 +1376,17 @@ class CGWrapWithCacheMethod(CGAbstractMe
 
         return """  *aTriedToWrap = true;
 
   JSObject* parent = WrapNativeParent(aCx, aScope, aObject->GetParentObject());
   if (!parent) {
     return NULL;
   }
 
-  JSAutoEnterCompartment ac;
-  if (js::GetGlobalForObjectCrossCompartment(parent) != aScope) {
-    if (!ac.enter(aCx, parent)) {
-      return NULL;
-    }
-  }
-
+  JSAutoCompartment ac(aCx, parent);
   JSObject* global = JS_GetGlobalForObject(aCx, parent);
 %s
   JSObject* proto = GetProtoObject(aCx, global, global);
   if (!proto) {
     return NULL;
   }
 
 %s
--- a/dom/bindings/TypedArray.h
+++ b/dom/bindings/TypedArray.h
@@ -61,21 +61,19 @@ struct TypedArray : public TypedArray_ba
   TypedArray(JSContext* cx, JSObject* obj) :
     TypedArray_base<T,UnboxArray>(cx, obj)
   {}
 
   static inline JSObject*
   Create(JSContext* cx, nsWrapperCache* creator, uint32_t length,
          const T* data = NULL) {
     JSObject* creatorWrapper;
-    JSAutoEnterCompartment ac;
+    Maybe<JSAutoCompartment> ac;
     if (creator && (creatorWrapper = creator->GetWrapperPreserveColor())) {
-      if (!ac.enter(cx, creatorWrapper)) {
-        return NULL;
-      }
+      ac.construct(cx, creatorWrapper);
     }
     JSObject* obj = CreateNew(cx, length);
     if (!obj) {
       return NULL;
     }
     if (data) {
       T* buf = static_cast<T*>(GetData(obj, cx));
       memcpy(buf, data, length*sizeof(T));
--- a/dom/bluetooth/BluetoothUtils.cpp
+++ b/dom/bluetooth/BluetoothUtils.cpp
@@ -16,21 +16,17 @@ nsresult
 mozilla::dom::bluetooth::StringArrayToJSArray(JSContext* aCx, JSObject* aGlobal,
                                               const nsTArray<nsString>& aSourceArray,
                                               JSObject** aResultArray)
 {
   NS_ASSERTION(aCx, "Null context!");
   NS_ASSERTION(aGlobal, "Null global!");
 
   JSAutoRequest ar(aCx);
-  JSAutoEnterCompartment ac;
-  if (!ac.enter(aCx, aGlobal)) {
-    NS_WARNING("Failed to enter compartment!");
-    return NS_ERROR_FAILURE;
-  }
+  JSAutoCompartment ac(aCx, aGlobal);
 
   JSObject* arrayObj;
 
   if (aSourceArray.IsEmpty()) {
     arrayObj = JS_NewArrayObject(aCx, 0, nullptr);
   } else {
     uint32_t valLength = aSourceArray.Length();
     mozilla::ScopedDeleteArray<jsval> valArray(new jsval[valLength]);
@@ -66,21 +62,17 @@ nsresult
 mozilla::dom::bluetooth::BluetoothDeviceArrayToJSArray(JSContext* aCx, JSObject* aGlobal,
                                                        const nsTArray<nsRefPtr<BluetoothDevice> >& aSourceArray,
                                                        JSObject** aResultArray)
 {
   NS_ASSERTION(aCx, "Null context!");
   NS_ASSERTION(aGlobal, "Null global!");
 
   JSAutoRequest ar(aCx);
-  JSAutoEnterCompartment ac;
-  if (!ac.enter(aCx, aGlobal)) {
-    NS_WARNING("Failed to enter compartment!");
-    return NS_ERROR_FAILURE;
-  }
+  JSAutoCompartment ac(aCx, aGlobal);
 
   JSObject* arrayObj;
 
   if (aSourceArray.IsEmpty()) {
     arrayObj = JS_NewArrayObject(aCx, 0, nullptr);
   } else {
     uint32_t valLength = aSourceArray.Length();
     mozilla::ScopedDeleteArray<jsval> valArray(new jsval[valLength]);
--- a/dom/file/ArchiveRequest.cpp
+++ b/dom/file/ArchiveRequest.cpp
@@ -124,34 +124,30 @@ ArchiveRequest::ReaderReady(nsTArray<nsC
 
   JSContext* cx = sc->GetNativeContext();
   NS_ASSERTION(cx, "Failed to get a context!");
 
   JSObject* global = sc->GetNativeGlobal();
   NS_ASSERTION(global, "Failed to get global object!");
 
   JSAutoRequest ar(cx);
-  JSAutoEnterCompartment ac;
-  if (ac.enter(cx, global)) {
-    switch (mOperation) {
-      case GetFilenames:
-        rv = GetFilenamesResult(cx, &result, aFileList);
-        break;
+  JSAutoCompartment ac(cx, global);
+
+  switch (mOperation) {
+    case GetFilenames:
+      rv = GetFilenamesResult(cx, &result, aFileList);
+      break;
 
-      case GetFile:
-        rv = GetFileResult(cx, &result, aFileList);
-        break;
-    }
+    case GetFile:
+      rv = GetFileResult(cx, &result, aFileList);
+      break;
+  }
 
-    if (NS_FAILED(rv)) {
-      NS_WARNING("Get*Result failed!");
-    }
-  } else {
-    NS_WARNING("Failed to enter correct compartment!");
-    rv = NS_ERROR_FAILURE;
+  if (NS_FAILED(rv)) {
+    NS_WARNING("Get*Result failed!");
   }
 
   if (NS_SUCCEEDED(rv)) {
     FireSuccess(result);
   }
   else {
     FireError(rv);
   }
--- a/dom/file/FileRequest.cpp
+++ b/dom/file/FileRequest.cpp
@@ -75,26 +75,21 @@ FileRequest::NotifyHelperCompleted(FileH
 
   JSContext* cx = sc->GetNativeContext();
   NS_ASSERTION(cx, "Failed to get a context!");
 
   JSObject* global = sc->GetNativeGlobal();
   NS_ASSERTION(global, "Failed to get global object!");
 
   JSAutoRequest ar(cx);
-  JSAutoEnterCompartment ac;
-  if (ac.enter(cx, global)) {
-    rv = aFileHelper->GetSuccessResult(cx, &result);
-    if (NS_FAILED(rv)) {
-      NS_WARNING("GetSuccessResult failed!");
-    }
-  }
-  else {
-    NS_WARNING("Failed to enter correct compartment!");
-    rv = NS_ERROR_DOM_FILEHANDLE_UNKNOWN_ERR;
+  JSAutoCompartment ac(cx, global);
+
+  rv = aFileHelper->GetSuccessResult(cx, &result);
+  if (NS_FAILED(rv)) {
+    NS_WARNING("GetSuccessResult failed!");
   }
 
   if (NS_SUCCEEDED(rv)) {
     FireSuccess(result);
   }
   else {
     FireError(rv);
   }
--- a/dom/indexedDB/IDBFactory.cpp
+++ b/dom/indexedDB/IDBFactory.cpp
@@ -233,21 +233,17 @@ IDBFactory::Create(ContentParent* aConte
   JSObject* global;
   rv = globalHolder->GetJSObject(&global);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // The CreateSandbox call returns a proxy to the actual sandbox object. We
   // don't need a proxy here.
   global = JS_UnwrapObject(global);
 
-  JSAutoEnterCompartment ac;
-  if (!ac.enter(cx, global)) {
-    NS_WARNING("Failed to enter compartment!");
-    return NS_ERROR_FAILURE;
-  }
+  JSAutoCompartment ac(cx, global);
 
   nsRefPtr<IDBFactory> factory;
   rv = Create(cx, global, aContentParent, getter_AddRefs(factory));
   NS_ENSURE_SUCCESS(rv, rv);
 
   NS_HOLD_JS_OBJECTS(factory, IDBFactory);
   factory->mRootedOwningObject = true;
 
--- a/dom/indexedDB/IDBRequest.cpp
+++ b/dom/indexedDB/IDBRequest.cpp
@@ -104,28 +104,22 @@ IDBRequest::NotifyHelperCompleted(Helper
     SetError(rv);
     return rv;
   }
 
   JSObject* global = GetParentObject();
   NS_ASSERTION(global, "This should never be null!");
 
   JSAutoRequest ar(cx);
-  JSAutoEnterCompartment ac;
-  if (ac.enter(cx, global)) {
-    AssertIsRooted();
+  JSAutoCompartment ac(cx, global);
+  AssertIsRooted();
 
-    rv = aHelper->GetSuccessResult(cx, &mResultVal);
-    if (NS_FAILED(rv)) {
-      NS_WARNING("GetSuccessResult failed!");
-    }
-  }
-  else {
-    NS_WARNING("Failed to enter correct compartment!");
-    rv = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
+  rv = aHelper->GetSuccessResult(cx, &mResultVal);
+  if (NS_FAILED(rv)) {
+    NS_WARNING("GetSuccessResult failed!");
   }
 
   if (NS_SUCCEEDED(rv)) {
     mError = nullptr;
   }
   else {
     SetError(rv);
     mResultVal = JSVAL_VOID;
--- a/dom/plugins/base/nsJSNPRuntime.cpp
+++ b/dom/plugins/base/nsJSNPRuntime.cpp
@@ -619,20 +619,17 @@ nsJSObjWrapper::NP_HasMethod(NPObject *n
 
     return false;
   }
 
   nsJSObjWrapper *npjsobj = (nsJSObjWrapper *)npobj;
 
   AutoCXPusher pusher(cx);
   JSAutoRequest ar(cx);
-  JSAutoEnterCompartment ac;
-
-  if (!ac.enter(cx, npjsobj->mJSObj))
-    return false;
+  JSAutoCompartment ac(cx, npjsobj->mJSObj);
 
   AutoJSExceptionReporter reporter(cx);
 
   jsval v;
   JSBool ok = GetProperty(cx, npjsobj->mJSObj, id, &v);
 
   return ok && !JSVAL_IS_PRIMITIVE(v) &&
     ::JS_ObjectIsFunction(cx, JSVAL_TO_OBJECT(v));
@@ -658,20 +655,17 @@ doInvoke(NPObject *npobj, NPIdentifier m
   // Initialize *result
   VOID_TO_NPVARIANT(*result);
 
   nsJSObjWrapper *npjsobj = (nsJSObjWrapper *)npobj;
   jsval fv;
 
   AutoCXPusher pusher(cx);
   JSAutoRequest ar(cx);
-  JSAutoEnterCompartment ac;
-
-  if (!ac.enter(cx, npjsobj->mJSObj))
-    return false;
+  JSAutoCompartment ac(cx, npjsobj->mJSObj);
 
   AutoJSExceptionReporter reporter(cx);
 
   if (method != NPIdentifier_VOID) {
     if (!GetProperty(cx, npjsobj->mJSObj, method, &fv) ||
         ::JS_TypeOfValue(cx, fv) != JSTYPE_FUNCTION) {
       return false;
     }
@@ -773,20 +767,17 @@ nsJSObjWrapper::NP_HasProperty(NPObject 
   }
 
   nsJSObjWrapper *npjsobj = (nsJSObjWrapper *)npobj;
   JSBool found, ok = JS_FALSE;
 
   AutoCXPusher pusher(cx);
   JSAutoRequest ar(cx);
   AutoJSExceptionReporter reporter(cx);
-  JSAutoEnterCompartment ac;
-
-  if (!ac.enter(cx, npjsobj->mJSObj))
-    return false;
+  JSAutoCompartment ac(cx, npjsobj->mJSObj);
 
   NS_ASSERTION(NPIdentifierIsInt(id) || NPIdentifierIsString(id),
                "id must be either string or int!\n");
   ok = ::JS_HasPropertyById(cx, npjsobj->mJSObj, NPIdentifierToJSId(id), &found);
   return ok && found;
 }
 
 // static
@@ -808,20 +799,17 @@ nsJSObjWrapper::NP_GetProperty(NPObject 
     return false;
   }
 
   nsJSObjWrapper *npjsobj = (nsJSObjWrapper *)npobj;
 
   AutoCXPusher pusher(cx);
   JSAutoRequest ar(cx);
   AutoJSExceptionReporter reporter(cx);
-  JSAutoEnterCompartment ac;
-
-  if (!ac.enter(cx, npjsobj->mJSObj))
-    return false;
+  JSAutoCompartment ac(cx, npjsobj->mJSObj);
 
   jsval v;
   return (GetProperty(cx, npjsobj->mJSObj, id, &v) &&
           JSValToNPVariant(npp, cx, v, result));
 }
 
 // static
 bool
@@ -843,20 +831,17 @@ nsJSObjWrapper::NP_SetProperty(NPObject 
   }
 
   nsJSObjWrapper *npjsobj = (nsJSObjWrapper *)npobj;
   JSBool ok = JS_FALSE;
 
   AutoCXPusher pusher(cx);
   JSAutoRequest ar(cx);
   AutoJSExceptionReporter reporter(cx);
-  JSAutoEnterCompartment ac;
-
-  if (!ac.enter(cx, npjsobj->mJSObj))
-    return false;
+  JSAutoCompartment ac(cx, npjsobj->mJSObj);
 
   jsval v = NPVariantToJSVal(npp, cx, value);
   JS::AutoValueRooter tvr(cx, v);
 
   NS_ASSERTION(NPIdentifierIsInt(id) || NPIdentifierIsString(id),
                "id must be either string or int!\n");
   ok = ::JS_SetPropertyById(cx, npjsobj->mJSObj, NPIdentifierToJSId(id), &v);
 
@@ -885,20 +870,17 @@ nsJSObjWrapper::NP_RemoveProperty(NPObje
 
   nsJSObjWrapper *npjsobj = (nsJSObjWrapper *)npobj;
   JSBool ok = JS_FALSE;
 
   AutoCXPusher pusher(cx);
   JSAutoRequest ar(cx);
   AutoJSExceptionReporter reporter(cx);
   jsval deleted = JSVAL_FALSE;
-  JSAutoEnterCompartment ac;
-
-  if (!ac.enter(cx, npjsobj->mJSObj))
-    return false;
+  JSAutoCompartment ac(cx, npjsobj->mJSObj);
 
   NS_ASSERTION(NPIdentifierIsInt(id) || NPIdentifierIsString(id),
                "id must be either string or int!\n");
   ok = ::JS_DeletePropertyById2(cx, npjsobj->mJSObj, NPIdentifierToJSId(id), &deleted);
   if (ok && deleted == JSVAL_TRUE) {
     // FIXME: See bug 425823, we shouldn't need to do this, and once
     // that bug is fixed we can remove this code.
 
@@ -940,20 +922,17 @@ nsJSObjWrapper::NP_Enumerate(NPObject *n
     return false;
   }
 
   nsJSObjWrapper *npjsobj = (nsJSObjWrapper *)npobj;
 
   AutoCXPusher pusher(cx);
   JSAutoRequest ar(cx);
   AutoJSExceptionReporter reporter(cx);
-  JSAutoEnterCompartment ac;
-
-  if (!ac.enter(cx, npjsobj->mJSObj))
-    return false;
+  JSAutoCompartment ac(cx, npjsobj->mJSObj);
 
   JS::AutoIdArray ida(cx, JS_Enumerate(cx, npjsobj->mJSObj));
   if (!ida) {
     return false;
   }
 
   *count = ida.length();
   *idarray = (NPIdentifier *)PR_Malloc(*count * sizeof(NPIdentifier));
@@ -2060,21 +2039,19 @@ nsJSNPRuntime::OnPluginDestroy(NPP npp)
                                       getter_AddRefs(holder));
   if (!holder) {
     return;
   }
 
   JSObject *obj, *proto;
   holder->GetJSObject(&obj);
 
-  JSAutoEnterCompartment ac;
-
-  if (obj && !ac.enter(cx, obj)) {
-    // Failure to enter compartment, nothing more we can do then.
-    return;
+  Maybe<JSAutoCompartment> ac;
+  if (obj) {
+    ac.construct(cx, obj);
   }
 
   // Loop over the DOM element's JS object prototype chain and remove
   // all JS objects of the class sNPObjectJSWrapperClass (there should
   // be only one, but remove all instances found in case the page put
   // more than one of the plugin's scriptable objects on the prototype
   // chain).
   while (obj && (proto = ::JS_GetPrototype(obj))) {
--- a/dom/sms/src/SmsManager.cpp
+++ b/dom/sms/src/SmsManager.cpp
@@ -190,21 +190,17 @@ SmsManager::Send(const jsval& aNumber, c
       !(aNumber.isObject() && JS_IsArrayObject(cx, &aNumber.toObject()))) {
     return NS_ERROR_INVALID_ARG;
   }
 
   JSObject* global = sc->GetNativeGlobal();
   NS_ASSERTION(global, "Failed to get global object!");
 
   JSAutoRequest ar(cx);
-  JSAutoEnterCompartment ac;
-  if (!ac.enter(cx, global)) {
-    NS_ERROR("Failed to enter the js compartment!");
-    return NS_ERROR_FAILURE;
-  }
+  JSAutoCompartment ac(cx, global);
 
   if (aNumber.isString()) {
     return Send(cx, global, aNumber.toString(), aMessage, aReturn);
   }
 
   // Must be an array then.
   JSObject& numbers = aNumber.toObject();
 
--- a/dom/sms/src/SmsRequest.cpp
+++ b/dom/sms/src/SmsRequest.cpp
@@ -154,21 +154,17 @@ SmsRequest::SetSuccessInternal(nsISuppor
 
   JSContext* cx = sc->GetNativeContext();    
   NS_ASSERTION(cx, "Failed to get a context!");
 
   JSObject* global = sc->GetNativeGlobal();
   NS_ASSERTION(global, "Failed to get global object!");
 
   JSAutoRequest ar(cx);
-  JSAutoEnterCompartment ac;
-  if (!ac.enter(cx, global)) {
-    SetError(nsISmsRequestManager::INTERNAL_ERROR);
-    return false;
-  }
+  JSAutoCompartment ac(cx, global);
 
   RootResult();
 
   if (NS_FAILED(nsContentUtils::WrapNative(cx, global, aObject, &mResult))) {
     UnrootResult();
     mResult = JSVAL_VOID;
     SetError(nsISmsRequestManager::INTERNAL_ERROR);
     return false;
--- a/dom/src/json/nsJSON.cpp
+++ b/dom/src/json/nsJSON.cpp
@@ -171,22 +171,19 @@ WriteCallback(const jschar *buf, uint32_
 NS_IMETHODIMP
 nsJSON::EncodeFromJSVal(JS::Value *value, JSContext *cx, nsAString &result)
 {
   result.Truncate();
 
   // Begin a new request
   JSAutoRequest ar(cx);
 
-  JSAutoEnterCompartment ac;
+  mozilla::Maybe<JSAutoCompartment> ac;
   if (value->isObject()) {
-    JSObject *obj = &value->toObject();
-    if (!ac.enter(cx, obj)) {
-      return NS_ERROR_FAILURE;
-    }
+    ac.construct(cx, &value->toObject());
   }
 
   nsJSONWriter writer;
   if (!JS_Stringify(cx, value, NULL, JSVAL_NULL, WriteCallback, &writer)) {
     return NS_ERROR_XPC_BAD_CONVERT_JS;
   }
 
   NS_ENSURE_TRUE(writer.DidWrite(), NS_ERROR_UNEXPECTED);
--- a/dom/system/gonk/SystemWorkerManager.cpp
+++ b/dom/system/gonk/SystemWorkerManager.cpp
@@ -329,20 +329,17 @@ SystemWorkerManager::InitRIL(JSContext *
 
   jsval workerval;
   nsresult rv = worker->GetWorker(&workerval);
   NS_ENSURE_SUCCESS(rv, rv);
 
   NS_ENSURE_TRUE(!JSVAL_IS_PRIMITIVE(workerval), NS_ERROR_UNEXPECTED);
 
   JSAutoRequest ar(cx);
-  JSAutoEnterCompartment ac;
-  if (!ac.enter(cx, JSVAL_TO_OBJECT(workerval))) {
-    return NS_ERROR_OUT_OF_MEMORY;
-  }
+  JSAutoCompartment ac(cx, JSVAL_TO_OBJECT(workerval));
 
   WorkerCrossThreadDispatcher *wctd =
     GetWorkerCrossThreadDispatcher(cx, workerval);
   if (!wctd) {
     return NS_ERROR_FAILURE;
   }
 
   nsRefPtr<ConnectWorkerToRIL> connection = new ConnectWorkerToRIL();
--- a/dom/telephony/Telephony.cpp
+++ b/dom/telephony/Telephony.cpp
@@ -38,21 +38,17 @@ inline nsresult
 nsTArrayToJSArray(JSContext* aCx, JSObject* aGlobal,
                   const nsTArray<nsRefPtr<T> >& aSourceArray,
                   JSObject** aResultArray)
 {
   NS_ASSERTION(aCx, "Null context!");
   NS_ASSERTION(aGlobal, "Null global!");
 
   JSAutoRequest ar(aCx);
-  JSAutoEnterCompartment ac;
-  if (!ac.enter(aCx, aGlobal)) {
-    NS_WARNING("Failed to enter compartment!");
-    return NS_ERROR_FAILURE;
-  }
+  JSAutoCompartment ac(aCx, aGlobal);
 
   JSObject* arrayObj;
 
   if (aSourceArray.IsEmpty()) {
     arrayObj = JS_NewArrayObject(aCx, 0, nullptr);
   } else {
     uint32_t valLength = aSourceArray.Length();
     mozilla::ScopedDeleteArray<jsval> valArray(new jsval[valLength]);
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -690,22 +690,17 @@ public:
   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
   {
     JSObject* global = CreateDedicatedWorkerGlobalScope(aCx);
     if (!global) {
       NS_WARNING("Failed to make global!");
       return false;
     }
 
-    JSAutoEnterCompartment ac;
-    if (!ac.enter(aCx, global)) {
-      NS_WARNING("Failed to enter compartment!");
-      return false;
-    }
-
+    JSAutoCompartment ac(aCx, global);
     JS_SetGlobalObject(aCx, global);
 
     return scriptloader::LoadWorkerScript(aCx);
   }
 };
 
 class CloseEventRunnable : public WorkerRunnable
 {
@@ -1681,19 +1676,19 @@ WorkerRunnable::Dispatch(JSContext* aCx)
     PostDispatch(nullptr, mWorkerPrivate, ok);
     return ok;
   }
 
   JSAutoRequest ar(aCx);
 
   JSObject* global = JS_GetGlobalObject(aCx);
 
-  JSAutoEnterCompartment ac;
-  if (global && !ac.enter(aCx, global)) {
-    return false;
+  Maybe<JSAutoCompartment> ac;
+  if (global) {
+    ac.construct(aCx, global);
   }
 
   ok = PreDispatch(aCx, mWorkerPrivate);
 
   if (ok && !DispatchInternal()) {
     ok = false;
   }
 
@@ -1788,19 +1783,19 @@ WorkerRunnable::Run()
       }
     }
   }
 
   NS_ASSERTION(cx, "Must have a context!");
 
   JSAutoRequest ar(cx);
 
-  JSAutoEnterCompartment ac;
-  if (targetCompartmentObject && !ac.enter(cx, targetCompartmentObject)) {
-    return NS_OK;
+  Maybe<JSAutoCompartment> ac;
+  if (targetCompartmentObject) {
+    ac.construct(cx, targetCompartmentObject);
   }
 
   bool result = WorkerRun(cx, mWorkerPrivate);
 
   PostRun(cx, mWorkerPrivate, result);
 
   if (contextStack) {
     JSContext* otherCx;
--- a/dom/workers/WorkerScope.cpp
+++ b/dom/workers/WorkerScope.cpp
@@ -917,20 +917,17 @@ CreateDedicatedWorkerGlobalScope(JSConte
 
   JSObject* global =
     JS_NewGlobalObject(aCx, DedicatedWorkerGlobalScope::Class(),
                        GetWorkerPrincipal());
   if (!global) {
     return NULL;
   }
 
-  JSAutoEnterCompartment ac;
-  if (!ac.enter(aCx, global)) {
-    return NULL;
-  }
+  JSAutoCompartment ac(aCx, global);
 
   // Make the private slots now so that all our instance checks succeed.
   if (!DedicatedWorkerGlobalScope::InitPrivate(aCx, global, worker)) {
     return NULL;
   }
 
   // Proto chain should be:
   //   global -> DedicatedWorkerGlobalScope
--- a/extensions/pref/autoconfig/src/nsJSConfigTriggers.cpp
+++ b/extensions/pref/autoconfig/src/nsJSConfigTriggers.cpp
@@ -128,19 +128,17 @@ nsresult CentralizedAdminPrefManagerInit
 
     // Create a new Security Manger and set it for the new JS context
     nsCOMPtr<nsIXPCSecurityManager> secman =
         static_cast<nsIXPCSecurityManager*>(new AutoConfigSecMan());
     xpc->SetSecurityManagerForJSContext(autoconfig_cx, secman, 0);
 
     autoconfig_glob = JS_NewGlobalObject(autoconfig_cx, &global_class, NULL);
     if (autoconfig_glob) {
-        JSAutoEnterCompartment ac;
-        if(!ac.enter(autoconfig_cx, autoconfig_glob))
-            return NS_ERROR_FAILURE;
+        JSAutoCompartment ac(autoconfig_cx, autoconfig_glob);
         if (JS_InitStandardClasses(autoconfig_cx, autoconfig_glob)) {
             // XPCONNECT enable this JS context
             rv = xpc->InitClasses(autoconfig_cx, autoconfig_glob);
             if (NS_SUCCEEDED(rv)) 
                 return NS_OK;
         }
     }
 
--- a/ipc/testshell/TestShellParent.cpp
+++ b/ipc/testshell/TestShellParent.cpp
@@ -90,21 +90,17 @@ TestShellCommandParent::RunCallback(cons
 {
   NS_ENSURE_TRUE(*mCallback.ToJSValPtr() != JSVAL_NULL && mCx, JS_FALSE);
 
   JSAutoRequest ar(mCx);
 
   JSObject* global = JS_GetGlobalObject(mCx);
   NS_ENSURE_TRUE(global, JS_FALSE);
 
-  JSAutoEnterCompartment ac;
-  if (!ac.enter(mCx, global)) {
-    NS_ERROR("Failed to enter compartment!");
-    return false;
-  }
+  JSAutoCompartment ac(mCx, global);
 
   JSString* str = JS_NewUCStringCopyN(mCx, aResponse.get(), aResponse.Length());
   NS_ENSURE_TRUE(str, JS_FALSE);
 
   jsval argv[] = { STRING_TO_JSVAL(str) };
   unsigned argc = ArrayLength(argv);
 
   jsval rval;
--- a/ipc/testshell/XPCShellEnvironment.cpp
+++ b/ipc/testshell/XPCShellEnvironment.cpp
@@ -557,22 +557,17 @@ ProcessFile(JSContext *cx,
             while((ch = fgetc(file)) != EOF) {
                 if(ch == '\n' || ch == '\r')
                     break;
             }
         }
         ungetc(ch, file);
 
         JSAutoRequest ar(cx);
-
-        JSAutoEnterCompartment ac;
-        if (!ac.enter(cx, obj)) {
-            NS_ERROR("Failed to enter compartment!");
-            return;
-        }
+        JSAutoCompartment ac(cx, obj);
 
         JSScript* script =
             JS_CompileUTF8FileHandleForPrincipals(cx, obj, filename, file,
                                                   env->GetPrincipal());
         if (script && !env->ShouldCompileOnly())
             (void)JS_ExecuteScript(cx, obj, script, &result);
 
         return;
@@ -581,22 +576,17 @@ ProcessFile(JSContext *cx,
     /* It's an interactive filehandle; drop into read-eval-print loop. */
     lineno = 1;
     hitEOF = JS_FALSE;
     do {
         bufp = buffer;
         *bufp = '\0';
 
         JSAutoRequest ar(cx);
-
-        JSAutoEnterCompartment ac;
-        if (!ac.enter(cx, obj)) {
-            NS_ERROR("Failed to enter compartment!");
-            return;
-        }
+        JSAutoCompartment ac(cx, obj);
 
         /*
          * Accumulate lines until we get a 'compilable unit' - one that either
          * generates an error (before running out of source) or that compiles
          * cleanly.  This should be whenever we get a complete statement that
          * coincides with the end of a line.
          */
         startline = lineno;
@@ -1110,22 +1100,17 @@ XPCShellEnvironment::Init()
     if (NS_FAILED(rv)) {
         NS_ERROR("Failed to get global JSObject!");
         return false;
     }
 
 
     {
         JSAutoRequest ar(cx);
-
-        JSAutoEnterCompartment ac;
-        if (!ac.enter(cx, globalObj)) {
-            NS_ERROR("Failed to enter compartment!");
-            return false;
-        }
+        JSAutoCompartment ac(cx, globalObj);
 
         if (!JS_DefineFunctions(cx, globalObj, gGlobalFunctions) ||
 	    !JS_DefineProfilingFunctions(cx, globalObj)) {
             NS_ERROR("JS_DefineFunctions failed!");
             return false;
         }
     }
 
@@ -1149,22 +1134,17 @@ XPCShellEnvironment::EvaluateString(cons
   XPCShellEnvironment* env = Environment(mCx);
   XPCShellEnvironment::AutoContextPusher pusher(env);
 
   JSAutoRequest ar(mCx);
 
   JS_ClearPendingException(mCx);
 
   JSObject* global = GetGlobalObject();
-
-  JSAutoEnterCompartment ac;
-  if (!ac.enter(mCx, global)) {
-      NS_ERROR("Failed to enter compartment!");
-      return false;
-  }
+  JSAutoCompartment ac(mCx, global);
 
   JSScript* script =
       JS_CompileUCScriptForPrincipals(mCx, global, GetPrincipal(),
                                       aString.get(), aString.Length(),
                                       "typein", 0);
   if (!script) {
      return false;
   }
--- a/js/ductwork/debugger/JSDebugger.cpp
+++ b/js/ductwork/debugger/JSDebugger.cpp
@@ -46,21 +46,17 @@ JSDebugger::AddClass(const JS::Value &gl
   }
   
   JSObject* obj = &global.toObject();
   obj = JS_UnwrapObjectAndInnerize(obj);
   if (!obj) {
     return NS_ERROR_FAILURE;
   }
 
-  JSAutoEnterCompartment aec;
-  if (!aec.enter(cx, obj)) {
-    return NS_ERROR_FAILURE;
-  }
-
+  JSAutoCompartment ac(cx, obj);
   if (JS_GetGlobalForObject(cx, obj) != obj) {
     return NS_ERROR_INVALID_ARG;
   }
 
   if (!JS_DefineDebuggerObject(cx, obj)) {
     return NS_ERROR_FAILURE;
   }
 
--- a/js/jsd/jsd_xpc.cpp
+++ b/js/jsd/jsd_xpc.cpp
@@ -996,20 +996,17 @@ jsdScript::CreatePPLineMap()
     JSString   *jsstr;
     size_t      length;
     const jschar *chars;
     
     if (fun) {
         unsigned nargs;
 
         {
-            JSAutoEnterCompartment ac;
-            if (!ac.enter(cx, JS_GetFunctionObject(fun)))
-                return nullptr;
-
+            JSAutoCompartment ac(cx, JS_GetFunctionObject(fun));
             nargs = JS_GetFunctionArgumentCount(cx, fun);
             if (nargs > 12)
                 return nullptr;
             jsstr = JS_DecompileFunctionBody (cx, fun, 4);
             if (!jsstr)
                 return nullptr;
 
             if (!(chars = JS_GetStringCharsAndLength(cx, jsstr, &length)))
@@ -1234,19 +1231,17 @@ jsdScript::GetParameterNames(uint32_t* c
     JSFunction *fun = JSD_GetJSFunction (mCx, mScript);
     if (!fun) {
         *count = 0;
         *paramNames = nullptr;
         return NS_OK;
     }
 
     JSAutoRequest ar(cx);
-    JSAutoEnterCompartment ac;
-    if (!ac.enter(cx, JS_GetFunctionObject(fun)))
-        return NS_ERROR_FAILURE;
+    JSAutoCompartment ac(cx, JS_GetFunctionObject(fun));
 
     unsigned nargs;
     if (!JS_FunctionHasLocalNames(cx, fun) ||
         (nargs = JS_GetFunctionArgumentCount(cx, fun)) == 0) {
         *count = 0;
         *paramNames = nullptr;
         return NS_OK;
     }
@@ -1323,21 +1318,20 @@ jsdScript::GetFunctionSource(nsAString &
         NS_WARNING("No default context !?");
         return NS_ERROR_FAILURE;
     }
     JSFunction *fun = JSD_GetJSFunction (mCx, mScript);
 
     JSAutoRequest ar(cx);
 
     JSString *jsstr;
-    JSAutoEnterCompartment ac;
+    mozilla::Maybe<JSAutoCompartment> ac;
     JS::AutoEnterScriptCompartment asc;
     if (fun) {
-        if (!ac.enter(cx, JS_GetFunctionObject(fun)))
-            return NS_ERROR_FAILURE;
+        ac.construct(cx, JS_GetFunctionObject(fun));
         jsstr = JS_DecompileFunction (cx, fun, 4);
     } else {
         JSScript *script = JSD_GetJSScript (mCx, mScript);
         if (!asc.enter(cx, script))
             return NS_ERROR_FAILURE;
         jsstr = JS_DecompileScript (cx, script, "ppscript", 4);
     }
     if (!jsstr)
--- a/js/src/ctypes/CTypes.cpp
+++ b/js/src/ctypes/CTypes.cpp
@@ -5871,20 +5871,17 @@ CClosure::ClosureStub(ffi_cif* cif, void
   JSContext* cx = cinfo->cx;
   RootedObject typeObj(cx, cinfo->typeObj);
   RootedObject thisObj(cx, cinfo->thisObj);
   RootedObject jsfnObj(cx, cinfo->jsfnObj);
 
   JS_AbortIfWrongThread(JS_GetRuntime(cx));
 
   JSAutoRequest ar(cx);
-
-  JSAutoEnterCompartment ac;
-  if (!ac.enter(cx, jsfnObj))
-    return;
+  JSAutoCompartment ac(cx, jsfnObj);
 
   // Assert that our CIFs agree.
   FunctionInfo* fninfo = FunctionType::GetFunctionInfo(typeObj);
   JS_ASSERT(cif == &fninfo->mCIF);
 
   TypeCode typeCode = CType::GetTypeCode(fninfo->mReturnType);
 
   // Initialize the result to zero, in case something fails. Small integer types
--- a/js/src/jsapi-tests/testBug604087.cpp
+++ b/js/src/jsapi-tests/testBug604087.cpp
@@ -24,20 +24,17 @@ struct OuterWrapper : js::DirectWrapper
 };
 
 OuterWrapper
 OuterWrapper::singleton;
 
 static JSObject *
 wrap(JSContext *cx, JS::HandleObject toWrap, JS::HandleObject target)
 {
-    JSAutoEnterCompartment ac;
-    if (!ac.enter(cx, target))
-        return NULL;
-
+    JSAutoCompartment ac(cx, target);
     JS::RootedObject wrapper(cx, toWrap);
     if (!JS_WrapObject(cx, wrapper.address()))
         return NULL;
     return wrapper;
 }
 
 static JSObject *
 SameCompartmentWrap(JSContext *cx, JSObject *objArg)
@@ -83,18 +80,17 @@ BEGIN_TEST(testBug604087)
 
     JS::RootedObject c4wrapper(cx, wrap(cx, outerObj, compartment4));
     CHECK(c4wrapper);
     js::SetProxyExtra(c4wrapper, 0, js::Int32Value(4));
     compartment4 = c4wrapper = NULL;
 
     JS::RootedObject next(cx);
     {
-        JSAutoEnterCompartment ac;
-        CHECK(ac.enter(cx, compartment2));
+        JSAutoCompartment ac(cx, compartment2);
         next = js::Wrapper::New(cx, compartment2, compartment2->getProto(), compartment2,
                                 &OuterWrapper::singleton);
         CHECK(next);
     }
 
     JS_SetWrapObjectCallbacks(JS_GetRuntime(cx), Wrap, SameCompartmentWrap, PreWrap);
     CHECK(JS_TransplantObject(cx, outerObj, next));
     return true;
--- a/js/src/jsapi-tests/testCallNonGenericMethodOnProxy.cpp
+++ b/js/src/jsapi-tests/testCallNonGenericMethodOnProxy.cpp
@@ -59,19 +59,17 @@ BEGIN_TEST(test_CallNonGenericMethodOnPr
   CHECK_SAME(rval, Int32Value(17));
 
   // Now create the second global object and compartment...
   {
     JS::RootedObject globalB(cx, JS_NewGlobalObject(cx, getGlobalClass(), NULL));
     CHECK(globalB);
 
     // ...and enter it.
-    JSAutoEnterCompartment enter;
-    CHECK(enter.enter(cx, globalB));
-
+    JSAutoCompartment enter(cx, globalB);
     JS::RootedObject customB(cx, JS_NewObject(cx, &CustomClass, NULL, NULL));
     CHECK(customB);
     JS_SetReservedSlot(customB, CUSTOM_SLOT, Int32Value(42));
 
     JSFunction *customMethodB = JS_NewFunction(cx, CustomMethod, 0, 0, customB, "customMethodB");
     CHECK(customMethodB);
 
     jsval rval;
--- a/js/src/jsapi-tests/testChromeBuffer.cpp
+++ b/js/src/jsapi-tests/testChromeBuffer.cpp
@@ -26,24 +26,20 @@ JSObject *trusted_fun = NULL;
 JSBool
 CallTrusted(JSContext *cx, unsigned argc, jsval *vp)
 {
     if (!JS_SaveFrameChain(cx))
         return JS_FALSE;
 
     JSBool ok = JS_FALSE;
     {
-        JSAutoEnterCompartment ac;
-        ok = ac.enter(cx, trusted_glob);
-        if (!ok)
-            goto out;
+        JSAutoCompartment ac(cx, trusted_glob);
         ok = JS_CallFunctionValue(cx, NULL, OBJECT_TO_JSVAL(trusted_fun),
                                   0, NULL, vp);
     }
-  out:
     JS_RestoreFrameChain(cx);
     return ok;
 }
 
 BEGIN_TEST(testChromeBuffer)
 {
     JS_SetTrustedPrincipals(rt, &system_principals);
 
@@ -59,18 +55,17 @@ BEGIN_TEST(testChromeBuffer)
 
     /*
      * Check that, even after untrusted content has exhausted the stack, code
      * compiled with "trusted principals" can run using reserved trusted-only
      * buffer space.
      */
     {
         {
-            JSAutoEnterCompartment ac;
-            CHECK(ac.enter(cx, trusted_glob));
+            JSAutoCompartment ac(cx, trusted_glob);
             const char *paramName = "x";
             const char *bytes = "return x ? 1 + trusted(x-1) : 0";
             JS::HandleObject global = JS::HandleObject::fromMarkedLocation(&trusted_glob);
             CHECK(fun = JS_CompileFunctionForPrincipals(cx, global, &system_principals,
                                                         "trusted", 1, &paramName, bytes, strlen(bytes),
                                                         "", 0));
             trusted_fun = JS_GetFunctionObject(fun);
         }
@@ -93,18 +88,17 @@ BEGIN_TEST(testChromeBuffer)
     }
 
     /*
      * Check that content called from chrome in the reserved-buffer space
      * immediately ooms.
      */
     {
         {
-            JSAutoEnterCompartment ac;
-            CHECK(ac.enter(cx, trusted_glob));
+            JSAutoCompartment ac(cx, trusted_glob);
             const char *paramName = "untrusted";
             const char *bytes = "try {                                  "
                                 "  untrusted();                         "
                                 "} catch (e) {                          "
                                 "  return 'From trusted: ' + e;         "
                                 "}                                      ";
             JS::HandleObject global = JS::HandleObject::fromMarkedLocation(&trusted_glob);
             CHECK(fun = JS_CompileFunctionForPrincipals(cx, global, &system_principals,
@@ -133,18 +127,17 @@ BEGIN_TEST(testChromeBuffer)
     }
 
     /*
      * Check that JS_SaveFrameChain called on the way from content to chrome
      * (say, as done by XPCJSContextSTack::Push) works.
      */
     {
         {
-            JSAutoEnterCompartment ac;
-            CHECK(ac.enter(cx, trusted_glob));
+            JSAutoCompartment ac(cx, trusted_glob);
             const char *bytes = "return 42";
             JS::HandleObject global = JS::HandleObject::fromMarkedLocation(&trusted_glob);
             CHECK(fun = JS_CompileFunctionForPrincipals(cx, global, &system_principals,
                                                         "trusted", 0, NULL, bytes, strlen(bytes),
                                                         "", 0));
             trusted_fun = JS_GetFunctionObject(fun);
         }
 
--- a/js/src/jsapi-tests/testCloneScript.cpp
+++ b/js/src/jsapi-tests/testCloneScript.cpp
@@ -27,31 +27,25 @@ BEGIN_TEST(test_cloneScript)
         "    ++i;\n"
         "}\n"
         "(sum);\n";
 
     JS::RootedObject obj(cx);
 
     // compile for A
     {
-        JSAutoEnterCompartment a;
-        if (!a.enter(cx, A))
-            return false;
-
+        JSAutoCompartment a(cx, A);
         JSFunction *fun;
         CHECK(fun = JS_CompileFunction(cx, A, "f", 0, NULL, source, strlen(source), __FILE__, 1));
         CHECK(obj = JS_GetFunctionObject(fun));
     }
 
     // clone into B
     {
-        JSAutoEnterCompartment b;
-        if (!b.enter(cx, B))
-            return false;
-
+        JSAutoCompartment b(cx, B);
         CHECK(JS_CloneFunctionObject(cx, obj, B));
     }
 
     return true;
 }
 END_TEST(test_cloneScript)
 
 void
@@ -104,38 +98,32 @@ BEGIN_TEST(test_cloneScriptWithPrincipal
 
     const char *argnames[] = { "arg" };
     const char *source = "return function() { return arg; }";
 
     JS::RootedObject obj(cx);
 
     // Compile in A
     {
-        JSAutoEnterCompartment a;
-        if (!a.enter(cx, A))
-            return false;
-
+        JSAutoCompartment a(cx, A);
         JSFunction *fun;
         CHECK(fun = JS_CompileFunctionForPrincipals(cx, A, principalsA, "f",
                                                     mozilla::ArrayLength(argnames), argnames,
                                                     source, strlen(source), __FILE__, 1));
 
         JSScript *script;
         CHECK(script = JS_GetFunctionScript(cx, fun));
 
         CHECK(JS_GetScriptPrincipals(script) == principalsA);
         CHECK(obj = JS_GetFunctionObject(fun));
     }
 
     // Clone into B
     {
-        JSAutoEnterCompartment b;
-        if (!b.enter(cx, B))
-            return false;
-
+        JSAutoCompartment b(cx, B);
         JS::RootedObject cloned(cx);
         CHECK(cloned = JS_CloneFunctionObject(cx, obj, B));
 
         JSFunction *fun;
         CHECK(fun = JS_ValueToFunction(cx, JS::ObjectValue(*cloned)));
 
         JSScript *script;
         CHECK(script = JS_GetFunctionScript(cx, fun));
--- a/js/src/jsapi-tests/testContexts.cpp
+++ b/js/src/jsapi-tests/testContexts.cpp
@@ -36,18 +36,17 @@ END_TEST(testContexts_IsRunning)
 BEGIN_TEST(testContexts_bug563735)
 {
     JSContext *cx2 = JS_NewContext(rt, 8192);
     CHECK(cx2);
 
     JSBool ok;
     {
         JSAutoRequest req(cx2);
-        JSAutoEnterCompartment ac;
-        CHECK(ac.enter(cx2, global));
+        JSAutoCompartment ac(cx2, global);
         jsval v = JSVAL_NULL;
         ok = JS_SetProperty(cx2, global, "x", &v);
     }
     CHECK(ok);
 
     EXEC("(function () { for (var i = 0; i < 9; i++) ; })();");
 
     JS_DestroyContext(cx2);
--- a/js/src/jsapi-tests/testDebugger.cpp
+++ b/js/src/jsapi-tests/testDebugger.cpp
@@ -149,18 +149,17 @@ END_TEST(testDebugger_throwHook)
 
 BEGIN_TEST(testDebugger_debuggerObjectVsDebugMode)
 {
     CHECK(JS_DefineDebuggerObject(cx, global));
     JS::RootedObject debuggee(cx, JS_NewGlobalObject(cx, getGlobalClass(), NULL));
     CHECK(debuggee);
 
     {
-        JSAutoEnterCompartment ae;
-        CHECK(ae.enter(cx, debuggee));
+        JSAutoCompartment ae(cx, debuggee);
         CHECK(JS_SetDebugMode(cx, true));
         CHECK(JS_InitStandardClasses(cx, debuggee));
     }
 
     JS::RootedObject debuggeeWrapper(cx, debuggee);
     CHECK(JS_WrapObject(cx, debuggeeWrapper.address()));
     jsval v = OBJECT_TO_JSVAL(debuggeeWrapper);
     CHECK(JS_SetProperty(cx, global, "debuggee", &v));
@@ -169,18 +168,17 @@ BEGIN_TEST(testDebugger_debuggerObjectVs
          "var hits = 0;\n"
          "dbg.onDebuggerStatement = function () { hits++; };\n"
          "debuggee.eval('debugger;');\n"
          "hits;\n",
          &v);
     CHECK_SAME(v, JSVAL_ONE);
 
     {
-        JSAutoEnterCompartment ae;
-        CHECK(ae.enter(cx, debuggee));
+        JSAutoCompartment ae(cx, debuggee);
         CHECK(JS_SetDebugMode(cx, false));
     }
 
     EVAL("debuggee.eval('debugger; debugger; debugger;');\n"
          "hits;\n",
          &v);
     CHECK_SAME(v, INT_TO_JSVAL(4));
 
@@ -190,18 +188,17 @@ END_TEST(testDebugger_debuggerObjectVsDe
 
 BEGIN_TEST(testDebugger_newScriptHook)
 {
     // Test that top-level indirect eval fires the newScript hook.
     CHECK(JS_DefineDebuggerObject(cx, global));
     JS::RootedObject g(cx, JS_NewGlobalObject(cx, getGlobalClass(), NULL));
     CHECK(g);
     {
-        JSAutoEnterCompartment ae;
-        CHECK(ae.enter(cx, g));
+        JSAutoCompartment ae(cx, g);
         CHECK(JS_InitStandardClasses(cx, g));
     }
 
     JS::RootedObject gWrapper(cx, g);
     CHECK(JS_WrapObject(cx, gWrapper.address()));
     jsval v = OBJECT_TO_JSVAL(gWrapper);
     CHECK(JS_SetProperty(cx, global, "g", &v));
 
@@ -220,18 +217,17 @@ BEGIN_TEST(testDebugger_newScriptHook)
     return testIndirectEval(g, "Math.abs(0)");
 }
 
 bool testIndirectEval(JS::HandleObject scope, const char *code)
 {
     EXEC("hits = 0;");
 
     {
-        JSAutoEnterCompartment ae;
-        CHECK(ae.enter(cx, scope));
+        JSAutoCompartment ae(cx, scope);
         JSString *codestr = JS_NewStringCopyZ(cx, code);
         CHECK(codestr);
         jsval argv[1] = { STRING_TO_JSVAL(codestr) };
         jsval v;
         CHECK(JS_CallFunctionName(cx, scope, "eval", 1, argv, &v));
     }
 
     jsval hitsv;
--- a/js/src/jsapi-tests/testOriginPrincipals.cpp
+++ b/js/src/jsapi-tests/testOriginPrincipals.cpp
@@ -58,18 +58,17 @@ eval(const char *asciiChars, JSPrincipal
     size_t len = strlen(asciiChars);
     jschar *chars = new jschar[len+1];
     for (size_t i = 0; i < len; ++i)
         chars[i] = asciiChars[i];
     chars[len] = 0;
 
     JS::RootedObject global(cx, JS_NewGlobalObject(cx, getGlobalClass(), principals));
     CHECK(global);
-    JSAutoEnterCompartment ac;
-    CHECK(ac.enter(cx, global));
+    JSAutoCompartment ac(cx, global);
     CHECK(JS_InitStandardClasses(cx, global));
     bool ok = JS_EvaluateUCScriptForPrincipalsVersionOrigin(cx, global,
                                                             principals,
                                                             originPrincipals,
                                                             chars, len, "", 0, rval,
                                                             JSVERSION_DEFAULT);
     delete[] chars;
     return ok;
--- a/js/src/jsapi-tests/tests.cpp
+++ b/js/src/jsapi-tests/tests.cpp
@@ -56,19 +56,17 @@ JSObject * JSAPITest::createGlobal(JSPri
 {
     /* Create the global object. */
     global = JS_NewGlobalObject(cx, getGlobalClass(), principals);
     if (!global)
         return NULL;
     JS_AddNamedObjectRoot(cx, &global, "test-global");
     JS::HandleObject globalHandle = JS::HandleObject::fromMarkedLocation(&global);
 
-    JSAutoEnterCompartment ac;
-    if (!ac.enter(cx, globalHandle))
-        return NULL;
+    JSAutoCompartment ac(cx, globalHandle);
 
     /* Populate the global object with the standard globals, like Object and
        Array. */
     if (!JS_InitStandardClasses(cx, globalHandle))
         return NULL;
     return global;
 }
 
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -1481,40 +1481,27 @@ JS_PUBLIC_API(void)
 JS_LeaveCrossCompartmentCall(JSCrossCompartmentCall *call)
 {
     AssertHeapIsIdle(call->context);
     CHECK_REQUEST(call->context);
     call->context->leaveCompartment(call->oldCompartment);
     Foreground::delete_(call);
 }
 
-bool
-JSAutoEnterCompartment::enter(JSContext *cx, JSRawObject target)
-{
-    enterAndIgnoreErrors(cx, target);
-    return true;
-}
-
-void
-JSAutoEnterCompartment::enterAndIgnoreErrors(JSContext *cx, JSRawObject target)
-{
-    AssertHeapIsIdleOrIterating(cx);
-    JS_ASSERT(!entered_);
-    cx_ = cx;
-    oldCompartment_ = cx->compartment;
-    cx->enterCompartment(target->compartment());
-    entered_ = true;
-}
-
-void
-JSAutoEnterCompartment::leave()
-{
-    JS_ASSERT(entered_);
+JSAutoCompartment::JSAutoCompartment(JSContext *cx, JSRawObject target)
+  : cx_(cx),
+    oldCompartment_(cx->compartment)
+{
+    AssertHeapIsIdleOrIterating(cx_);
+    cx_->enterCompartment(target->compartment());
+}
+
+JSAutoCompartment::~JSAutoCompartment()
+{
     cx_->leaveCompartment(oldCompartment_);
-    entered_ = false;
 }
 
 bool
 AutoEnterScriptCompartment::enter(JSContext *cx, JSScript *target)
 {
     JS_ASSERT(!call);
     if (cx->compartment == target->compartment()) {
         call = reinterpret_cast<JSCrossCompartmentCall*>(1);
@@ -1646,19 +1633,19 @@ JS_TransplantObject(JSContext *cx, JSObj
 
     // Now, iterate through other scopes looking for references to the
     // old object, and update the relevant cross-compartment wrappers.
     if (!RemapAllWrappersForObject(cx, origobj, newIdentity))
         return NULL;
 
     // Lastly, update the original object to point to the new one.
     if (origobj->compartment() != destination) {
+        RootedObject newIdentityWrapper(cx, newIdentity);
         AutoCompartment ac(cx, origobj);
-        RootedObject newIdentityWrapper(cx, newIdentity);
-        if (!ac.enter() || !JS_WrapObject(cx, newIdentityWrapper.address()))
+        if (!JS_WrapObject(cx, newIdentityWrapper.address()))
             return NULL;
         if (!origobj->swap(cx, newIdentityWrapper))
             return NULL;
         origobj->compartment()->crossCompartmentWrappers.put(ObjectValue(*newIdentity), origv);
     }
 
     // The new identity object might be one of several things. Return it to avoid
     // ambiguity.
@@ -1725,18 +1712,16 @@ js_TransplantObjectWithWrapper(JSContext
 
     // Lastly, update things in the original compartment. Our invariants dictate
     // that the original compartment can only have one cross-compartment wrapper
     // to the new object. So we choose to update |origwrapper|, not |origobj|,
     // since there are probably no live direct intra-compartment references to
     // |origobj|.
     {
         AutoCompartment ac(cx, origobj);
-        if (!ac.enter())
-            return NULL;
 
         // We can't be sure that the reflector is completely dead. This is bad,
         // because it is in a weird state. To minimize potential harm we create
         // a new unreachable dummy object and swap it with the reflector.
         // After the swap we have a possibly-live object that isn't dangerous,
         // and a possibly-dangerous object that isn't live.
         RootedObject reflectorGuts(cx, NewDeadProxyObject(cx, JS_GetGlobalForObject(cx, origobj)));
         if (!reflectorGuts || !origobj->swap(cx, reflectorGuts))
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -3313,43 +3313,23 @@ JS_RefreshCrossCompartmentWrappers(JSCon
 
 #ifdef __cplusplus
 JS_END_EXTERN_C
 
 namespace js {
 class AutoCompartment;
 }
 
-class JS_PUBLIC_API(JSAutoEnterCompartment)
+class JS_PUBLIC_API(JSAutoCompartment)
 {
     JSContext *cx_;
     JSCompartment *oldCompartment_;
-    bool entered_;
-
   public:
-    JSAutoEnterCompartment() : entered_(false) {}
-
-    JSAutoEnterCompartment(JSContext *cx, JSRawObject target)
-      : entered_(false)
-    { enter(cx, target); }
-
-    bool enter(JSContext *cx, JSRawObject target);
-
-    void enterAndIgnoreErrors(JSContext *cx, JSRawObject target);
-
-    bool entered() const { return entered_; }
-
-    /*
-     * In general, consumers should try to avoid calling leave() explicitly,
-     * and defer to the destructor by scoping the JSAutoEnterCompartment
-     * appropriately. Sometimes, though, it's unavoidable.
-     */
-    void leave();
-
-    ~JSAutoEnterCompartment() { if (entered_) leave(); }
+    JSAutoCompartment(JSContext *cx, JSRawObject target);
+    ~JSAutoCompartment();
 };
 
 JS_BEGIN_EXTERN_C
 #endif
 
 typedef void (*JSIterateCompartmentCallback)(JSRuntime *rt, void *data, JSCompartment *compartment);
 
 /*
--- a/js/src/jsclone.cpp
+++ b/js/src/jsclone.cpp
@@ -505,22 +505,17 @@ JSStructuredCloneWriter::startWrite(cons
         RootedObject obj(context(), &v.toObject());
 
         // The object might be a security wrapper. See if we can clone what's
         // behind it. If we can, unwrap the object.
         obj = UnwrapObjectChecked(context(), obj);
         if (!obj)
             return false;
 
-        // If we unwrapped above, we'll need to enter the underlying compartment.
-        // Let the AutoEnterCompartment do the right thing for us.
-        JSAutoEnterCompartment ac;
-        if (!ac.enter(context(), obj))
-            return false;
-
+        AutoCompartment ac(context(), obj);
         if (obj->isRegExp()) {
             RegExpObject &reobj = obj->asRegExp();
             return out.writePair(SCTAG_REGEXP_OBJECT, reobj.getFlags()) &&
                    writeString(SCTAG_STRING, reobj.getSource());
         } else if (obj->isDate()) {
             double d = js_DateGetMsecSinceEpoch(context(), obj);
             return out.writePair(SCTAG_DATE_OBJECT, 0) && out.writeDouble(d);
         } else if (obj->isObject() || obj->isArray()) {
@@ -550,22 +545,17 @@ JSStructuredCloneWriter::startWrite(cons
 bool
 JSStructuredCloneWriter::write(const Value &v)
 {
     if (!startWrite(v))
         return false;
 
     while (!counts.empty()) {
         RootedObject obj(context(), &objs.back().toObject());
-
-        // The objects in |obj| can live in other compartments.
-        JSAutoEnterCompartment ac;
-        if (!ac.enter(context(), obj))
-            return false;
-
+        AutoCompartment ac(context(), obj);
         if (counts.back()) {
             counts.back()--;
             RootedId id(context(), ids.back());
             ids.popBack();
             checkStack();
             if (JSID_IS_STRING(id) || JSID_IS_INT(id)) {
                 /*
                  * If obj still has an own property named id, write it out.
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -215,20 +215,16 @@ bool
 JSRuntime::initSelfHosting(JSContext *cx)
 {
     JS_ASSERT(!selfHostedGlobal_);
     RootedObject savedGlobal(cx, JS_GetGlobalObject(cx));
     if (!(selfHostedGlobal_ = JS_NewGlobalObject(cx, &self_hosting_global_class, NULL)))
         return false;
     JS_SetGlobalObject(cx, selfHostedGlobal_);
 
-    JSAutoEnterCompartment ac;
-    if (!ac.enter(cx, cx->global()))
-        return false;
-
     const char *src = selfhosted::raw_sources;
     uint32_t srcLen = selfhosted::GetRawScriptsSize();
 
     CompileOptions options(cx);
     options.setFileAndLine("self-hosted", 1);
     options.setSelfHostingMode(true);
 
     RootedObject shg(cx, selfHostedGlobal_);
@@ -261,18 +257,18 @@ JSRuntime::getSelfHostedFunction(JSConte
 }
 
 bool
 JSRuntime::cloneSelfHostedValueById(JSContext *cx, jsid id, HandleObject holder, Value *vp)
 {
     Value funVal;
     {
         RootedObject shg(cx, selfHostedGlobal_);
-        JSAutoEnterCompartment ac;
-        if (!ac.enter(cx, shg) || !JS_GetPropertyById(cx, shg, id, &funVal) || !funVal.isObject())
+        AutoCompartment ac(cx, shg);
+        if (!JS_GetPropertyById(cx, shg, id, &funVal) || !funVal.isObject())
             return false;
     }
 
     RootedObject clone(cx, JS_CloneFunctionObject(cx, &funVal.toObject(), cx->global()));
     if (!clone)
         return false;
 
     vp->setObjectOrNull(clone);
--- a/js/src/jscompartment.h
+++ b/js/src/jscompartment.h
@@ -478,38 +478,33 @@ class AssertCompartmentUnchanged {
 
     ~AssertCompartmentUnchanged() {
         JS_ASSERT(cx->compartment == oldCompartment);
     }
 };
 
 class AutoCompartment
 {
-  public:
-    JSContext * const context;
-    JSCompartment * const origin;
-    JSCompartment * const destination;
-  private:
-    bool entered;
+    JSContext * const cx_;
+    JSCompartment * const origin_;
 
   public:
     AutoCompartment(JSContext *cx, JSObject *target)
-      : context(cx),
-        origin(cx->compartment),
-        destination(target->compartment()),
-        entered(false)
-    {}
+      : cx_(cx),
+        origin_(cx->compartment)
+    {
+        cx_->enterCompartment(target->compartment());
+    }
 
     ~AutoCompartment() {
-        if (entered)
-            leave();
+        cx_->leaveCompartment(origin_);
     }
 
-    bool enter() { context->enterCompartment(destination); entered = true; return true; }
-    void leave() { JS_ASSERT(entered); context->leaveCompartment(origin); entered = false; }
+    JSContext *context() const { return cx_; }
+    JSCompartment *origin() const { return origin_; }
 
   private:
     AutoCompartment(const AutoCompartment &) MOZ_DELETE;
     AutoCompartment & operator=(const AutoCompartment &) MOZ_DELETE;
 };
 
 /*
  * Entering the atoms comaprtment is not possible with the AutoCompartment
@@ -539,23 +534,22 @@ class AutoEnterAtomsCompartment
 
 /*
  * Use this to change the behavior of an AutoCompartment slightly on error. If
  * the exception happens to be an Error object, copy it to the origin compartment
  * instead of wrapping it.
  */
 class ErrorCopier
 {
-    AutoCompartment &ac;
+    Maybe<AutoCompartment> &ac;
     RootedObject scope;
 
   public:
-    ErrorCopier(AutoCompartment &ac, JSObject *scope) : ac(ac), scope(ac.context, scope) {
-        JS_ASSERT(scope->compartment() == ac.origin);
-    }
+    ErrorCopier(Maybe<AutoCompartment> &ac, JSObject *scope)
+      : ac(ac), scope(ac.ref().context(), scope) {}
     ~ErrorCopier();
 };
 
 class CompartmentsIter {
   private:
     JSCompartment **it, **end;
 
   public:
--- a/js/src/jsdbgapi.cpp
+++ b/js/src/jsdbgapi.cpp
@@ -530,20 +530,17 @@ JS_SetFrameAnnotation(JSContext *cx, JSS
     Valueify(fp)->setAnnotation(annotation);
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_GetFrameScopeChain(JSContext *cx, JSStackFrame *fpArg)
 {
     StackFrame *fp = Valueify(fpArg);
     JS_ASSERT(cx->stack.space().containsSlow(fp));
-    js::AutoCompartment ac(cx, fp->scopeChain());
-    if (!ac.enter())
-        return NULL;
-
+    AutoCompartment ac(cx, fp->scopeChain());
     return GetDebugScopeForFrame(cx, fp);
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_GetFrameCallObject(JSContext *cx, JSStackFrame *fpArg)
 {
     StackFrame *fp = Valueify(fpArg);
     JS_ASSERT(cx->stack.space().containsSlow(fp));
@@ -571,21 +568,19 @@ JS_GetFrameCallObject(JSContext *cx, JSS
 }
 
 JS_PUBLIC_API(JSBool)
 JS_GetFrameThis(JSContext *cx, JSStackFrame *fpArg, jsval *thisv)
 {
     StackFrame *fp = Valueify(fpArg);
 
     js::AutoCompartment ac(cx, fp->scopeChain());
-    if (!ac.enter())
+    if (!ComputeThis(cx, fp))
         return false;
 
-    if (!ComputeThis(cx, fp))
-        return false;
     *thisv = fp->thisValue();
     return true;
 }
 
 JS_PUBLIC_API(JSFunction *)
 JS_GetFrameFunction(JSContext *cx, JSStackFrame *fp)
 {
     return Valueify(fp)->maybeScriptFunction();
@@ -726,21 +721,19 @@ JS_EvaluateUCInStackFrame(JSContext *cx,
         return false;
 
     SkipRoot skip(cx, &chars);
 
     Rooted<Env*> env(cx, JS_GetFrameScopeChain(cx, fpArg));
     if (!env)
         return false;
 
+    StackFrame *fp = Valueify(fpArg);
+
     js::AutoCompartment ac(cx, env);
-    if (!ac.enter())
-        return false;
-
-    StackFrame *fp = Valueify(fpArg);
     return EvaluateInEnv(cx, env, fp, chars, length, filename, lineno, rval);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_EvaluateInStackFrame(JSContext *cx, JSStackFrame *fp,
                         const char *bytes, unsigned length,
                         const char *filename, unsigned lineno,
                         jsval *rval)
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -3141,26 +3141,22 @@ JSObject::swap(JSContext *cx, JSObject *
         TradeGuts(cx, this, other, reserved);
         return true;
     }
 
     JSObject *thisClone;
     JSObject *otherClone;
     {
         AutoCompartment ac(cx, other);
-        if (!ac.enter())
-            return false;
         thisClone = JS_CloneObject(cx, this, other->getProto(), other->getParent());
         if (!thisClone || !JS_CopyPropertiesFrom(cx, thisClone, this))
             return false;
     }
     {
         AutoCompartment ac(cx, this);
-        if (!ac.enter())
-            return false;
         otherClone = JS_CloneObject(cx, other, other->getProto(), other->getParent());
         if (!otherClone || !JS_CopyPropertiesFrom(cx, otherClone, other))
             return false;
     }
 
     TradeGutsReserved reservedThis(cx);
     TradeGutsReserved reservedOther(cx);
 
--- a/js/src/jsopcode.cpp
+++ b/js/src/jsopcode.cpp
@@ -6787,21 +6787,17 @@ GetPCCountScriptContents(JSContext *cx, 
     JSScript *script = sac.script;
 
     StringBuffer buf(cx);
 
     if (!script->function() && !script->compileAndGo)
         return buf.finishString();
 
     {
-        JSAutoEnterCompartment ac;
-        RootedObject target(cx, &script->global());
-        if (!ac.enter(cx, target))
-            return NULL;
-
+        AutoCompartment ac(cx, &script->global());
         if (!GetPCCountJSON(cx, sac, buf))
             return NULL;
     }
 
     return buf.finishString();
 }
 
 } // namespace js
--- a/js/src/jswrapper.cpp
+++ b/js/src/jswrapper.cpp
@@ -390,25 +390,22 @@ js::TransparentObjectWrapper(JSContext *
 
     // Allow wrapping outer window proxies.
     JS_ASSERT(!obj->isWrapper() || obj->getClass()->ext.innerObject);
     return Wrapper::New(cx, obj, wrappedProto, parent, &CrossCompartmentWrapper::singleton);
 }
 
 ErrorCopier::~ErrorCopier()
 {
-    JSContext *cx = ac.context;
-    if (cx->compartment == ac.destination &&
-        ac.origin != ac.destination &&
-        cx->isExceptionPending())
-    {
+    JSContext *cx = ac.ref().context();
+    if (ac.ref().origin() != cx->compartment && cx->isExceptionPending()) {
         Value exc = cx->getPendingException();
         if (exc.isObject() && exc.toObject().isError() && exc.toObject().getPrivate()) {
             cx->clearPendingException();
-            ac.leave();
+            ac.destroy();
             Rooted<JSObject*> errObj(cx, &exc.toObject());
             JSObject *copyobj = js_CopyErrorObject(cx, errObj, scope);
             if (copyobj)
                 cx->setPendingException(ObjectValue(*copyobj));
         }
     }
 }
 
@@ -418,54 +415,54 @@ CrossCompartmentWrapper::CrossCompartmen
   : DirectWrapper(CROSS_COMPARTMENT | flags, hasPrototype)
 {
 }
 
 CrossCompartmentWrapper::~CrossCompartmentWrapper()
 {
 }
 
-#define PIERCE(cx, wrapper, mode, pre, op, post)            \
-    JS_BEGIN_MACRO                                          \
-        AutoCompartment call(cx, wrappedObject(wrapper));   \
-        if (!call.enter())                                  \
-            return false;                                   \
-        bool ok = (pre) && (op);                            \
-        call.leave();                                       \
-        return ok && (post);                                \
+#define PIERCE(cx, wrapper, mode, pre, op, post)                \
+    JS_BEGIN_MACRO                                              \
+        bool ok;                                                \
+        {                                                       \
+            AutoCompartment call(cx, wrappedObject(wrapper));   \
+            ok = (pre) && (op);                                 \
+        }                                                       \
+        return ok && (post);                                    \
     JS_END_MACRO
 
 #define NOTHING (true)
 
 bool
 CrossCompartmentWrapper::getPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id,
                                                bool set, PropertyDescriptor *desc)
 {
     PIERCE(cx, wrapper, set ? SET : GET,
-           call.destination->wrapId(cx, &id),
+           cx->compartment->wrapId(cx, &id),
            DirectWrapper::getPropertyDescriptor(cx, wrapper, id, set, desc),
            cx->compartment->wrap(cx, desc));
 }
 
 bool
 CrossCompartmentWrapper::getOwnPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id,
                                                   bool set, PropertyDescriptor *desc)
 {
     PIERCE(cx, wrapper, set ? SET : GET,
-           call.destination->wrapId(cx, &id),
+           cx->compartment->wrapId(cx, &id),
            DirectWrapper::getOwnPropertyDescriptor(cx, wrapper, id, set, desc),
            cx->compartment->wrap(cx, desc));
 }
 
 bool
 CrossCompartmentWrapper::defineProperty(JSContext *cx, JSObject *wrapper, jsid id, PropertyDescriptor *desc)
 {
     AutoPropertyDescriptorRooter desc2(cx, desc);
     PIERCE(cx, wrapper, SET,
-           call.destination->wrapId(cx, &id) && call.destination->wrap(cx, &desc2),
+           cx->compartment->wrapId(cx, &id) && cx->compartment->wrap(cx, &desc2),
            DirectWrapper::defineProperty(cx, wrapper, id, &desc2),
            NOTHING);
 }
 
 bool
 CrossCompartmentWrapper::getOwnPropertyNames(JSContext *cx, JSObject *wrapper, AutoIdVector &props)
 {
     PIERCE(cx, wrapper, GET,
@@ -473,17 +470,17 @@ CrossCompartmentWrapper::getOwnPropertyN
            DirectWrapper::getOwnPropertyNames(cx, wrapper, props),
            cx->compartment->wrap(cx, props));
 }
 
 bool
 CrossCompartmentWrapper::delete_(JSContext *cx, JSObject *wrapper, jsid id, bool *bp)
 {
     PIERCE(cx, wrapper, SET,
-           call.destination->wrapId(cx, &id),
+           cx->compartment->wrapId(cx, &id),
            DirectWrapper::delete_(cx, wrapper, id, bp),
            NOTHING);
 }
 
 bool
 CrossCompartmentWrapper::enumerate(JSContext *cx, JSObject *wrapper, AutoIdVector &props)
 {
     PIERCE(cx, wrapper, GET,
@@ -491,54 +488,54 @@ CrossCompartmentWrapper::enumerate(JSCon
            DirectWrapper::enumerate(cx, wrapper, props),
            cx->compartment->wrap(cx, props));
 }
 
 bool
 CrossCompartmentWrapper::has(JSContext *cx, JSObject *wrapper, jsid id, bool *bp)
 {
     PIERCE(cx, wrapper, GET,
-           call.destination->wrapId(cx, &id),
+           cx->compartment->wrapId(cx, &id),
            DirectWrapper::has(cx, wrapper, id, bp),
            NOTHING);
 }
 
 bool
 CrossCompartmentWrapper::hasOwn(JSContext *cx, JSObject *wrapper, jsid id, bool *bp)
 {
     PIERCE(cx, wrapper, GET,
-           call.destination->wrapId(cx, &id),
+           cx->compartment->wrapId(cx, &id),
            DirectWrapper::hasOwn(cx, wrapper, id, bp),
            NOTHING);
 }
 
 bool
 CrossCompartmentWrapper::get(JSContext *cx, JSObject *wrapperArg, JSObject *receiverArg,
                              jsid idArg, Value *vp)
 {
     RootedObject wrapper(cx, wrapperArg);
     RootedObject receiver(cx, receiverArg);
     RootedId id(cx, idArg);
     PIERCE(cx, wrapper, GET,
-           call.destination->wrap(cx, receiver.address()) && call.destination->wrapId(cx, id.address()),
+           cx->compartment->wrap(cx, receiver.address()) && cx->compartment->wrapId(cx, id.address()),
            DirectWrapper::get(cx, wrapper, receiver, id, vp),
            cx->compartment->wrap(cx, vp));
 }
 
 bool
 CrossCompartmentWrapper::set(JSContext *cx, JSObject *wrapper_, JSObject *receiver_, jsid id_,
                              bool strict, Value *vp)
 {
     RootedObject wrapper(cx, wrapper_), receiver(cx, receiver_);
     RootedId id(cx, id_);
     RootedValue value(cx, *vp);
     PIERCE(cx, wrapper, SET,
-           call.destination->wrap(cx, receiver.address()) &&
-           call.destination->wrapId(cx, id.address()) &&
-           call.destination->wrap(cx, value.address()),
+           cx->compartment->wrap(cx, receiver.address()) &&
+           cx->compartment->wrapId(cx, id.address()) &&
+           cx->compartment->wrap(cx, value.address()),
            DirectWrapper::set(cx, wrapper, receiver, id, strict, value.address()),
            NOTHING);
 }
 
 bool
 CrossCompartmentWrapper::keys(JSContext *cx, JSObject *wrapper, AutoIdVector &props)
 {
     PIERCE(cx, wrapper, GET,
@@ -633,161 +630,141 @@ CrossCompartmentWrapper::iterate(JSConte
            DirectWrapper::iterate(cx, wrapper, flags, vp),
            CanReify(vp) ? Reify(cx, cx->compartment, vp) : cx->compartment->wrap(cx, vp));
 }
 
 bool
 CrossCompartmentWrapper::call(JSContext *cx, JSObject *wrapper_, unsigned argc, Value *vp)
 {
     RootedObject wrapper(cx, wrapper_);
-
     JSObject *wrapped = wrappedObject(wrapper);
-    AutoCompartment call(cx, wrapped);
-    if (!call.enter())
-        return false;
+    {
+        AutoCompartment call(cx, wrapped);
 
-    vp[0] = ObjectValue(*wrapped);
-    if (!call.destination->wrap(cx, &vp[1]))
-        return false;
-    Value *argv = JS_ARGV(cx, vp);
-    for (size_t n = 0; n < argc; ++n) {
-        if (!call.destination->wrap(cx, &argv[n]))
+        vp[0] = ObjectValue(*wrapped);
+        if (!cx->compartment->wrap(cx, &vp[1]))
+            return false;
+        Value *argv = JS_ARGV(cx, vp);
+        for (size_t n = 0; n < argc; ++n) {
+            if (!cx->compartment->wrap(cx, &argv[n]))
+                return false;
+        }
+        if (!DirectWrapper::call(cx, wrapper, argc, vp))
             return false;
     }
-    if (!DirectWrapper::call(cx, wrapper, argc, vp))
-        return false;
-
-    call.leave();
     return cx->compartment->wrap(cx, vp);
 }
 
 bool
 CrossCompartmentWrapper::construct(JSContext *cx, JSObject *wrapper_, unsigned argc, Value *argv,
                                    Value *rval)
 {
     RootedObject wrapper(cx, wrapper_);
+    JSObject *wrapped = wrappedObject(wrapper);
+    {
+        AutoCompartment call(cx, wrapped);
 
-    AutoCompartment call(cx, wrappedObject(wrapper));
-    if (!call.enter())
-        return false;
-
-    for (size_t n = 0; n < argc; ++n) {
-        if (!call.destination->wrap(cx, &argv[n]))
+        for (size_t n = 0; n < argc; ++n) {
+            if (!cx->compartment->wrap(cx, &argv[n]))
+                return false;
+        }
+        if (!DirectWrapper::construct(cx, wrapper, argc, argv, rval))
             return false;
     }
-    if (!DirectWrapper::construct(cx, wrapper, argc, argv, rval))
-        return false;
-
-    call.leave();
     return cx->compartment->wrap(cx, rval);
 }
 
 bool
 CrossCompartmentWrapper::nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl,
                                     CallArgs srcArgs)
 {
     Rooted<JSObject*> wrapper(cx, &srcArgs.thisv().toObject());
     JS_ASSERT(srcArgs.thisv().isMagic(JS_IS_CONSTRUCTING) ||
               !UnwrapObject(wrapper)->isCrossCompartmentWrapper());
 
-    Rooted<JSObject*> wrapped(cx, wrappedObject(wrapper));
-    AutoCompartment call(cx, wrapped);
-    if (!call.enter())
-        return false;
-
-    InvokeArgsGuard dstArgs;
-    if (!cx->stack.pushInvokeArgs(cx, srcArgs.length(), &dstArgs))
-        return false;
+    RootedObject wrapped(cx, wrappedObject(wrapper));
+    {
+        AutoCompartment call(cx, wrapped);
+        InvokeArgsGuard dstArgs;
+        if (!cx->stack.pushInvokeArgs(cx, srcArgs.length(), &dstArgs))
+            return false;
 
-    Value *src = srcArgs.base();
-    Value *srcend = srcArgs.array() + srcArgs.length();
-    Value *dst = dstArgs.base();
-    for (; src < srcend; ++src, ++dst) {
-        *dst = *src;
-        if (!call.destination->wrap(cx, dst))
+        Value *src = srcArgs.base();
+        Value *srcend = srcArgs.array() + srcArgs.length();
+        Value *dst = dstArgs.base();
+        for (; src < srcend; ++src, ++dst) {
+            *dst = *src;
+            if (!cx->compartment->wrap(cx, dst))
+                return false;
+        }
+
+        if (!CallNonGenericMethod(cx, test, impl, dstArgs))
             return false;
+
+        srcArgs.rval().set(dstArgs.rval());
+        dstArgs.pop();
     }
-
-    if (!CallNonGenericMethod(cx, test, impl, dstArgs))
-        return false;
-
-    srcArgs.rval().set(dstArgs.rval());
-    dstArgs.pop();
-    call.leave();
     return cx->compartment->wrap(cx, srcArgs.rval().address());
 }
 
 bool
 CrossCompartmentWrapper::hasInstance(JSContext *cx, JSObject *wrapper, const Value *vp, bool *bp)
 {
     AutoCompartment call(cx, wrappedObject(wrapper));
-    if (!call.enter())
-        return false;
-
     Value v = *vp;
-    if (!call.destination->wrap(cx, &v))
+    if (!cx->compartment->wrap(cx, &v))
         return false;
     return DirectWrapper::hasInstance(cx, wrapper, &v, bp);
 }
 
 JSString *
 CrossCompartmentWrapper::obj_toString(JSContext *cx, JSObject *wrapper)
 {
-    AutoCompartment call(cx, wrappedObject(wrapper));
-    if (!call.enter())
-        return NULL;
-
-    JSString *str = DirectWrapper::obj_toString(cx, wrapper);
-    if (!str)
-        return NULL;
-
-    call.leave();
+    JSString *str = NULL;
+    {
+        AutoCompartment call(cx, wrappedObject(wrapper));
+        str = DirectWrapper::obj_toString(cx, wrapper);
+        if (!str)
+            return NULL;
+    }
     if (!cx->compartment->wrap(cx, &str))
         return NULL;
     return str;
 }
 
 JSString *
 CrossCompartmentWrapper::fun_toString(JSContext *cx, JSObject *wrapper, unsigned indent)
 {
-    AutoCompartment call(cx, wrappedObject(wrapper));
-    if (!call.enter())
-        return NULL;
-
-    JSString *str = DirectWrapper::fun_toString(cx, wrapper, indent);
-    if (!str)
-        return NULL;
-
-    call.leave();
+    JSString *str = NULL;
+    {
+        AutoCompartment call(cx, wrappedObject(wrapper));
+        str = DirectWrapper::fun_toString(cx, wrapper, indent);
+        if (!str)
+            return NULL;
+    }
     if (!cx->compartment->wrap(cx, &str))
         return NULL;
     return str;
 }
 
 bool
 CrossCompartmentWrapper::regexp_toShared(JSContext *cx, JSObject *wrapper, RegExpGuard *g)
 {
     AutoCompartment call(cx, wrappedObject(wrapper));
-    if (!call.enter())
-        return false;
-
     return DirectWrapper::regexp_toShared(cx, wrapper, g);
 }
 
 bool
 CrossCompartmentWrapper::defaultValue(JSContext *cx, JSObject *wrapper, JSType hint, Value *vp)
 {
-    AutoCompartment call(cx, wrappedObject(wrapper));
-    if (!call.enter())
-        return false;
-
-    if (!IndirectProxyHandler::defaultValue(cx, wrapper, hint, vp))
-        return false;
-
-    call.leave();
+    {
+        AutoCompartment call(cx, wrappedObject(wrapper));
+        if (!IndirectProxyHandler::defaultValue(cx, wrapper, hint, vp))
+            return false;
+    }
     return cx->compartment->wrap(cx, vp);
 }
 
 bool
 CrossCompartmentWrapper::iteratorNext(JSContext *cx, JSObject *wrapper, Value *vp)
 {
     PIERCE(cx, wrapper, GET,
            NOTHING,
@@ -1077,19 +1054,19 @@ js::RemapWrapper(JSContext *cx, JSObject
     pmap.remove(origv);
 
     // When we remove origv from the wrapper map, its wrapper, wobj, must
     // immediately cease to be a cross-compartment wrapper. Neuter it.
     NukeCrossCompartmentWrapper(wobj);
 
     // First, we wrap it in the new compartment. This will return
     // a new wrapper.
+    JSObject *tobj = newTarget;
     AutoCompartment ac(cx, wobj);
-    JSObject *tobj = newTarget;
-    if (!ac.enter() || !wcompartment->wrap(cx, &tobj))
+    if (!wcompartment->wrap(cx, &tobj))
         return false;
 
     // Now, because we need to maintain object identity, we do a
     // brain transplant on the old object. At the same time, we
     // update the entry in the compartment's wrapper map to point
     // to the old wrapper.
     JS_ASSERT(tobj != wobj);
     if (!wobj->swap(cx, tobj))
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -891,20 +891,17 @@ Evaluate(JSContext *cx, unsigned argc, j
     AutoNewContext ancx;
     if (newContext) {
         if (!ancx.enter(cx))
             return false;
         cx = ancx.get();
     }
 
     {
-        JSAutoEnterCompartment aec;
-        if (!aec.enter(cx, global))
-            return false;
-
+        JSAutoCompartment ac(cx, global);
         uint32_t saved = JS_GetOptions(cx);
         uint32_t options = saved & ~(JSOPTION_COMPILE_N_GO | JSOPTION_NO_SCRIPT_RVAL);
         if (compileAndGo)
             options |= JSOPTION_COMPILE_N_GO;
         if (noScriptRval)
             options |= JSOPTION_NO_SCRIPT_RVAL;
         JS_SetOptions(cx, options);
 
@@ -2302,23 +2299,22 @@ Clone(JSContext *cx, unsigned argc, jsva
 
     if (!argc) {
         JS_ReportError(cx, "Invalid arguments to clone");
         return false;
     }
 
     jsval *argv = JS_ARGV(cx, vp);
     {
-        JSAutoEnterCompartment ac;
+        Maybe<JSAutoCompartment> ac;
         RootedObject obj(cx, JSVAL_IS_PRIMITIVE(argv[0]) ? NULL : JSVAL_TO_OBJECT(argv[0]));
 
         if (obj && IsCrossCompartmentWrapper(obj)) {
             obj = UnwrapObject(obj);
-            if (!ac.enter(cx, obj))
-                return false;
+            ac.construct(cx, obj);
             argv[0] = ObjectValue(*obj);
         }
         if (obj && obj->isFunction()) {
             funobj = obj;
         } else {
             JSFunction *fun = JS_ValueToFunction(cx, argv[0]);
             if (!fun)
                 return false;
@@ -2535,20 +2531,17 @@ static JSClass sandbox_class = {
 static JSObject *
 NewSandbox(JSContext *cx, bool lazy)
 {
     RootedObject obj(cx, JS_NewGlobalObject(cx, &sandbox_class, NULL));
     if (!obj)
         return NULL;
 
     {
-        JSAutoEnterCompartment ac;
-        if (!ac.enter(cx, obj))
-            return NULL;
-
+        JSAutoCompartment ac(cx, obj);
         if (!lazy && !JS_InitStandardClasses(cx, obj))
             return NULL;
 
         RootedValue value(cx, BooleanValue(lazy));
         if (!JS_SetProperty(cx, obj, "lazy", value.address()))
             return NULL;
     }
 
@@ -2592,23 +2585,22 @@ EvalInContext(JSContext *cx, unsigned ar
     }
 
     JSScript *script;
     unsigned lineno;
 
     JS_DescribeScriptedCaller(cx, &script, &lineno);
     jsval rval;
     {
-        JSAutoEnterCompartment ac;
+        Maybe<JSAutoCompartment> ac;
         unsigned flags;
         JSObject *unwrapped = UnwrapObject(sobj, true, &flags);
         if (flags & Wrapper::CROSS_COMPARTMENT) {
             sobj = unwrapped;
-            if (!ac.enter(cx, sobj))
-                return false;
+            ac.construct(cx, sobj);
         }
 
         sobj = GetInnerObject(cx, sobj);
         if (!sobj)
             return false;
         if (!(sobj->getClass()->flags & JSCLASS_IS_GLOBAL)) {
             JS_ReportError(cx, "Invalid scope argument to evalcx");
             return false;
@@ -4677,19 +4669,17 @@ DestroyContext(JSContext *cx, bool withG
 static JSObject *
 NewGlobalObject(JSContext *cx)
 {
     RootedObject glob(cx, JS_NewGlobalObject(cx, &global_class, NULL));
     if (!glob)
         return NULL;
 
     {
-        JSAutoEnterCompartment ac;
-        if (!ac.enter(cx, glob))
-            return NULL;
+        JSAutoCompartment ac(cx, glob);
 
 #ifndef LAZY_STANDARD_CLASSES
         if (!JS_InitStandardClasses(cx, glob))
             return NULL;
 #endif
 
 #ifdef JS_HAS_CTYPES
         if (!JS_InitCTypesClass(cx, glob))
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -523,22 +523,18 @@ Debugger::slowPathOnLeaveFrame(JSContext
     for (JSObject **p = frames.begin(); p != frames.end(); p++) {
         RootedObject frameobj(cx, *p);
         Debugger *dbg = Debugger::fromChildJSObject(frameobj);
 
         if (dbg->enabled &&
             !frameobj->getReservedSlot(JSSLOT_DEBUGFRAME_ONPOP_HANDLER).isUndefined()) {
             RootedValue handler(cx, frameobj->getReservedSlot(JSSLOT_DEBUGFRAME_ONPOP_HANDLER));
 
-            AutoCompartment ac(cx, dbg->object);
-
-            if (!ac.enter()) {
-                status = JSTRAP_ERROR;
-                break;
-            }
+            Maybe<AutoCompartment> ac;
+            ac.construct(cx, dbg->object);
 
             Value completion;
             if (!dbg->newCompletionValue(cx, status, value, &completion)) {
                 status = dbg->handleUncaughtException(ac, NULL, false);
                 break;
             }
 
             /* Call the onPop handler. */
@@ -721,35 +717,35 @@ Debugger::unwrapDebuggeeValue(JSContext 
         }
 
         vp->setObject(*(JSObject *) dobj->getPrivate());
     }
     return true;
 }
 
 JSTrapStatus
-Debugger::handleUncaughtException(AutoCompartment &ac, Value *vp, bool callHook)
+Debugger::handleUncaughtException(Maybe<AutoCompartment> &ac, Value *vp, bool callHook)
 {
-    JSContext *cx = ac.context;
+    JSContext *cx = ac.ref().context();
     if (cx->isExceptionPending()) {
         if (callHook && uncaughtExceptionHook) {
             Value fval = ObjectValue(*uncaughtExceptionHook);
             Value exc = cx->getPendingException();
             Value rv;
             cx->clearPendingException();
             if (Invoke(cx, ObjectValue(*object), fval, 1, &exc, &rv))
                 return vp ? parseResumptionValue(ac, true, rv, vp, false) : JSTRAP_CONTINUE;
         }
 
         if (cx->isExceptionPending()) {
             JS_ReportPendingException(cx);
             cx->clearPendingException();
         }
     }
-    ac.leave();
+    ac.destroy();
     return JSTRAP_ERROR;
 }
 
 void
 Debugger::resultToCompletion(JSContext *cx, bool ok, const Value &rv,
                              JSTrapStatus *status, Value *value)
 {
     JS_ASSERT_IF(ok, !cx->isExceptionPending());
@@ -806,45 +802,45 @@ Debugger::newCompletionValue(JSContext *
         return false;
     }
 
     result->setObject(*obj);
     return true;
 }
 
 bool
-Debugger::receiveCompletionValue(AutoCompartment &ac, bool ok, Value val, Value *vp)
+Debugger::receiveCompletionValue(Maybe<AutoCompartment> &ac, bool ok, Value val, Value *vp)
 {
-    JSContext *cx = ac.context;
+    JSContext *cx = ac.ref().context();
 
     JSTrapStatus status;
     Value value;
     resultToCompletion(cx, ok, val, &status, &value);
-    ac.leave();
+    ac.destroy();
     return newCompletionValue(cx, status, value, vp);
 }
 
 JSTrapStatus
-Debugger::parseResumptionValue(AutoCompartment &ac, bool ok, const Value &rv, Value *vp,
+Debugger::parseResumptionValue(Maybe<AutoCompartment> &ac, bool ok, const Value &rv, Value *vp,
                                bool callHook)
 {
     vp->setUndefined();
     if (!ok)
         return handleUncaughtException(ac, vp, callHook);
     if (rv.isUndefined()) {
-        ac.leave();
+        ac.destroy();
         return JSTRAP_CONTINUE;
     }
     if (rv.isNull()) {
-        ac.leave();
+        ac.destroy();
         return JSTRAP_ERROR;
     }
 
     /* Check that rv is {return: val} or {throw: val}. */
-    JSContext *cx = ac.context;
+    JSContext *cx = ac.ref().context();
     Rooted<JSObject*> obj(cx);
     Shape *shape;
     jsid returnId = NameToId(cx->runtime->atomState.returnAtom);
     jsid throwId = NameToId(cx->runtime->atomState.throwAtom);
     bool okResumption = rv.isObject();
     if (okResumption) {
         obj = &rv.toObject();
         okResumption = obj->isObject();
@@ -859,17 +855,17 @@ Debugger::parseResumptionValue(AutoCompa
     if (!okResumption) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_DEBUG_BAD_RESUMPTION);
         return handleUncaughtException(ac, vp, callHook);
     }
 
     if (!js_NativeGet(cx, obj, obj, shape, 0, vp) || !unwrapDebuggeeValue(cx, vp))
         return handleUncaughtException(ac, vp, callHook);
 
-    ac.leave();
+    ac.destroy();
     if (!cx->compartment->wrap(cx, vp)) {
         vp->setUndefined();
         return JSTRAP_ERROR;
     }
     return shape->propid() == returnId ? JSTRAP_RETURN : JSTRAP_THROW;
 }
 
 bool
@@ -889,51 +885,46 @@ CallMethodIfPresent(JSContext *cx, Handl
 
 JSTrapStatus
 Debugger::fireDebuggerStatement(JSContext *cx, Value *vp)
 {
     RootedObject hook(cx, getHook(OnDebuggerStatement));
     JS_ASSERT(hook);
     JS_ASSERT(hook->isCallable());
 
-    /* Grab cx->fp() before pushing a dummy frame. */
-    StackFrame *fp = cx->fp();
-    AutoCompartment ac(cx, object);
-    if (!ac.enter())
-        return JSTRAP_ERROR;
+    Maybe<AutoCompartment> ac;
+    ac.construct(cx, object);
 
     Value argv[1];
-    if (!getScriptFrame(cx, fp, argv))
+    if (!getScriptFrame(cx, cx->fp(), argv))
         return handleUncaughtException(ac, vp, false);
 
     Value rv;
     bool ok = Invoke(cx, ObjectValue(*object), ObjectValue(*hook), 1, argv, &rv);
     return parseResumptionValue(ac, ok, rv, vp);
 }
 
 JSTrapStatus
 Debugger::fireExceptionUnwind(JSContext *cx, Value *vp)
 {
     RootedObject hook(cx, getHook(OnExceptionUnwind));
     JS_ASSERT(hook);
     JS_ASSERT(hook->isCallable());
 
-    StackFrame *fp = cx->fp();
     RootedValue exc(cx, cx->getPendingException());
     cx->clearPendingException();
 
-    AutoCompartment ac(cx, object);
-    if (!ac.enter())
-        return JSTRAP_ERROR;
+    Maybe<AutoCompartment> ac;
+    ac.construct(cx, object);
 
     Value argv[2];
     AutoValueArray avr(cx, argv, 2);
 
     argv[1] = exc;
-    if (!getScriptFrame(cx, fp, &argv[0]) || !wrapDebuggeeValue(cx, &argv[1]))
+    if (!getScriptFrame(cx, cx->fp(), &argv[0]) || !wrapDebuggeeValue(cx, &argv[1]))
         return handleUncaughtException(ac, vp, false);
 
     Value rv;
     bool ok = Invoke(cx, ObjectValue(*object), ObjectValue(*hook), 2, argv, &rv);
     JSTrapStatus st = parseResumptionValue(ac, ok, rv, vp);
     if (st == JSTRAP_CONTINUE)
         cx->setPendingException(exc);
     return st;
@@ -942,19 +933,18 @@ Debugger::fireExceptionUnwind(JSContext 
 JSTrapStatus
 Debugger::fireEnterFrame(JSContext *cx, Value *vp)
 {
     RootedObject hook(cx, getHook(OnEnterFrame));
     JS_ASSERT(hook);
     JS_ASSERT(hook->isCallable());
 
     StackFrame *fp = cx->fp();
-    AutoCompartment ac(cx, object);
-    if (!ac.enter())
-        return JSTRAP_ERROR;
+    Maybe<AutoCompartment> ac;
+    ac.construct(cx, object);
 
     Value argv[1];
     if (!getScriptFrame(cx, fp, &argv[0]))
         return handleUncaughtException(ac, vp, false);
 
     Value rv;
     bool ok = Invoke(cx, ObjectValue(*object), ObjectValue(*hook), 1, argv, &rv);
     return parseResumptionValue(ac, ok, rv, vp);
@@ -962,19 +952,18 @@ Debugger::fireEnterFrame(JSContext *cx, 
 
 void
 Debugger::fireNewScript(JSContext *cx, HandleScript script)
 {
     RootedObject hook(cx, getHook(OnNewScript));
     JS_ASSERT(hook);
     JS_ASSERT(hook->isCallable());
 
-    AutoCompartment ac(cx, object);
-    if (!ac.enter())
-        return;
+    Maybe<AutoCompartment> ac;
+    ac.construct(cx, object);
 
     JSObject *dsobj = wrapScript(cx, script);
     if (!dsobj) {
         handleUncaughtException(ac, NULL, false);
         return;
     }
 
     Value argv[1];
@@ -1117,19 +1106,18 @@ Debugger::onTrap(JSContext *cx, Value *v
          * or remove debuggees.
          *
          * The other has to do with non-compile-and-go scripts, which have no
          * specific global--until they are executed. Only now do we know which
          * global the script is running against.
          */
         Debugger *dbg = bp->debugger;
         if (dbg->enabled && dbg->debuggees.lookup(scriptGlobal)) {
-            AutoCompartment ac(cx, dbg->object);
-            if (!ac.enter())
-                return JSTRAP_ERROR;
+            Maybe<AutoCompartment> ac;
+            ac.construct(cx, dbg->object);
 
             Value argv[1];
             AutoValueArray ava(cx, argv, 1);
             if (!dbg->getScriptFrame(cx, fp, &argv[0]))
                 return dbg->handleUncaughtException(ac, vp, false);
             Value rv;
             Rooted<JSObject*> handler(cx, bp->handler);
             bool ok = CallMethodIfPresent(cx, handler, "hit", 1, argv, &rv);
@@ -1234,19 +1222,20 @@ Debugger::onSingleStep(JSContext *cx, Va
         }
     };
     PreserveIterValue piv(cx);
 
     /* Call all the onStep handlers we found. */
     for (JSObject **p = frames.begin(); p != frames.end(); p++) {
         JSObject *frame = *p;
         Debugger *dbg = Debugger::fromChildJSObject(frame);
-        AutoCompartment ac(cx, dbg->object);
-        if (!ac.enter())
-            return JSTRAP_ERROR;
+
+        Maybe<AutoCompartment> ac;
+        ac.construct(cx, dbg->object);
+
         const Value &handler = frame->getReservedSlot(JSSLOT_DEBUGFRAME_ONSTEP_HANDLER);
         Value rval;
         bool ok = Invoke(cx, ObjectValue(*frame), handler, 0, NULL, &rval);
         JSTrapStatus st = dbg->parseResumptionValue(ac, ok, rval, vp);
         if (st != JSTRAP_CONTINUE)
             return st;
     }
 
@@ -1892,18 +1881,16 @@ Debugger::addDebuggeeGlobal(JSContext *c
         return false;
     }
 
     /*
      * Each debugger-debuggee relation must be stored in up to three places.
      * JSCompartment::addDebuggee enables debug mode if needed.
      */
     AutoCompartment ac(cx, global);
-    if (!ac.enter())
-        return false;
     GlobalObject::DebuggerVector *v = GlobalObject::getOrCreateDebuggers(cx, global);
     if (!v || !v->append(this)) {
         js_ReportOutOfMemory(cx);
     } else {
         if (!debuggees.put(global)) {
             js_ReportOutOfMemory(cx);
         } else {
             if (global->getDebuggers()->length() > 1)
@@ -3091,18 +3078,16 @@ DebuggerFrame_getType(JSContext *cx, uns
 static JSBool
 DebuggerFrame_getEnvironment(JSContext *cx, unsigned argc, Value *vp)
 {
     THIS_FRAME_OWNER(cx, argc, vp, "get environment", args, thisobj, fp, dbg);
 
     Rooted<Env*> env(cx);
     {
         AutoCompartment ac(cx, fp->scopeChain());
-        if (!ac.enter())
-            return false;
         env = GetDebugScopeForFrame(cx, fp);
         if (!env)
             return false;
     }
 
     return dbg->wrapEnvironment(cx, env, args.rval().address());
 }
 
@@ -3135,18 +3120,16 @@ DebuggerFrame_getConstructing(JSContext 
 
 static JSBool
 DebuggerFrame_getThis(JSContext *cx, unsigned argc, Value *vp)
 {
     THIS_FRAME(cx, argc, vp, "get this", args, thisobj, fp);
     Value thisv;
     {
         AutoCompartment ac(cx, fp->scopeChain());
-        if (!ac.enter())
-            return false;
         if (!ComputeThis(cx, fp))
             return false;
         thisv = fp->thisValue();
     }
     if (!Debugger::fromChildJSObject(thisobj)->wrapDebuggeeValue(cx, &thisv))
         return false;
     args.rval().set(thisv);
     return true;
@@ -3368,18 +3351,16 @@ DebuggerFrame_setOnStep(JSContext *cx, u
         return false;
     }
 
     Value prior = thisobj->getReservedSlot(JSSLOT_DEBUGFRAME_ONSTEP_HANDLER);
     int delta = !args[0].isUndefined() - !prior.isUndefined();
     if (delta != 0) {
         /* Try to adjust this frame's script single-step mode count. */
         AutoCompartment ac(cx, fp->scopeChain());
-        if (!ac.enter())
-            return false;
         if (!fp->script()->changeStepModeCount(cx, delta))
             return false;
     }
 
     /* Now that the step mode switch has succeeded, we can install the handler. */
     thisobj->setReservedSlot(JSSLOT_DEBUGFRAME_ONSTEP_HANDLER, args[0]);
     args.rval().setUndefined();
     return true;
@@ -3489,19 +3470,18 @@ DebuggerFrameEval(JSContext *cx, unsigne
             if (!JSObject::getGeneric(cx, bindingsobj, bindingsobj, keyp, valp) ||
                 !dbg->unwrapDebuggeeValue(cx, valp.address()))
             {
                 return false;
             }
         }
     }
 
-    AutoCompartment ac(cx, fp->scopeChain());
-    if (!ac.enter())
-        return false;
+    Maybe<AutoCompartment> ac;
+    ac.construct(cx, fp->scopeChain());
 
     Rooted<Env *> env(cx, GetDebugScopeForFrame(cx, fp));
     if (!env)
         return false;
 
     /* If evalWithBindings, create the inner environment. */
     if (mode == WithBindings) {
         /* TODO - This should probably be a Call object, like ES5 strict eval. */
@@ -3799,19 +3779,16 @@ DebuggerObject_getEnvironment(JSContext 
     if (!obj->isFunction() || !obj->toFunction()->isInterpreted()) {
         args.rval().setUndefined();
         return true;
     }
 
     Rooted<Env*> env(cx);
     {
         AutoCompartment ac(cx, obj);
-        if (!ac.enter())
-            return false;
-
         env = GetDebugScopeForFunction(cx, obj->toFunction());
         if (!env)
             return false;
     }
 
     return dbg->wrapEnvironment(cx, env, args.rval().address());
 }
 
@@ -3822,18 +3799,19 @@ DebuggerObject_getOwnPropertyDescriptor(
 
     RootedId id(cx);
     if (!ValueToId(cx, argc >= 1 ? args[0] : UndefinedValue(), id.address()))
         return false;
 
     /* Bug: This can cause the debuggee to run! */
     AutoPropertyDescriptorRooter desc(cx);
     {
-        AutoCompartment ac(cx, obj);
-        if (!ac.enter() || !cx->compartment->wrapId(cx, id.address()))
+        Maybe<AutoCompartment> ac;
+        ac.construct(cx, obj);
+        if (!cx->compartment->wrapId(cx, id.address()))
             return false;
 
         ErrorCopier ec(ac, dbg->toJSObject());
         if (!GetOwnPropertyDescriptor(cx, obj, id, &desc))
             return false;
     }
 
     if (desc.obj) {
@@ -3859,20 +3837,18 @@ DebuggerObject_getOwnPropertyDescriptor(
 
 static JSBool
 DebuggerObject_getOwnPropertyNames(JSContext *cx, unsigned argc, Value *vp)
 {
     THIS_DEBUGOBJECT_OWNER_REFERENT(cx, argc, vp, "getOwnPropertyNames", args, dbg, obj);
 
     AutoIdVector keys(cx);
     {
-        AutoCompartment ac(cx, obj);
-        if (!ac.enter())
-            return false;
-
+        Maybe<AutoCompartment> ac;
+        ac.construct(cx, obj);
         ErrorCopier ec(ac, dbg->toJSObject());
         if (!GetPropertyNames(cx, obj, JSITER_OWNONLY | JSITER_HIDDEN, &keys))
             return false;
     }
 
     AutoValueVector vals(cx);
     if (!vals.resize(keys.length()))
         return false;
@@ -3926,18 +3902,19 @@ DebuggerObject_defineProperty(JSContext 
         return false;
 
     {
         PropDesc *rewrappedDesc = descs.append();
         if (!rewrappedDesc)
             return false;
         RootedId wrappedId(cx);
 
-        AutoCompartment ac(cx, obj);
-        if (!ac.enter() || !unwrappedDesc->wrapInto(cx, obj, id, wrappedId.address(), rewrappedDesc))
+        Maybe<AutoCompartment> ac;
+        ac.construct(cx, obj);
+        if (!unwrappedDesc->wrapInto(cx, obj, id, wrappedId.address(), rewrappedDesc))
             return false;
 
         ErrorCopier ec(ac, dbg->toJSObject());
         bool dummy;
         if (!DefineProperty(cx, obj, wrappedId, *rewrappedDesc, true, &dummy))
             return false;
     }
 
@@ -3969,19 +3946,18 @@ DebuggerObject_defineProperties(JSContex
         if (!descs[i].unwrapDebuggerObjectsInto(cx, dbg, obj, &unwrappedDescs[i]))
             return false;
     }
 
     {
         AutoIdVector rewrappedIds(cx);
         AutoPropDescArrayRooter rewrappedDescs(cx);
 
-        AutoCompartment ac(cx, obj);
-        if (!ac.enter())
-            return false;
+        Maybe<AutoCompartment> ac;
+        ac.construct(cx, obj);
         for (size_t i = 0; i < n; i++) {
             if (!rewrappedIds.append(jsid()) || !rewrappedDescs.append())
                 return false;
             if (!unwrappedDescs[i].wrapInto(cx, obj, ids[i], &rewrappedIds[i], &rewrappedDescs[i]))
                 return false;
         }
 
         ErrorCopier ec(ac, dbg->toJSObject());
@@ -4004,35 +3980,34 @@ DebuggerObject_defineProperties(JSContex
  * property is non-configurable isn't necessarily exceptional here.
  */
 static JSBool
 DebuggerObject_deleteProperty(JSContext *cx, unsigned argc, Value *vp)
 {
     THIS_DEBUGOBJECT_OWNER_REFERENT(cx, argc, vp, "deleteProperty", args, dbg, obj);
     Value nameArg = argc > 0 ? args[0] : UndefinedValue();
 
-    AutoCompartment ac(cx, obj);
-    if (!ac.enter() || !cx->compartment->wrap(cx, &nameArg))
+    Maybe<AutoCompartment> ac;
+    ac.construct(cx, obj);
+    if (!cx->compartment->wrap(cx, &nameArg))
         return false;
 
     ErrorCopier ec(ac, dbg->toJSObject());
     return JSObject::deleteByValue(cx, obj, nameArg, args.rval(), false);
 }
 
 enum SealHelperOp { Seal, Freeze, PreventExtensions };
 
 static JSBool
 DebuggerObject_sealHelper(JSContext *cx, unsigned argc, Value *vp, SealHelperOp op, const char *name)
 {
     THIS_DEBUGOBJECT_OWNER_REFERENT(cx, argc, vp, name, args, dbg, obj);
 
-    AutoCompartment ac(cx, obj);
-    if (!ac.enter())
-        return false;
-
+    Maybe<AutoCompartment> ac;
+    ac.construct(cx, obj);
     ErrorCopier ec(ac, dbg->toJSObject());
     bool ok;
     if (op == Seal) {
         ok = JSObject::seal(cx, obj);
     } else if (op == Freeze) {
         ok = JSObject::freeze(cx, obj);
     } else {
         JS_ASSERT(op == PreventExtensions);
@@ -4067,20 +4042,18 @@ DebuggerObject_preventExtensions(JSConte
 }
 
 static JSBool
 DebuggerObject_isSealedHelper(JSContext *cx, unsigned argc, Value *vp, SealHelperOp op,
                               const char *name)
 {
     THIS_DEBUGOBJECT_OWNER_REFERENT(cx, argc, vp, name, args, dbg, obj);
 
-    AutoCompartment ac(cx, obj);
-    if (!ac.enter())
-        return false;
-
+    Maybe<AutoCompartment> ac;
+    ac.construct(cx, obj);
     ErrorCopier ec(ac, dbg->toJSObject());
     bool r;
     if (op == Seal) {
         if (!JSObject::isSealed(cx, obj, &r))
             return false;
     } else if (op == Freeze) {
         if (!JSObject::isFrozen(cx, obj, &r))
             return false;
@@ -4160,18 +4133,19 @@ ApplyOrCall(JSContext *cx, unsigned argc
         if (!dbg->unwrapDebuggeeValue(cx, &callArgv[i]))
             return false;
     }
 
     /*
      * Enter the debuggee compartment and rewrap all input value for that compartment.
      * (Rewrapping always takes place in the destination compartment.)
      */
-    AutoCompartment ac(cx, obj);
-    if (!ac.enter() || !cx->compartment->wrap(cx, &calleev) || !cx->compartment->wrap(cx, &thisv))
+    Maybe<AutoCompartment> ac;
+    ac.construct(cx, obj);
+    if (!cx->compartment->wrap(cx, &calleev) || !cx->compartment->wrap(cx, &thisv))
         return false;
     for (unsigned i = 0; i < callArgc; i++) {
         if (!cx->compartment->wrap(cx, &callArgv[i]))
             return false;
     }
 
     /*
      * Call the function. Use receiveCompletionValue to return to the debugger
@@ -4201,18 +4175,17 @@ DebuggerObject_makeDebuggeeValue(JSConte
     THIS_DEBUGOBJECT_OWNER_REFERENT(cx, argc, vp, "makeDebuggeeValue", args, dbg, referent);
 
     /* Non-objects are already debuggee values. */
     if (args[0].isObject()) {
         // Enter this Debugger.Object's referent's compartment, and wrap the
         // argument as appropriate for references from there.
         {
             AutoCompartment ac(cx, referent);
-            if (!ac.enter() ||
-                !cx->compartment->wrap(cx, &args[0]))
+            if (!cx->compartment->wrap(cx, &args[0]))
                 return false;
         }
 
         // Back in the debugger's compartment, produce a new Debugger.Object
         // instance referring to the wrapped argument.
         if (!dbg->wrapDebuggeeValue(cx, &args[0]))
             return false;
     }
@@ -4425,20 +4398,18 @@ DebuggerEnv_getCallee(JSContext *cx, uns
 
 static JSBool
 DebuggerEnv_names(JSContext *cx, unsigned argc, Value *vp)
 {
     THIS_DEBUGENV_OWNER(cx, argc, vp, "names", args, envobj, env, dbg);
 
     AutoIdVector keys(cx);
     {
-        AutoCompartment ac(cx, env);
-        if (!ac.enter())
-            return false;
-
+        Maybe<AutoCompartment> ac;
+        ac.construct(cx, env);
         ErrorCopier ec(ac, dbg->toJSObject());
         if (!GetPropertyNames(cx, env, JSITER_HIDDEN, &keys))
             return false;
     }
 
     RootedObject arr(cx, NewDenseEmptyArray(cx));
     if (!arr)
         return false;
@@ -4461,18 +4432,19 @@ DebuggerEnv_find(JSContext *cx, unsigned
     REQUIRE_ARGC("Debugger.Environment.find", 1);
     THIS_DEBUGENV_OWNER(cx, argc, vp, "find", args, envobj, env, dbg);
 
     RootedId id(cx);
     if (!ValueToIdentifier(cx, args[0], id.address()))
         return false;
 
     {
-        AutoCompartment ac(cx, env);
-        if (!ac.enter() || !cx->compartment->wrapId(cx, id.address()))
+        Maybe<AutoCompartment> ac;
+        ac.construct(cx, env);
+        if (!cx->compartment->wrapId(cx, id.address()))
             return false;
 
         /* This can trigger resolve hooks. */
         ErrorCopier ec(ac, dbg->toJSObject());
         RootedShape prop(cx);
         RootedObject pobj(cx);
         for (; env && !prop; env = env->enclosingScope()) {
             if (!JSObject::lookupGeneric(cx, env, id, &pobj, &prop))
@@ -4492,18 +4464,19 @@ DebuggerEnv_getVariable(JSContext *cx, u
     THIS_DEBUGENV_OWNER(cx, argc, vp, "getVariable", args, envobj, env, dbg);
 
     RootedId id(cx);
     if (!ValueToIdentifier(cx, args[0], id.address()))
         return false;
 
     RootedValue v(cx);
     {
-        AutoCompartment ac(cx, env);
-        if (!ac.enter() || !cx->compartment->wrapId(cx, id.address()))
+        Maybe<AutoCompartment> ac;
+        ac.construct(cx, env);
+        if (!cx->compartment->wrapId(cx, id.address()))
             return false;
 
         /* This can trigger getters. */
         ErrorCopier ec(ac, dbg->toJSObject());
         if (!JSObject::getGeneric(cx, env, env, id, &v))
             return false;
     }
 
@@ -4523,23 +4496,20 @@ DebuggerEnv_setVariable(JSContext *cx, u
     if (!ValueToIdentifier(cx, args[0], id.address()))
         return false;
 
     RootedValue v(cx, args[1]);
     if (!dbg->unwrapDebuggeeValue(cx, v.address()))
         return false;
 
     {
-        AutoCompartment ac(cx, env);
-        if (!ac.enter() ||
-            !cx->compartment->wrapId(cx, id.address()) ||
-            !cx->compartment->wrap(cx, v.address()))
-        {
+        Maybe<AutoCompartment> ac;
+        ac.construct(cx, env);
+        if (!cx->compartment->wrapId(cx, id.address()) || !cx->compartment->wrap(cx, v.address()))
             return false;
-        }
 
         /* This can trigger setters. */
         ErrorCopier ec(ac, dbg->toJSObject());
 
         /* Make sure the environment actually has the specified binding. */
         bool has;
         if (!JSObject::hasProperty(cx, env, id, &has))
             return false;
--- a/js/src/vm/Debugger.h
+++ b/js/src/vm/Debugger.h
@@ -102,17 +102,17 @@ class Debugger {
      *
      * If there is no uncaughtExceptionHook, or if it fails, report and clear
      * the pending exception on ac.context and return JSTRAP_ERROR.
      *
      * This always calls ac.leave(); ac is a parameter because this method must
      * do some things in the debugger compartment and some things in the
      * debuggee compartment.
      */
-    JSTrapStatus handleUncaughtException(AutoCompartment &ac, Value *vp, bool callHook);
+    JSTrapStatus handleUncaughtException(Maybe<AutoCompartment> &ac, Value *vp, bool callHook);
 
     /*
      * Handle the result of a hook that is expected to return a resumption
      * value <https://wiki.mozilla.org/Debugger#Resumption_Values>. This is called
      * when we return from a debugging hook to debuggee code. The interpreter wants
      * a (JSTrapStatus, Value) pair telling it how to proceed.
      *
      * Precondition: ac is entered. We are in the debugger compartment.
@@ -129,18 +129,18 @@ class Debugger {
      *         unwrap value. Store the result in *vp and return JSTRAP_RETURN
      *         or JSTRAP_THROW. The interpreter will force the current frame to
      *         return or throw an exception.
      *     null - Return JSTRAP_ERROR to terminate the debuggee with an
      *         uncatchable error.
      *     anything else - Make a new TypeError the pending exception and
      *         return handleUncaughtException(ac, vp, callHook).
      */
-    JSTrapStatus parseResumptionValue(AutoCompartment &ac, bool ok, const Value &rv, Value *vp,
-                                      bool callHook = true);
+    JSTrapStatus parseResumptionValue(Maybe<AutoCompartment> &ac, bool ok, const Value &rv,
+                                      Value *vp, bool callHook = true);
 
     JSObject *unwrapDebuggeeArgument(JSContext *cx, const Value &v);
 
     static void traceObject(JSTracer *trc, JSObject *obj);
     void trace(JSTracer *trc);
     static void finalize(FreeOp *fop, JSObject *obj);
     void markKeysInCompartment(JSTracer *tracer);
 
@@ -325,17 +325,17 @@ class Debugger {
      *
      * Postcondition: we are in the debugger compartment, having called
      * ac.leave() even if an error occurred.
      *
      * On success, a completion value is in vp and ac.context does not have a
      * pending exception. (This ordinarily returns true even if the ok argument
      * is false.)
      */
-    bool receiveCompletionValue(AutoCompartment &ac, bool ok, Value val, Value *vp);
+    bool receiveCompletionValue(Maybe<AutoCompartment> &ac, bool ok, Value val, Value *vp);
 
     /*
      * Return the Debugger.Script object for |script|, or create a new one if
      * needed. The context |cx| must be in the debugger compartment; |script|
      * must be a script in a debuggee compartment.
      */
     JSObject *wrapScript(JSContext *cx, HandleScript script);
 
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -888,17 +888,16 @@ ContextStack::ensureOnTop(JSContext *cx,
                 JSFunction *f = fp->fun();
                 if (f->isInterpreted())
                     fun = f;
             }
         }
 
         if (fun) {
             AutoCompartment ac(cx, fun);
-            (void) ac.enter();
             fun->script()->uninlineable = true;
             types::MarkTypeObjectFlags(cx, fun, types::OBJECT_FLAG_UNINLINEABLE);
         }
     }
     JS_ASSERT_IF(cx->hasfp(), !cx->regs().inlined());
 #endif
 
     if (onTop() && extend) {
--- a/js/xpconnect/loader/mozJSComponentLoader.cpp
+++ b/js/xpconnect/loader/mozJSComponentLoader.cpp
@@ -500,19 +500,17 @@ mozJSComponentLoader::LoadModule(FileLoc
         return NULL;
 
     nsCOMPtr<nsIComponentManager> cm;
     rv = NS_GetComponentManager(getter_AddRefs(cm));
     if (NS_FAILED(rv))
         return NULL;
 
     JSCLContextHelper cx(this);
-    JSAutoEnterCompartment ac;
-    if (!ac.enter(cx, entry->global))
-        return NULL;
+    JSAutoCompartment ac(cx, entry->global);
 
     JSObject* cm_jsobj;
     nsCOMPtr<nsIXPConnectJSObjectHolder> cm_holder;
     rv = xpc->WrapNative(cx, entry->global, cm,
                          NS_GET_IID(nsIComponentManager),
                          getter_AddRefs(cm_holder));
 
     if (NS_FAILED(rv)) {
@@ -650,20 +648,17 @@ mozJSComponentLoader::GlobalForLocation(
                                               0,
                                               getter_AddRefs(holder));
     NS_ENSURE_SUCCESS(rv, rv);
 
     JSObject *global;
     rv = holder->GetJSObject(&global);
     NS_ENSURE_SUCCESS(rv, rv);
 
-    JSAutoEnterCompartment ac;
-    if (!ac.enter(cx, global))
-        return NS_ERROR_FAILURE;
-
+    JSAutoCompartment ac(cx, global);
     if (!JS_DefineFunctions(cx, global, gGlobalFun) ||
         !JS_DefineProfilingFunctions(cx, global)) {
         return NS_ERROR_FAILURE;
     }
 
     bool realFile = false;
     // need to be extra careful checking for URIs pointing to files
     // EnsureFile may not always get called, especially on resource URIs
@@ -1031,20 +1026,19 @@ mozJSComponentLoader::Import(const nsACS
         if (!targetObject) {
             NS_ERROR("null calling object");
             return NS_ERROR_FAILURE;
         }
 
         targetObject = JS_GetGlobalForObject(cx, targetObject);
     }
 
-    JSAutoEnterCompartment ac;
-    if (targetObject && !ac.enter(cx, targetObject)) {
-        NS_ERROR("can't enter compartment");
-        return NS_ERROR_FAILURE;
+    Maybe<JSAutoCompartment> ac;
+    if (targetObject) {
+        ac.construct(cx, targetObject);
     }
 
     JSObject *globalObj = nullptr;
     nsresult rv = ImportInto(registryLocation, targetObject, cx, &globalObj);
 
     if (globalObj && !JS_WrapObject(cx, &globalObj)) {
         NS_ERROR("can't wrap return value");
         return NS_ERROR_FAILURE;
@@ -1166,20 +1160,17 @@ mozJSComponentLoader::ImportInto(const n
         mod = newEntry;
     }
 
     NS_ASSERTION(mod->global, "Import table contains entry with no global");
     *_retval = mod->global;
 
     if (targetObj) {
         JSCLContextHelper cxhelper(this);
-
-        JSAutoEnterCompartment ac;
-        if (!ac.enter(mContext, mod->global))
-            return NS_ERROR_FAILURE;
+        JSAutoCompartment ac(mContext, mod->global);
 
         JS::Value symbols;
         if (!JS_GetProperty(mContext, mod->global,
                             "EXPORTED_SYMBOLS", &symbols)) {
             return ReportOnCaller(cxhelper, ERROR_NOT_PRESENT,
                                   PromiseFlatCString(aLocation).get());
         }
 
@@ -1218,20 +1209,19 @@ mozJSComponentLoader::ImportInto(const n
                 JSAutoByteString bytes(mContext, JSID_TO_STRING(symbolId));
                 if (!bytes)
                     return NS_ERROR_FAILURE;
                 return ReportOnCaller(cxhelper, ERROR_GETTING_SYMBOL,
                                       PromiseFlatCString(aLocation).get(),
                                       bytes.ptr());
             }
 
-            JSAutoEnterCompartment target_ac;
+            JSAutoCompartment target_ac(mContext, targetObj);
 
-            if (!target_ac.enter(mContext, targetObj) ||
-                !JS_WrapValue(mContext, &val) ||
+            if (!JS_WrapValue(mContext, &val) ||
                 !JS_SetPropertyById(mContext, targetObj, symbolId, &val)) {
                 JSAutoByteString bytes(mContext, JSID_TO_STRING(symbolId));
                 if (!bytes)
                     return NS_ERROR_FAILURE;
                 return ReportOnCaller(cxhelper, ERROR_SETTING_SYMBOL,
                                       PromiseFlatCString(aLocation).get(),
                                       bytes.ptr());
             }
--- a/js/xpconnect/loader/mozJSComponentLoader.h
+++ b/js/xpconnect/loader/mozJSComponentLoader.h
@@ -93,18 +93,17 @@ class mozJSComponentLoader : public mozi
         }
 
         void Clear() {
             getfactoryobj = NULL;
 
             if (global) {
                 JSAutoRequest ar(sSelf->mContext);
 
-                JSAutoEnterCompartment ac;
-                ac.enterAndIgnoreErrors(sSelf->mContext, global);
+                JSAutoCompartment ac(sSelf->mContext, global);
 
                 JS_ClearScope(sSelf->mContext, global);
                 JS_RemoveObjectRoot(sSelf->mContext, &global);
             }
 
             if (location)
                 NS_Free(location);
 
--- a/js/xpconnect/loader/mozJSSubScriptLoader.cpp
+++ b/js/xpconnect/loader/mozJSSubScriptLoader.cpp
@@ -212,19 +212,17 @@ mozJSSubScriptLoader::LoadSubScript(cons
             do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
         if (!secman)
             return NS_ERROR_FAILURE;
 
         rv = secman->GetObjectPrincipal(cx, targetObj, getter_AddRefs(principal));
         NS_ENSURE_SUCCESS(rv, rv);
     }
 
-    JSAutoEnterCompartment ac;
-    if (!ac.enter(cx, targetObj))
-        return NS_ERROR_UNEXPECTED;
+    JSAutoCompartment ac(cx, targetObj);
 
     /* load up the url.  From here on, failures are reflected as ``custom''
      * js exceptions */
     nsCOMPtr<nsIURI> uri;
     nsCAutoString uriStr;
     nsCAutoString scheme;
 
     JSScript* script = nullptr;
@@ -295,18 +293,18 @@ mozJSSubScriptLoader::LoadSubScript(cons
     }
 
     if (NS_FAILED(rv) || !script)
         return rv;
 
     bool ok = JS_ExecuteScriptVersion(cx, targetObj, script, retval, version);
 
     if (ok) {
-        JSAutoEnterCompartment rac;
-        if (!rac.enter(cx, result_obj) || !JS_WrapValue(cx, retval))
+        JSAutoCompartment rac(cx, result_obj);
+        if (!JS_WrapValue(cx, retval))
             return NS_ERROR_UNEXPECTED;
     }
 
     if (cache && ok && writeScript) {
         WriteCachedScript(cache, cachePath, cx, mSystemPrincipal, script);
     }
 
     return NS_OK;
--- a/js/xpconnect/shell/xpcshell.cpp
+++ b/js/xpconnect/shell/xpcshell.cpp
@@ -1871,21 +1871,17 @@ main(int argc, char **argv, char **envp)
         rv = holder->GetJSObject(&glob);
         if (NS_FAILED(rv)) {
             NS_ASSERTION(glob == nullptr, "bad GetJSObject?");
             return 1;
         }
 
         JS_BeginRequest(cx);
         {
-            JSAutoEnterCompartment ac;
-            if (!ac.enter(cx, glob)) {
-                JS_EndRequest(cx);
-                return 1;
-            }
+            JSAutoCompartment ac(cx, glob);
 
             if (!JS_InitReflect(cx, glob)) {
                 JS_EndRequest(cx);
                 return 1;
             }
 
             if (!JS_DefineFunctions(cx, glob, glob_functions) ||
                 !JS_DefineProfilingFunctions(cx, glob)) {
--- a/js/xpconnect/src/XPCComponents.cpp
+++ b/js/xpconnect/src/XPCComponents.cpp
@@ -2714,19 +2714,17 @@ nsXPCComponents_Utils::LookupMethod(cons
     if (js::IsCrossCompartmentWrapper(obj)) {
         obj = js::UnwrapOneChecked(cx, obj);
         if (!obj)
             return NS_ERROR_XPC_BAD_CONVERT_JS;
     }
 
     {
         // Enter the target compartment.
-        JSAutoEnterCompartment ac;
-        if (!ac.enter(cx, obj))
-            return NS_ERROR_FAILURE;
+        JSAutoCompartment ac(cx, obj);
 
         // Morph slim wrappers.
         if (IS_SLIM_WRAPPER(obj) && !MorphSlimWrapper(cx, obj))
             return NS_ERROR_FAILURE;
 
         // Now, try to create an Xray wrapper around the object. This won't work
         // if the object isn't Xray-able. In that case, we throw.
         JSObject *xray = WrapperFactory::WrapForSameCompartmentXray(cx, obj);
@@ -2911,20 +2909,17 @@ SandboxImport(JSContext *cx, unsigned ar
         argv[1] = STRING_TO_JSVAL(funname);
     } else {
         // NB: funobj must only be used to get the JSFunction out.
         JSObject *funobj = JSVAL_TO_OBJECT(argv[0]);
         if (js::IsProxy(funobj)) {
             funobj = XPCWrapper::UnsafeUnwrapSecurityWrapper(funobj);
         }
 
-        JSAutoEnterCompartment ac;
-        if (!ac.enter(cx, funobj)) {
-            return false;
-        }
+        JSAutoCompartment ac(cx, funobj);
 
         JSFunction *fun = JS_ValueToFunction(cx, OBJECT_TO_JSVAL(funobj));
         if (!fun) {
             XPCThrower::Throw(NS_ERROR_INVALID_ARG, cx);
             return false;
         }
 
         // Use the actual function name as the name.
@@ -3268,19 +3263,17 @@ xpc_CreateSandboxObject(JSContext *cx, j
     nsRefPtr<Identity> identity = new Identity();
     rv = xpc_CreateGlobalObject(cx, &SandboxClass, principal, identity,
                                 options.wantXrays, &sandbox, &compartment);
     NS_ENSURE_SUCCESS(rv, rv);
 
     JS::AutoObjectRooter tvr(cx, sandbox);
 
     {
-        JSAutoEnterCompartment ac;
-        if (!ac.enter(cx, sandbox))
-            return NS_ERROR_XPC_UNEXPECTED;
+        JSAutoCompartment ac(cx, sandbox);
 
         if (options.proto) {
             bool ok = JS_WrapObject(cx, &options.proto);
             if (!ok)
                 return NS_ERROR_XPC_UNEXPECTED;
 
             if (xpc::WrapperFactory::IsXrayWrapper(options.proto) && !options.wantXrays) {
                 jsval v = OBJECT_TO_JSVAL(options.proto);
@@ -3311,19 +3304,17 @@ xpc_CreateSandboxObject(JSContext *cx, j
         // Pass on ownership of sop to |sandbox|.
         JS_SetPrivate(sandbox, sop.forget().get());
 
         XPCCallContext ccx(NATIVE_CALLER, cx);
         if (!ccx.IsValid())
             return NS_ERROR_XPC_UNEXPECTED;
 
         {
-          JSAutoEnterCompartment ac;
-          if (!ac.enter(ccx, sandbox))
-              return NS_ERROR_XPC_UNEXPECTED;
+          JSAutoCompartment ac(ccx, sandbox);
           XPCWrappedNativeScope* scope =
               XPCWrappedNativeScope::GetNewOrUsed(ccx, sandbox);
 
           if (!scope)
               return NS_ERROR_XPC_UNEXPECTED;
 
           if (options.wantComponents &&
               !nsXPCComponents::AttachComponentsObject(ccx, scope, sandbox))
@@ -3915,23 +3906,17 @@ xpc_EvalInSandbox(JSContext *cx, JSObjec
         JS_ReportError(cx, "Unable to initialize XPConnect with the sandbox context");
         return NS_ERROR_FAILURE;
     }
 
     nsresult rv = NS_OK;
 
     {
         JSAutoRequest req(sandcx->GetJSContext());
-        JSAutoEnterCompartment ac;
-
-        if (!ac.enter(sandcx->GetJSContext(), sandbox)) {
-            if (stack)
-                unused << stack->Pop();
-            return NS_ERROR_FAILURE;
-        }
+        JSAutoCompartment ac(sandcx->GetJSContext(), sandbox);
 
         jsval v;
         JSString *str = nullptr;
         JSBool ok =
             JS_EvaluateUCScriptForPrincipals(sandcx->GetJSContext(), sandbox,
                                              nsJSPrincipals::get(prin),
                                              reinterpret_cast<const jschar *>
                                                              (PromiseFlatString(source).get()),
@@ -3978,24 +3963,24 @@ xpc_EvalInSandbox(JSContext *cx, JSObjec
                 // Clear str so we don't confuse callers.
                 str = nullptr;
             } else {
                 rv = NS_ERROR_OUT_OF_MEMORY;
             }
         } else {
             // Convert the result into something safe for our caller.
             JSAutoRequest req(cx);
-            JSAutoEnterCompartment ac;
+            JSAutoCompartment ac(cx, callingScope);
+
             if (str) {
                 v = STRING_TO_JSVAL(str);
             }
 
             CompartmentPrivate *sandboxdata = GetCompartmentPrivate(sandbox);
-            if (!ac.enter(cx, callingScope) ||
-                !WrapForSandbox(cx, sandboxdata->wantXrays, &v)) {
+            if (!WrapForSandbox(cx, sandboxdata->wantXrays, &v)) {
                 rv = NS_ERROR_FAILURE;
             }
 
             if (NS_SUCCEEDED(rv)) {
                 *rval = v;
             }
         }
     }
@@ -4166,19 +4151,17 @@ nsXPCComponents_Utils::GetGlobalForObjec
   // Wrappers are parented to their the global in their home compartment. But
   // when getting the global for a cross-compartment wrapper, we really want
   // a wrapper for the foreign global. So we need to unwrap before getting the
   // parent, enter the compartment for the duration of the call, and wrap the
   // result.
   JS::Rooted<JSObject*> obj(cx, JSVAL_TO_OBJECT(object));
   obj = js::UnwrapObject(obj);
   {
-    JSAutoEnterCompartment ac;
-    if (!ac.enter(cx, obj))
-      return NS_ERROR_FAILURE;
+    JSAutoCompartment ac(cx, obj);
     obj = JS_GetGlobalForObject(cx, obj);
   }
   JS_WrapObject(cx, obj.address());
   *retval = OBJECT_TO_JSVAL(obj);
 
   // Outerize if necessary.
   if (JSObjectOp outerize = js::GetObjectClass(obj)->ext.outerObject)
       *retval = OBJECT_TO_JSVAL(outerize(cx, obj));
@@ -4195,20 +4178,17 @@ nsXPCComponents_Utils::CreateObjectIn(co
 
     // first argument must be an object
     if (JSVAL_IS_PRIMITIVE(vobj))
         return NS_ERROR_XPC_BAD_CONVERT_JS;
 
     JSObject *scope = js::UnwrapObject(JSVAL_TO_OBJECT(vobj));
     JSObject *obj;
     {
-        JSAutoEnterCompartment ac;
-        if (!ac.enter(cx, scope))
-            return NS_ERROR_FAILURE;
-
+        JSAutoCompartment ac(cx, scope);
         obj = JS_NewObject(cx, nullptr, nullptr, scope);
         if (!obj)
             return NS_ERROR_FAILURE;
     }
 
     if (!JS_WrapObject(cx, &obj))
         return NS_ERROR_FAILURE;
     *rval = OBJECT_TO_JSVAL(obj);
@@ -4224,20 +4204,17 @@ nsXPCComponents_Utils::CreateArrayIn(con
 
     // first argument must be an object
     if (JSVAL_IS_PRIMITIVE(vobj))
         return NS_ERROR_XPC_BAD_CONVERT_JS;
 
     JSObject *scope = js::UnwrapObject(JSVAL_TO_OBJECT(vobj));
     JSObject *obj;
     {
-        JSAutoEnterCompartment ac;
-        if (!ac.enter(cx, scope))
-            return NS_ERROR_FAILURE;
-
+        JSAutoCompartment ac(cx, scope);
         obj =  JS_NewArrayObject(cx, 0, NULL);
         if (!obj)
             return NS_ERROR_FAILURE;
     }
 
     if (!JS_WrapObject(cx, &obj))
         return NS_ERROR_FAILURE;
     *rval = OBJECT_TO_JSVAL(obj);
@@ -4280,20 +4257,17 @@ nsXPCComponents_Utils::MakeObjectPropsNo
         return NS_ERROR_FAILURE;
 
     // first argument must be an object
     if (JSVAL_IS_PRIMITIVE(vobj))
         return NS_ERROR_XPC_BAD_CONVERT_JS;
 
     JSObject *obj = js::UnwrapObject(JSVAL_TO_OBJECT(vobj));
 
-    JSAutoEnterCompartment ac;
-    if (!ac.enter(cx, obj))
-        return NS_ERROR_FAILURE;
-
+    JSAutoCompartment ac(cx, obj);
     JS::AutoIdArray ida(cx, JS_Enumerate(cx, obj));
     if (!ida)
         return NS_ERROR_FAILURE;
 
     for (size_t i = 0; i < ida.length(); ++i) {
         jsid id = ida[i];
         jsval v;
 
@@ -4347,21 +4321,24 @@ nsXPCComponents_Utils::RecomputeWrappers
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsXPCComponents_Utils::Dispatch(const jsval &runnable_, const jsval &scope,
                                 JSContext *cx)
 {
     // Enter the given compartment, if any, and rewrap runnable.
-    JSAutoEnterCompartment ac;
+    Maybe<JSAutoCompartment> ac;
     js::Value runnable = runnable_;
     if (scope.isObject()) {
         JSObject *scopeObj = js::UnwrapObject(&scope.toObject());
-        if (!scopeObj || !ac.enter(cx, scopeObj) || !JS_WrapValue(cx, &runnable))
+        if (!scopeObj)
+            return NS_ERROR_FAILURE;
+        ac.construct(cx, scopeObj);
+        if (!JS_WrapValue(cx, &runnable))
             return NS_ERROR_FAILURE;
     }
 
     // Get an XPCWrappedJS for |runnable|.
     if (!runnable.isObject())
         return NS_ERROR_INVALID_ARG;
     nsCOMPtr<nsIRunnable> run;
     nsresult rv = nsXPConnect::GetXPConnect()->WrapJS(cx, &runnable.toObject(),
--- a/js/xpconnect/src/XPCConvert.cpp
+++ b/js/xpconnect/src/XPCConvert.cpp
@@ -1010,24 +1010,17 @@ XPCConvert::JSObject2NativeInterface(XPC
                                      nsISupports* aOuter,
                                      nsresult* pErr)
 {
     NS_ASSERTION(dest, "bad param");
     NS_ASSERTION(src, "bad param");
     NS_ASSERTION(iid, "bad param");
 
     JSContext* cx = ccx.GetJSContext();
-
-    JSAutoEnterCompartment ac;
-
-    if (!ac.enter(cx, src)) {
-       if (pErr)
-           *pErr = NS_ERROR_UNEXPECTED;
-       return false;
-    }
+    JSAutoCompartment ac(cx, src);
 
     *dest = nullptr;
      if (pErr)
         *pErr = NS_ERROR_XPC_BAD_CONVERT_JS;
 
     nsISupports* iface;
 
     if (!aOuter) {
--- a/js/xpconnect/src/XPCDebug.cpp
+++ b/js/xpconnect/src/XPCDebug.cpp
@@ -72,19 +72,17 @@ static char* FormatJSFrame(JSContext* cx
     JSBool isString;
 
     // get the info for this stack frame
 
     JSScript* script = JS_GetFrameScript(cx, fp);
     jsbytecode* pc = JS_GetFramePC(cx, fp);
 
     JSAutoRequest ar(cx);
-    JSAutoEnterCompartment ac;
-    if (!ac.enter(cx, JS_GetGlobalForFrame(fp)))
-        return buf;
+    JSAutoCompartment ac(cx, JS_GetGlobalForFrame(fp));
 
     if (script && pc) {
         filename = JS_GetScriptFilename(cx, script);
         lineno =  (int32_t) JS_PCToLineNumber(cx, script, pc);
         fun = JS_GetFrameFunction(cx, fp);
         if (fun)
             funname = JS_GetFunctionId(fun);
 
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -1853,37 +1853,32 @@ class XPCJSRuntimeStats : public JS::Run
         GetCompartmentName(c, cName, true);
 
         // Get the compartment's global.
         nsXPConnect *xpc = nsXPConnect::GetXPConnect();
         JSContext *cx = xpc->GetSafeJSContext();
         if (JSObject *global = JS_GetGlobalForCompartmentOrNull(cx, c)) {
             // Need to enter the compartment, otherwise GetNativeOfWrapper()
             // might crash.
-            JSAutoEnterCompartment aec;
-            if (aec.enter(cx, global)) {
-                nsISupports *native = xpc->GetNativeOfWrapper(cx, global);
-                if (nsCOMPtr<nsPIDOMWindow> piwindow = do_QueryInterface(native)) {
-                    // The global is a |window| object.  Use the path prefix that
-                    // we should have already created for it.
-                    if (mWindowPaths->Get(piwindow->WindowID(), &cJSPathPrefix)) {
-                        cDOMPathPrefix.Assign(cJSPathPrefix);
-                        cDOMPathPrefix.AppendLiteral("/dom/");
-                        cJSPathPrefix.AppendLiteral("/js/");
-                    } else {
-                        cJSPathPrefix.AssignLiteral("explicit/js-non-window/compartments/unknown-window-global/");
-                        cDOMPathPrefix.AssignLiteral("explicit/dom/?!/");
-                    }
+            JSAutoCompartment ac(cx, global);
+            nsISupports *native = xpc->GetNativeOfWrapper(cx, global);
+            if (nsCOMPtr<nsPIDOMWindow> piwindow = do_QueryInterface(native)) {
+                // The global is a |window| object.  Use the path prefix that
+                // we should have already created for it.
+                if (mWindowPaths->Get(piwindow->WindowID(), &cJSPathPrefix)) {
+                    cDOMPathPrefix.Assign(cJSPathPrefix);
+                    cDOMPathPrefix.AppendLiteral("/dom/");
+                    cJSPathPrefix.AppendLiteral("/js/");
                 } else {
-                    cJSPathPrefix.AssignLiteral("explicit/js-non-window/compartments/non-window-global/");
+                    cJSPathPrefix.AssignLiteral("explicit/js-non-window/compartments/unknown-window-global/");
                     cDOMPathPrefix.AssignLiteral("explicit/dom/?!/");
                 }
             } else {
-                cJSPathPrefix.AssignLiteral("explicit/js-non-window/compartments/unentered/");
-                cDOMPathPrefix.AssignLiteral("explicit/dom/unentered/");
+                cJSPathPrefix.AssignLiteral("explicit/js-non-window/compartments/non-window-global/");
+                cDOMPathPrefix.AssignLiteral("explicit/dom/?!/");
             }
         } else {
             cJSPathPrefix.AssignLiteral("explicit/js-non-window/compartments/no-global/");
             cDOMPathPrefix.AssignLiteral("explicit/dom/?!/");
         }
 
         cJSPathPrefix += NS_LITERAL_CSTRING("compartment(") + cName + NS_LITERAL_CSTRING(")/");
 
--- a/js/xpconnect/src/XPCWrappedJSClass.cpp
+++ b/js/xpconnect/src/XPCWrappedJSClass.cpp
@@ -31,18 +31,17 @@ bool AutoScriptEvaluate::StartEvaluating
 
     mEvaluated = true;
     if (!JS_GetErrorReporter(mJSContext)) {
         JS_SetErrorReporter(mJSContext, errorReporter);
         mErrorReporterSet = true;
     }
 
     JS_BeginRequest(mJSContext);
-    if (!mEnterCompartment.enter(mJSContext, scope))
-        return false;
+    mAutoCompartment.construct(mJSContext, scope);
 
     // Saving the exception state keeps us from interfering with another script
     // that may also be running on this context.  This occurred first with the
     // js debugger, as described in
     // http://bugzilla.mozilla.org/show_bug.cgi?id=88130 but presumably could
     // show up in any situation where a script calls into a wrapped js component
     // on the same context, while the context has a nonzero exception state.
     // Because JS_SaveExceptionState/JS_RestoreExceptionState use malloc
@@ -499,19 +498,17 @@ GetContextFromObject(JSObject *obj)
     if (stack && stack->Peek())
         return nullptr;
 
     // In order to get a context, we need a context.
     XPCCallContext ccx(NATIVE_CALLER);
     if (!ccx.IsValid())
         return nullptr;
 
-    JSAutoEnterCompartment ac;
-    if (!ac.enter(ccx, obj))
-        return nullptr;
+    JSAutoCompartment ac(ccx, obj);
     XPCWrappedNativeScope* scope =
         XPCWrappedNativeScope::FindInJSObjectScope(ccx, obj);
     XPCContext *xpcc = scope->GetContext();
 
     if (xpcc) {
         JSContext *cx = xpcc->GetJSContext();
         JS_AbortIfWrongThread(JS_GetRuntime(cx));
         return cx;
@@ -1142,20 +1139,17 @@ nsXPCWrappedJSClass::CallMethod(nsXPCWra
     JSContext *cx = xpc_UnmarkGrayContext(ccx.GetJSContext());
 
     if (!cx || !xpcc || !IsReflectable(methodIndex))
         return NS_ERROR_FAILURE;
 
     JSObject *obj = wrapper->GetJSObject();
     JSObject *thisObj = obj;
 
-    JSAutoEnterCompartment ac;
-    if (!ac.enter(cx, obj))
-        return NS_ERROR_FAILURE;
-
+    JSAutoCompartment ac(cx, obj);
     ccx.SetScopeForNewJSObjects(obj);
 
     JS::AutoValueVector args(cx);
     AutoScriptEvaluate scriptEval(cx);
 
     // XXX ASSUMES that retval is last arg. The xpidl compiler ensures this.
     uint8_t paramCount = info->num_args;
     uint8_t argc = paramCount -
--- a/js/xpconnect/src/XPCWrappedNative.cpp
+++ b/js/xpconnect/src/XPCWrappedNative.cpp
@@ -318,19 +318,17 @@ XPCWrappedNative::WrapNewGlobal(XPCCallC
     JSObject *global;
     JSCompartment *compartment;
     rv = xpc_CreateGlobalObject(ccx, clasp, principal, nullptr, false,
                                 &global, &compartment);
     NS_ENSURE_SUCCESS(rv, rv);
 
     // Immediately enter the global's compartment, so that everything else we
     // create ends up there.
-    JSAutoEnterCompartment ac;
-    success = ac.enter(ccx, global);
-    MOZ_ASSERT(success);
+    JSAutoCompartment ac(ccx, global);
 
     // If requested, immediately initialize the standard classes on the global.
     // We need to do this before creating a scope, because
     // XPCWrappedNativeScope::SetGlobal resolves |Object| via
     // JS_ResolveStandardClass. JS_InitStandardClasses asserts if any of the
     // standard classes are already initialized, so this is a problem.
     if (initStandardClasses && ! JS_InitStandardClasses(ccx, global))
         return NS_ERROR_FAILURE;
@@ -514,34 +512,33 @@ XPCWrappedNative::GetNewOrUsed(XPCCallCo
     JSObject* parent = Scope->GetGlobalJSObject();
 
     jsval newParentVal = JSVAL_NULL;
     XPCMarkableJSVal newParentVal_markable(&newParentVal);
     AutoMarkingJSVal newParentVal_automarker(ccx, &newParentVal_markable);
     JSBool needsSOW = false;
     JSBool needsCOW = false;
 
-    JSAutoEnterCompartment ac;
+    mozilla::Maybe<JSAutoCompartment> ac;
 
     if (sciWrapper.GetFlags().WantPreCreate()) {
         JSObject* plannedParent = parent;
         nsresult rv = sciWrapper.GetCallback()->PreCreate(identity, ccx,
                                                           parent, &parent);
         if (NS_FAILED(rv))
             return rv;
 
         if (rv == NS_SUCCESS_CHROME_ACCESS_ONLY)
             needsSOW = true;
         rv = NS_OK;
 
         NS_ASSERTION(!xpc::WrapperFactory::IsXrayWrapper(parent),
                      "Xray wrapper being used to parent XPCWrappedNative?");
 
-        if (!ac.enter(ccx, parent))
-            return NS_ERROR_FAILURE;
+        ac.construct(ccx, parent);
 
         if (parent != plannedParent) {
             XPCWrappedNativeScope* betterScope =
                 XPCWrappedNativeScope::FindInJSObjectScope(ccx, parent);
             if (betterScope != Scope)
                 return GetNewOrUsed(ccx, helper, betterScope, Interface, resultWrapper);
 
             newParentVal = OBJECT_TO_JSVAL(parent);
@@ -572,18 +569,17 @@ XPCWrappedNative::GetNewOrUsed(XPCCallCo
             if (Interface && !wrapper->FindTearOff(ccx, Interface, false, &rv)) {
                 NS_ASSERTION(NS_FAILED(rv), "returning NS_OK on failure");
                 return rv;
             }
             *resultWrapper = wrapper.forget().get();
             return NS_OK;
         }
     } else {
-        if (!ac.enter(ccx, parent))
-            return NS_ERROR_FAILURE;
+        ac.construct(ccx, parent);
 
         nsISupports *Object = helper.Object();
         if (nsXPCWrappedJSClass::IsWrappedJS(Object)) {
             nsCOMPtr<nsIXPConnectWrappedJS> wrappedjs(do_QueryInterface(Object));
             JSObject *obj;
             wrappedjs->GetJSObject(&obj);
             if (xpc::AccessCheck::isChrome(js::GetObjectCompartment(obj)) &&
                 !xpc::AccessCheck::isChrome(js::GetObjectCompartment(Scope->GetGlobalJSObject()))) {
@@ -787,21 +783,17 @@ XPCWrappedNative::Morph(XPCCallContext& 
                  "Xray wrapper being used to parent XPCWrappedNative?");
 
     // We use an AutoMarkingPtr here because it is possible for JS gc to happen
     // after we have Init'd the wrapper but *before* we add it to the hashtable.
     // This would cause the mSet to get collected and we'd later crash. I've
     // *seen* this happen.
     AutoMarkingWrappedNativePtr wrapperMarker(ccx, wrapper);
 
-    JSAutoEnterCompartment ac;
-    if (!ac.enter(ccx, existingJSObject)) {
-        wrapper->mIdentity = nullptr;
-        return NS_ERROR_FAILURE;
-    }
+    JSAutoCompartment ac(ccx, existingJSObject);
     if (!wrapper->Init(ccx, existingJSObject))
         return NS_ERROR_FAILURE;
 
     nsresult rv;
     if (Interface && !wrapper->FindTearOff(ccx, Interface, false, &rv)) {
         NS_ASSERTION(NS_FAILED(rv), "returning NS_OK on failure");
         return rv;
     }
@@ -1522,19 +1514,17 @@ XPCWrappedNative::ReparentWrapperIfFound
     // which must happen only on the main thread. Bail if we're on some other
     // thread or have a non-main-thread-only wrapper.
     if (wrapper &&
         wrapper->GetProto() &&
         !wrapper->GetProto()->ClassIsMainThreadOnly()) {
         return NS_ERROR_FAILURE;
     }
 
-    JSAutoEnterCompartment ac;
-    if (!ac.enter(ccx, aNewScope->GetGlobalJSObject()))
-        return NS_ERROR_FAILURE;
+    JSAutoCompartment ac(ccx, aNewScope->GetGlobalJSObject());
 
     if (aOldScope != aNewScope) {
         // Oh, so now we need to move the wrapper to a different scope.
         AutoMarkingWrappedNativeProtoPtr oldProto(ccx);
         AutoMarkingWrappedNativeProtoPtr newProto(ccx);
 
         // Cross-scope means cross-compartment.
         MOZ_ASSERT(js::GetObjectCompartment(aOldScope->GetGlobalJSObject()) !=
@@ -1604,19 +1594,18 @@ XPCWrappedNative::ReparentWrapperIfFound
                 // crash when JS_CopyPropertiesFrom tries to call wrap() on foo.x.
                 JS_SetPrivate(flat, nullptr);
             }
 
             // Before proceeding, eagerly create any same-compartment security wrappers
             // that the object might have. This forces us to take the 'WithWrapper' path
             // while transplanting that handles this stuff correctly.
             {
-                JSAutoEnterCompartment innerAC;
-                if (!innerAC.enter(ccx, aOldScope->GetGlobalJSObject()) ||
-                    !wrapper->GetSameCompartmentSecurityWrapper(ccx))
+                JSAutoCompartment innerAC(ccx, aOldScope->GetGlobalJSObject());
+                if (!wrapper->GetSameCompartmentSecurityWrapper(ccx))
                     return NS_ERROR_FAILURE;
             }
 
             // Update scope maps. This section modifies global state, so from
             // here on out we crash if anything fails.
             {   // scoped lock
                 Native2WrappedNativeMap* oldMap = aOldScope->GetWrappedNativeMap();
                 Native2WrappedNativeMap* newMap = aNewScope->GetWrappedNativeMap();
@@ -3803,22 +3792,17 @@ ConstructSlimWrapper(XPCCallContext &ccx
     }
 
     if (!js::IsObjectInContextCompartment(parent, ccx.GetJSContext())) {
         SLIM_LOG_NOT_CREATED(ccx, identityObj, "wrong compartment");
 
         return false;
     }
 
-    JSAutoEnterCompartment ac;
-    if (!ac.enter(ccx, parent)) {
-        SLIM_LOG_NOT_CREATED(ccx, identityObj, "unable to enter compartment");
-
-        return false;
-    }
+    JSAutoCompartment ac(ccx, parent);
 
     if (parent != plannedParent) {
         XPCWrappedNativeScope *newXpcScope =
             XPCWrappedNativeScope::FindInJSObjectScope(ccx, parent);
         if (newXpcScope != xpcScope) {
             SLIM_LOG_NOT_CREATED(ccx, identityObj, "crossing origins");
 
             return false;
--- a/js/xpconnect/src/XPCWrappedNativeJSOps.cpp
+++ b/js/xpconnect/src/XPCWrappedNativeJSOps.cpp
@@ -139,19 +139,17 @@ GetDoubleWrappedJSObject(XPCCallContext&
     nsCOMPtr<nsIXPConnectWrappedJS>
         underware = do_QueryInterface(wrapper->GetIdentityObject());
     if (underware) {
         JSObject* mainObj = nullptr;
         if (NS_SUCCEEDED(underware->GetJSObject(&mainObj)) && mainObj) {
             jsid id = ccx.GetRuntime()->
                     GetStringID(XPCJSRuntime::IDX_WRAPPED_JSOBJECT);
 
-            JSAutoEnterCompartment ac;
-            if (!ac.enter(ccx, mainObj))
-                return NULL;
+            JSAutoCompartment ac(ccx, mainObj);
 
             jsval val;
             if (JS_GetPropertyById(ccx, mainObj, id, &val) &&
                 !JSVAL_IS_PRIMITIVE(val)) {
                 obj = JSVAL_TO_OBJECT(val);
             }
         }
     }
--- a/js/xpconnect/src/XPCWrappedNativeScope.cpp
+++ b/js/xpconnect/src/XPCWrappedNativeScope.cpp
@@ -668,19 +668,17 @@ XPCWrappedNativeScope::FindInJSObjectSco
     // scope directly.
 
     scope = GetScopeOfObject(obj);
     if (scope)
         return scope;
 
     // Else we'll have to look up the parent chain to get the scope
 
-    JSAutoEnterCompartment ac;
-    ac.enterAndIgnoreErrors(cx, obj);
-
+    JSAutoCompartment ac(cx, obj);
     obj = JS_GetGlobalForObject(cx, obj);
 
     if (js::GetObjectClass(obj)->flags & JSCLASS_XPCONNECT_GLOBAL) {
         scope = XPCWrappedNativeScope::GetNativeScope(obj);
         if (scope)
             return scope;
     }
 
--- a/js/xpconnect/src/dictionary_helper_gen.py
+++ b/js/xpconnect/src/dictionary_helper_gen.py
@@ -416,18 +416,17 @@ def write_cpp(iface, fd):
              "  }\n\n"
              "  JSObject* obj = &aVal->toObject();\n"
              "  Maybe<nsCxPusher> pusher;\n"
              "  if (NS_IsMainThread()) {\n"
              "    pusher.construct();\n"
              "    NS_ENSURE_STATE(pusher.ref().Push(aCx, false));\n"
              "  }\n"
              "  JSAutoRequest ar(aCx);\n"
-             "  JSAutoEnterCompartment ac;\n"
-             "  NS_ENSURE_STATE(ac.enter(aCx, obj));\n")
+             "  JSAutoCompartment ac(aCx, obj);\n")
 
     fd.write("  return %s_InitInternal(*this, aCx, obj);\n}\n\n" %
                  iface.name)
 
 
 if __name__ == '__main__':
     from optparse import OptionParser
     o = OptionParser(usage="usage: %prog [options] configfile")
--- a/js/xpconnect/src/dombindings.cpp
+++ b/js/xpconnect/src/dombindings.cpp
@@ -415,22 +415,17 @@ ListBase<LC>::create(JSContext *cx, JSOb
 {
     *triedToWrap = true;
 
     JSObject *parent = WrapNativeParent(cx, scope, aList->GetParentObject());
     if (!parent)
         return NULL;
 
     JSObject *global = js::GetGlobalForObjectCrossCompartment(parent);
-
-    JSAutoEnterCompartment ac;
-    if (global != scope) {
-        if (!ac.enter(cx, global))
-            return NULL;
-    }
+    JSAutoCompartment ac(cx, global);
 
     JSObject *proto = getPrototype(cx, global, triedToWrap);
     if (!proto && !*triedToWrap)
         aWrapperCache->ClearIsDOMBinding();
     if (!proto)
         return NULL;
     JSObject *obj = NewProxyObject(cx, &ListBase<LC>::instance,
                                    PrivateValue(aList), proto, parent);
@@ -826,21 +821,20 @@ ListBase<LC>::getPropertyOnPrototype(JSC
 
     return JS_ForwardGetPropertyTo(cx, proto, id, proxy, vp);
 }
 
 template<class LC>
 bool
 ListBase<LC>::hasPropertyOnPrototype(JSContext *cx, JSObject *proxy, jsid id)
 {
-    JSAutoEnterCompartment ac;
+    Maybe<JSAutoCompartment> ac;
     if (xpc::WrapperFactory::IsXrayWrapper(proxy)) {
         proxy = js::UnwrapObject(proxy);
-        if (!ac.enter(cx, proxy))
-            return false;
+        ac.construct(cx, proxy);
     }
     JS_ASSERT(objIsList(proxy));
 
     bool found = false;
     // We ignore an error from getPropertyOnPrototype.
     return !getPropertyOnPrototype(cx, proxy, id, &found, NULL) || found;
 }
 
--- a/js/xpconnect/src/nsXPConnect.cpp
+++ b/js/xpconnect/src/nsXPConnect.cpp
@@ -981,19 +981,17 @@ nsXPConnect::InitClasses(JSContext * aJS
     NS_ASSERTION(aJSContext, "bad param");
     NS_ASSERTION(aGlobalJSObj, "bad param");
 
     // Nest frame chain save/restore in request created by XPCCallContext.
     XPCCallContext ccx(NATIVE_CALLER, aJSContext);
     if (!ccx.IsValid())
         return UnexpectedFailure(NS_ERROR_FAILURE);
 
-    JSAutoEnterCompartment ac;
-    if (!ac.enter(ccx, aGlobalJSObj))
-        return UnexpectedFailure(NS_ERROR_FAILURE);
+    JSAutoCompartment ac(ccx, aGlobalJSObj);
 
     XPCWrappedNativeScope* scope =
         XPCWrappedNativeScope::GetNewOrUsed(ccx, aGlobalJSObj);
 
     if (!scope)
         return UnexpectedFailure(NS_ERROR_FAILURE);
 
     scope->RemoveWrappedNativeProtos();
@@ -1171,19 +1169,17 @@ nsXPConnect::InitClassesWithNewWrappedGl
         XPCWrappedNative::WrapNewGlobal(ccx, helper, aPrincipal,
                                         aFlags & nsIXPConnect::INIT_JS_STANDARD_CLASSES,
                                         getter_AddRefs(wrappedGlobal));
     NS_ENSURE_SUCCESS(rv, rv);
 
     // Grab a copy of the global and enter its compartment.
     JSObject *global = wrappedGlobal->GetFlatJSObject();
     MOZ_ASSERT(!js::GetObjectParent(global));
-    JSAutoEnterCompartment ac;
-    if (!ac.enter(ccx, global))
-        return NS_ERROR_UNEXPECTED;
+    JSAutoCompartment ac(ccx, global);
 
     if (!(aFlags & nsIXPConnect::OMIT_COMPONENTS_OBJECT)) {
         // XPCCallContext gives us an active request needed to save/restore.
         if (!nsXPCComponents::AttachComponentsObject(ccx, wrappedGlobal->GetScope(), global))
             return UnexpectedFailure(NS_ERROR_FAILURE);
 
         if (!XPCNativeWrapper::AttachNewConstructorObject(ccx, global))
             return UnexpectedFailure(NS_ERROR_FAILURE);
@@ -1218,20 +1214,17 @@ NativeInterface2JSObject(XPCLazyCallCont
                          JSObject * aScope,
                          nsISupports *aCOMObj,
                          nsWrapperCache *aCache,
                          const nsIID * aIID,
                          bool aAllowWrapping,
                          jsval *aVal,
                          nsIXPConnectJSObjectHolder **aHolder)
 {
-    JSAutoEnterCompartment ac;
-    if (!ac.enter(lccx.GetJSContext(), aScope))
-        return NS_ERROR_OUT_OF_MEMORY;
-
+    JSAutoCompartment ac(lccx.GetJSContext(), aScope);
     lccx.SetScopeForNewJSObjects(aScope);
 
     nsresult rv;
     xpcObjectHelper helper(aCOMObj, aCache);
     if (!XPCConvert::NativeInterface2JSObject(lccx, aVal, aHolder, helper, aIID,
                                               nullptr, aAllowWrapping, &rv))
         return rv;
 
@@ -1303,21 +1296,20 @@ nsXPConnect::WrapJS(JSContext * aJSConte
     NS_ASSERTION(result, "bad param");
 
     *result = nullptr;
 
     XPCCallContext ccx(NATIVE_CALLER, aJSContext);
     if (!ccx.IsValid())
         return UnexpectedFailure(NS_ERROR_FAILURE);
 
-    JSAutoEnterCompartment aec;
+    JSAutoCompartment ac(ccx, aJSObj);
 
     nsresult rv = NS_ERROR_UNEXPECTED;
-    if (!aec.enter(ccx, aJSObj) ||
-        !XPCConvert::JSObject2NativeInterface(ccx, result, aJSObj,
+    if (!XPCConvert::JSObject2NativeInterface(ccx, result, aJSObj,
                                               &aIID, nullptr, &rv))
         return rv;
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsXPConnect::JSValToVariant(JSContext *cx,
                             jsval *aJSVal,
@@ -1943,19 +1935,17 @@ nsXPConnect::GetWrappedNativePrototype(J
                                        JSObject * aScope,
                                        nsIClassInfo *aClassInfo,
                                        nsIXPConnectJSObjectHolder **_retval)
 {
     XPCCallContext ccx(NATIVE_CALLER, aJSContext);
     if (!ccx.IsValid())
         return UnexpectedFailure(NS_ERROR_FAILURE);
 
-    JSAutoEnterCompartment ac;
-    if (!ac.enter(aJSContext, aScope))
-        return UnexpectedFailure(NS_ERROR_FAILURE);
+    JSAutoCompartment ac(aJSContext, aScope);
 
     XPCWrappedNativeScope* scope =
         XPCWrappedNativeScope::FindInJSObjectScope(ccx, aScope);
     if (!scope)
         return UnexpectedFailure(NS_ERROR_FAILURE);
 
     XPCNativeScriptableCreateInfo sciProto;
     XPCWrappedNative::GatherProtoScriptableCreateInfo(aClassInfo, sciProto);
--- a/js/xpconnect/src/xpcprivate.h
+++ b/js/xpconnect/src/xpcprivate.h
@@ -3867,27 +3867,28 @@ public:
     /**
      * Does the pre script evaluation and sets the error reporter if given
      * This function should only be called once, and will assert if called
      * more than once
      * @param errorReporter the error reporter callback function to set
      */
 
     bool StartEvaluating(JSObject *scope, JSErrorReporter errorReporter = nullptr);
+
     /**
      * Does the post script evaluation and resets the error reporter
      */
     ~AutoScriptEvaluate();
 private:
     JSContext* mJSContext;
     JSExceptionState* mState;
     bool mErrorReporterSet;
     bool mEvaluated;
     intptr_t mContextHasThread;
-    JSAutoEnterCompartment mEnterCompartment;
+    mozilla::Maybe<JSAutoCompartment> mAutoCompartment;
     MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
 
     // No copying or assignment allowed
     AutoScriptEvaluate(const AutoScriptEvaluate &) MOZ_DELETE;
     AutoScriptEvaluate & operator =(const AutoScriptEvaluate &) MOZ_DELETE;
 };
 
 /***************************************************************************/
--- a/js/xpconnect/wrappers/AccessCheck.cpp
+++ b/js/xpconnect/wrappers/AccessCheck.cpp
@@ -381,19 +381,17 @@ PermitIfUniversalXPConnect(JSContext *cx
 
     // Deny
     return Deny(cx, id, act);
 }
 
 static bool
 IsInSandbox(JSContext *cx, JSObject *obj)
 {
-    JSAutoEnterCompartment ac;
-    if (!ac.enter(cx, obj))
-        return false;
+    JSAutoCompartment ac(cx, obj);
     JSObject *global = JS_GetGlobalForObject(cx, obj);
     return !strcmp(js::GetObjectJSClass(global)->name, "Sandbox");
 }
 
 bool
 ExposedPropertiesOnly::check(JSContext *cx, JSObject *wrapper, jsid id, Wrapper::Action act,
                              Permission &perm)
 {
@@ -409,39 +407,34 @@ ExposedPropertiesOnly::check(JSContext *
         return PermitIfUniversalXPConnect(cx, id, act, perm); // Deny
 
     jsid exposedPropsId = GetRTIdByIndex(cx, XPCJSRuntime::IDX_EXPOSEDPROPS);
 
     // We need to enter the wrappee's compartment to look at __exposedProps__,
     // but we need to be in the wrapper's compartment to check UniversalXPConnect.
     //
     // Unfortunately, |cx| can be in either compartment when we call ::check. :-(
-    JSAutoEnterCompartment ac;
-    JSAutoEnterCompartment wrapperAC;
-    if (!ac.enter(cx, wrappedObject))
-        return false;
+    JSAutoCompartment ac(cx, wrappedObject);
 
     JSBool found = false;
     if (!JS_HasPropertyById(cx, wrappedObject, exposedPropsId, &found))
         return false;
 
     // Always permit access to "length" and indexed properties of arrays.
     if (JS_IsArrayObject(cx, wrappedObject) &&
         ((JSID_IS_INT(id) && JSID_TO_INT(id) >= 0) ||
          (JSID_IS_STRING(id) && JS_FlatStringEqualsAscii(JSID_TO_FLAT_STRING(id), "length")))) {
         perm = PermitPropertyAccess;
         return true; // Allow
     }
 
     // If no __exposedProps__ existed, deny access.
     if (!found) {
         // Everything below here needs to be done in the wrapper's compartment.
-        if (!wrapperAC.enter(cx, wrapper))
-            return false;
-
+        JSAutoCompartment wrapperAC(cx, wrapper);
         // Make a temporary exception for objects in a chrome sandbox to help
         // out jetpack. See bug 784233.
         if (!JS_ObjectIsFunction(cx, wrappedObject) &&
             IsInSandbox(cx, wrappedObject))
         {
             // This little loop hole will go away soon! See bug 553102.
             nsCOMPtr<nsPIDOMWindow> win =
                 do_QueryInterface(nsJSUtils::GetStaticScriptGlobal(cx, wrapper));
@@ -466,36 +459,36 @@ ExposedPropertiesOnly::check(JSContext *
         return true;
     }
 
     JS::Value exposedProps;
     if (!JS_LookupPropertyById(cx, wrappedObject, exposedPropsId, &exposedProps))
         return false;
 
     if (exposedProps.isNullOrUndefined()) {
-        return wrapperAC.enter(cx, wrapper) &&
-               PermitIfUniversalXPConnect(cx, id, act, perm); // Deny
+        JSAutoCompartment wrapperAC(cx, wrapper);
+        return PermitIfUniversalXPConnect(cx, id, act, perm); // Deny
     }
 
     if (!exposedProps.isObject()) {
         JS_ReportError(cx, "__exposedProps__ must be undefined, null, or an Object");
         return false;
     }
 
     JSObject *hallpass = &exposedProps.toObject();
 
     Access access = NO_ACCESS;
 
     JSPropertyDescriptor desc;
     if (!JS_GetPropertyDescriptorById(cx, hallpass, id, JSRESOLVE_QUALIFIED, &desc)) {
         return false; // Error
     }
     if (desc.obj == NULL || !(desc.attrs & JSPROP_ENUMERATE)) {
-        return wrapperAC.enter(cx, wrapper) &&
-               PermitIfUniversalXPConnect(cx, id, act, perm); // Deny
+        JSAutoCompartment wrapperAC(cx, wrapper);
+        return PermitIfUniversalXPConnect(cx, id, act, perm); // Deny
     }
 
     if (!JSVAL_IS_STRING(desc.value)) {
         JS_ReportError(cx, "property must be a string");
         return false;
     }
 
     JSString *str = JSVAL_TO_STRING(desc.value);
@@ -530,32 +523,30 @@ ExposedPropertiesOnly::check(JSContext *
 
     if (access == NO_ACCESS) {
         JS_ReportError(cx, "specified properties must have a permission bit set");
         return false;
     }
 
     if ((act == Wrapper::SET && !(access & WRITE)) ||
         (act != Wrapper::SET && !(access & READ))) {
-        return wrapperAC.enter(cx, wrapper) &&
-               PermitIfUniversalXPConnect(cx, id, act, perm); // Deny
+        JSAutoCompartment wrapperAC(cx, wrapper);
+        return PermitIfUniversalXPConnect(cx, id, act, perm); // Deny
     }
 
     perm = PermitPropertyAccess;
     return true; // Allow
 }
 
 bool
 ComponentsObjectPolicy::check(JSContext *cx, JSObject *wrapper, jsid id, Wrapper::Action act,
                               Permission &perm) 
 {
     perm = DenyAccess;
-    JSAutoEnterCompartment ac;
-    if (!ac.enter(cx, wrapper))
-        return false;
+    JSAutoCompartment ac(cx, wrapper);
 
     if (JSID_IS_STRING(id) && act == Wrapper::GET) {
         JSFlatString *flatId = JSID_TO_FLAT_STRING(id);
         if (JS_FlatStringEqualsAscii(flatId, "isSuccessCode") ||
             JS_FlatStringEqualsAscii(flatId, "lookupMethod") ||
             JS_FlatStringEqualsAscii(flatId, "interfaces") ||
             JS_FlatStringEqualsAscii(flatId, "interfacesByID") ||
             JS_FlatStringEqualsAscii(flatId, "results"))
--- a/js/xpconnect/wrappers/AccessCheck.h
+++ b/js/xpconnect/wrappers/AccessCheck.h
@@ -56,19 +56,17 @@ struct Permissive : public Policy {
 struct OnlyIfSubjectIsSystem : public Policy {
     static bool check(JSContext *cx, JSObject *wrapper, jsid id, js::Wrapper::Action act,
                       Permission &perm) {
         if (AccessCheck::isSystemOnlyAccessPermitted(cx)) {
             perm = PermitObjectAccess;
             return true;
         }
         perm = DenyAccess;
-        JSAutoEnterCompartment ac;
-        if (!ac.enter(cx, wrapper))
-            return false;
+        JSAutoCompartment ac(cx, wrapper);
         AccessCheck::deny(cx, id);
         return false;
     }
 };
 
 // This policy only permits access to properties that are safe to be used
 // across origins.
 struct CrossOriginAccessiblePropertiesOnly : public Policy {
@@ -77,19 +75,17 @@ struct CrossOriginAccessiblePropertiesOn
         // Location objects should always use LocationPolicy.
         MOZ_ASSERT(!WrapperFactory::IsLocationObject(js::UnwrapObject(wrapper)));
 
         if (AccessCheck::isCrossOriginAccessPermitted(cx, wrapper, id, act)) {
             perm = PermitPropertyAccess;
             return true;
         }
         perm = DenyAccess;
-        JSAutoEnterCompartment ac;
-        if (!ac.enter(cx, wrapper))
-            return false;
+        JSAutoCompartment ac(cx, wrapper);
         AccessCheck::deny(cx, id);
         return false;
     }
 };
 
 // We need a special security policy for Location objects.
 //
 // Location objects are special because their effective principal is that of
@@ -125,19 +121,17 @@ struct LocationPolicy : public Policy {
         // Location object security is complicated enough. Don't allow punctures.
         if (act != js::Wrapper::PUNCTURE &&
             (AccessCheck::isCrossOriginAccessPermitted(cx, wrapper, id, act) ||
              AccessCheck::isLocationObjectSameOrigin(cx, wrapper))) {
             perm = PermitPropertyAccess;
             return true;
         }
 
-        JSAutoEnterCompartment ac;
-        if (!ac.enter(cx, wrapper))
-            return false;
+        JSAutoCompartment ac(cx, wrapper);
         AccessCheck::deny(cx, id);
         return false;
     }
 };
 
 // This policy only permits access to properties if they appear in the
 // objects exposed properties list.
 struct ExposedPropertiesOnly : public Policy {
--- a/js/xpconnect/wrappers/ChromeObjectWrapper.cpp
+++ b/js/xpconnect/wrappers/ChromeObjectWrapper.cpp
@@ -29,41 +29,37 @@ ChromeObjectWrapper::getPropertyDescript
     }
 
     // If we found something, were doing a set, or have no proto, we're done.
     JSObject *wrapperProto = JS_GetPrototype(wrapper);
     if (desc->obj || set || !wrapperProto)
         return true;
 
     // If not, try doing the lookup on the prototype.
-    JSAutoEnterCompartment ac;
-    return ac.enter(cx, wrapper) &&
-           JS_GetPropertyDescriptorById(cx, wrapperProto, id, 0, desc);
+    JSAutoCompartment ac(cx, wrapper);
+    return JS_GetPropertyDescriptorById(cx, wrapperProto, id, 0, desc);
 }
 
 bool
 ChromeObjectWrapper::has(JSContext *cx, JSObject *wrapper, jsid id, bool *bp)
 {
     // Try the lookup on the base wrapper.
     if (!ChromeObjectWrapperBase::has(cx, wrapper, id, bp))
         return false;
 
     // If we found something or have no prototype, we're done.
     JSObject *wrapperProto = JS_GetPrototype(wrapper);
     if (*bp || !wrapperProto)
         return true;
 
     // Try the prototype if that failed.
-    JSAutoEnterCompartment ac;
+    JSAutoCompartment ac(cx, wrapper);
     JSPropertyDescriptor desc;
-    if (!ac.enter(cx, wrapper) ||
-        !JS_GetPropertyDescriptorById(cx, wrapperProto, id, 0, &desc))
-    {
+    if (!JS_GetPropertyDescriptorById(cx, wrapperProto, id, 0, &desc))
         return false;
-    }
     *bp = !!desc.obj;
     return true;
 }
 
 bool
 ChromeObjectWrapper::get(JSContext *cx, JSObject *wrapper, JSObject *receiver,
                          jsid id, js::Value *vp)
 {
@@ -72,15 +68,13 @@ ChromeObjectWrapper::get(JSContext *cx, 
         return false;
 
     // If we found something or have no proto, we're done.
     JSObject *wrapperProto = JS_GetPrototype(wrapper);
     if (!vp->isUndefined() || !wrapperProto)
         return true;
 
     // Try the prototype.
-    JSAutoEnterCompartment ac;
-    if (!ac.enter(cx, wrapper))
-        return false;
+    JSAutoCompartment ac(cx, wrapper);
     return js::GetGeneric(cx, wrapperProto, receiver, id, vp);
 }
 
 }
--- a/js/xpconnect/wrappers/WrapperFactory.cpp
+++ b/js/xpconnect/wrappers/WrapperFactory.cpp
@@ -77,18 +77,18 @@ WrapperFactory::CreateXrayWaiver(JSConte
     CompartmentPrivate *priv = GetCompartmentPrivate(obj);
 
     // Get a waiver for the proto.
     JSObject *proto = js::GetObjectProto(obj);
     if (proto && !(proto = WaiveXray(cx, proto)))
         return nullptr;
 
     // Create the waiver.
-    JSAutoEnterCompartment ac;
-    if (!ac.enter(cx, obj) || !JS_WrapObject(cx, &proto))
+    JSAutoCompartment ac(cx, obj);
+    if (!JS_WrapObject(cx, &proto))
         return nullptr;
     JSObject *waiver = Wrapper::New(cx, obj, proto,
                                     JS_GetGlobalForObject(cx, obj),
                                     &XrayWaiver);
     if (!waiver)
         return nullptr;
 
     // Add the new waiver to the map. It's important that we only ever have
@@ -121,20 +121,17 @@ WrapperFactory::WaiveXray(JSContext *cx,
 // DoubleWrap is called from PrepareForWrapping to maintain the state that
 // we're supposed to waive Xray wrappers for the given on. On entrance, it
 // expects |cx->compartment != obj->compartment()|. The returned object will
 // be in the same compartment as |obj|.
 JSObject *
 WrapperFactory::DoubleWrap(JSContext *cx, JSObject *obj, unsigned flags)
 {
     if (flags & WrapperFactory::WAIVE_XRAY_WRAPPER_FLAG) {
-        JSAutoEnterCompartment ac;
-        if (!ac.enter(cx, obj))
-            return nullptr;
-
+        JSAutoCompartment ac(cx, obj);
         return WaiveXray(cx, obj);
     }
     return obj;
 }
 
 JSObject *
 WrapperFactory::PrepareForWrapping(JSContext *cx, JSObject *scope, JSObject *obj, unsigned flags)
 {
@@ -164,19 +161,17 @@ WrapperFactory::PrepareForWrapping(JSCon
     // those objects in a security wrapper, then we need to hand back the
     // wrapper for the new scope instead. Also, global objects don't move
     // between scopes so for those we also want to return the wrapper. So...
     if (!IS_WN_WRAPPER(obj) || !js::GetObjectParent(obj))
         return DoubleWrap(cx, obj, flags);
 
     XPCWrappedNative *wn = static_cast<XPCWrappedNative *>(xpc_GetJSPrivate(obj));
 
-    JSAutoEnterCompartment ac;
-    if (!ac.enter(cx, obj))
-        return nullptr;
+    JSAutoCompartment ac(cx, obj);
     XPCCallContext ccx(JS_CALLER, cx, obj);
 
     {
         if (NATIVE_HAS_FLAG(&ccx, WantPreCreate)) {
             // We have a precreate hook. This object might enforce that we only
             // ever create JS object for it.
 
             // Note: this penalizes objects that only have one wrapper, but are
@@ -393,19 +388,17 @@ WrapperFactory::Rewrap(JSContext *cx, JS
             //
             // The prototype chain of COW(obj) looks lke this:
             //
             // COW(obj) => COW(foo) => COW(bar) => contentWin.StandardClass.prototype
             JSProtoKey key = JSProto_Null;
             JSObject *unwrappedProto = NULL;
             if (wrappedProto && IsCrossCompartmentWrapper(wrappedProto) &&
                 (unwrappedProto = Wrapper::wrappedObject(wrappedProto))) {
-                JSAutoEnterCompartment ac;
-                if (!ac.enter(cx, unwrappedProto))
-                    return NULL;
+                JSAutoCompartment ac(cx, unwrappedProto);
                 key = JS_IdentifyClassPrototype(cx, unwrappedProto);
             }
             if (key != JSProto_Null) {
                 JSObject *homeProto;
                 if (!JS_GetClassPrototype(cx, key, &homeProto))
                     return NULL;
                 MOZ_ASSERT(homeProto);
                 proxyProto = homeProto;
--- a/js/xpconnect/wrappers/XrayWrapper.cpp
+++ b/js/xpconnect/wrappers/XrayWrapper.cpp
@@ -127,22 +127,19 @@ ExpandoObjectMatchesConsumer(JSContext *
 }
 
 JSObject *
 LookupExpandoObject(JSContext *cx, JSObject *target, nsIPrincipal *origin,
                     JSObject *exclusiveGlobal)
 {
     // The expando object lives in the compartment of the target, so all our
     // work needs to happen there.
-    JSAutoEnterCompartment ac;
-    if (!ac.enter(cx, target) ||
-        !JS_WrapObject(cx, &exclusiveGlobal))
-    {
+    JSAutoCompartment ac(cx, target);
+    if (!JS_WrapObject(cx, &exclusiveGlobal))
         return NULL;
-    }
 
     // Iterate through the chain, looking for a same-origin object.
     JSObject *head = GetExpandoChain(target);
     while (head) {
         if (ExpandoObjectMatchesConsumer(cx, head, origin, exclusiveGlobal))
             return head;
         head = JS_GetReservedSlot(head, JSSLOT_EXPANDO_NEXT).toObjectOrNull();
     }
@@ -208,20 +205,17 @@ AttachExpandoObject(JSContext *cx, JSObj
 
     return expandoObject;
 }
 
 JSObject *
 EnsureExpandoObject(JSContext *cx, JSObject *wrapper, JSObject *target)
 {
     // Expando objects live in the target compartment.
-    JSAutoEnterCompartment ac;
-    if (!ac.enter(cx, target))
-        return nullptr;
-
+    JSAutoCompartment ac(cx, target);
     JSObject *expandoObject = LookupExpandoObject(cx, target, wrapper);
     if (!expandoObject) {
         // If the object is a sandbox, we don't want it to share expandos with
         // anyone else, so we tag it with the sandbox global.
         //
         // NB: We first need to check the class, _then_ wrap for the target's
         // compartment.
         JSObject *consumerGlobal = js::GetGlobalForObjectCrossCompartment(wrapper);
@@ -511,19 +505,17 @@ JSBool
 holder_get(JSContext *cx, JSHandleObject wrapper_, JSHandleId id, JSMutableHandleValue vp)
 {
     JSObject *wrapper = FindWrapper(wrapper_);
 
     JSObject *holder = GetHolder(wrapper);
 
     XPCWrappedNative *wn = GetWrappedNativeFromHolder(holder);
     if (NATIVE_HAS_FLAG(wn, WantGetProperty)) {
-        JSAutoEnterCompartment ac;
-        if (!ac.enter(cx, holder))
-            return false;
+        JSAutoCompartment ac(cx, holder);
         bool retval = true;
         nsresult rv = wn->GetScriptableCallback()->GetProperty(wn, cx, wrapper,
                                                                id, vp.address(), &retval);
         if (NS_FAILED(rv) || !retval) {
             if (retval)
                 XPCThrower::Throw(rv, cx);
             return false;
         }
@@ -538,19 +530,17 @@ holder_set(JSContext *cx, JSHandleObject
 
     JSObject *holder = GetHolder(wrapper);
     if (XPCWrappedNativeXrayTraits::isResolving(cx, holder, id)) {
         return true;
     }
 
     XPCWrappedNative *wn = GetWrappedNativeFromHolder(holder);
     if (NATIVE_HAS_FLAG(wn, WantSetProperty)) {
-        JSAutoEnterCompartment ac;
-        if (!ac.enter(cx, holder))
-            return false;
+        JSAutoCompartment ac(cx, holder);
         bool retval = true;
         nsresult rv = wn->GetScriptableCallback()->SetProperty(wn, cx, wrapper,
                                                                id, vp.address(), &retval);
         if (NS_FAILED(rv) || !retval) {
             if (retval)
                 XPCThrower::Throw(rv, cx);
             return false;
         }
@@ -816,22 +806,19 @@ XPCWrappedNativeXrayTraits::resolveOwnPr
 
     unsigned flags = (set ? JSRESOLVE_ASSIGNING : 0) | JSRESOLVE_QUALIFIED;
     JSObject *target = GetWrappedNativeObjectFromHolder(holder);
     JSObject *expando = LookupExpandoObject(cx, target, wrapper);
 
     // Check for expando properties first. Note that the expando object lives
     // in the target compartment.
     if (expando) {
-        JSAutoEnterCompartment ac;
-        if (!ac.enter(cx, expando) ||
-            !JS_GetPropertyDescriptorById(cx, expando, id, flags, desc))
-        {
+        JSAutoCompartment ac(cx, expando);
+        if (!JS_GetPropertyDescriptorById(cx, expando, id, flags, desc))
             return false;
-        }
     }
     if (desc->obj) {
         if (!JS_WrapPropertyDescriptor(cx, desc))
             return false;
         // Pretend the property lives on the wrapper.
         desc->obj = wrapper;
         return true;
     }
@@ -886,19 +873,17 @@ XPCWrappedNativeXrayTraits::defineProper
 
         return JS_DefinePropertyById(cx, holder, id, desc->value, desc->getter, desc->setter,
                                      desc->attrs);
     }
 
     // We're placing an expando. The expando objects live in the target
     // compartment, so we need to enter it.
     JSObject *target = GetWrappedNativeObjectFromHolder(holder);
-    JSAutoEnterCompartment ac;
-    if (!ac.enter(cx, target))
-        return false;
+    JSAutoCompartment ac(cx, target);
 
     // Grab the relevant expando object.
     JSObject *expandoObject = EnsureExpandoObject(cx, wrapper, target);
     if (!expandoObject)
         return false;
 
     // Wrap the property descriptor for the target compartment.
     PropertyDescriptor wrappedDesc = *desc;
@@ -911,25 +896,25 @@ XPCWrappedNativeXrayTraits::defineProper
 }
 
 bool
 XPCWrappedNativeXrayTraits::delete_(JSContext *cx, JSObject *wrapper, jsid id, bool *bp)
 {
     JSObject *holder = getHolderObject(wrapper);
     JSObject *target = GetWrappedNativeObjectFromHolder(holder);
     JSObject *expando = LookupExpandoObject(cx, target, wrapper);
-    JSAutoEnterCompartment ac;
     JSBool b = true;
-    jsval v;
-    if (expando &&
-        (!ac.enter(cx, expando) ||
-         !JS_DeletePropertyById2(cx, expando, id, &v) ||
-         !JS_ValueToBoolean(cx, v, &b)))
-    {
-        return false;
+    if (expando) {
+        JSAutoCompartment ac(cx, expando);
+        jsval v;
+        if (!JS_DeletePropertyById2(cx, expando, id, &v) ||
+            !JS_ValueToBoolean(cx, v, &b))
+        {
+            return false;
+        }
     }
 
     *bp = !!b;
     return true;
 }
 
 bool
 XPCWrappedNativeXrayTraits::enumerateNames(JSContext *cx, JSObject *wrapper, unsigned flags,
@@ -937,34 +922,29 @@ XPCWrappedNativeXrayTraits::enumerateNam
 {
     JSObject *holder = getHolderObject(wrapper);
 
     // Enumerate expando properties first. Note that the expando object lives
     // in the target compartment.
     JSObject *target = GetWrappedNativeObjectFromHolder(holder);
     JSObject *expando = LookupExpandoObject(cx, target, wrapper);
     if (expando) {
-        JSAutoEnterCompartment ac;
-        if (!ac.enter(cx, expando) ||
-            !js::GetPropertyNames(cx, expando, flags, &props))
-        {
+        JSAutoCompartment ac(cx, expando);
+        if (!js::GetPropertyNames(cx, expando, flags, &props))
             return false;
-        }
     }
     if (!JS_WrapAutoIdVector(cx, props))
         return false;
 
     // Force all native properties to be materialized onto the wrapped native.
     JS::AutoIdVector wnProps(cx);
     {
         JSObject *wnObject = GetWrappedNativeObjectFromHolder(holder);
 
-        JSAutoEnterCompartment ac;
-        if (!ac.enter(cx, wnObject))
-            return false;
+        JSAutoCompartment ac(cx, wnObject);
         if (!js::GetPropertyNames(cx, wnObject, flags, &wnProps))
             return false;
     }
 
     // Go through the properties we got and enumerate all native ones.
     for (size_t n = 0; n < wnProps.length(); ++n) {
         jsid id = wnProps[n];
         JSBool hasProp;
@@ -1241,20 +1221,17 @@ XrayWrapper<Base, Traits>::getPropertyDe
         return status;
 
     typename Traits::ResolvingId resolving(wrapper, id);
 
     // Redirect access straight to the wrapper if we should be transparent.
     if (XrayUtils::IsTransparent(cx, wrapper)) {
         JSObject *obj = Traits::getInnerObject(wrapper);
         {
-            JSAutoEnterCompartment ac;
-            if (!ac.enter(cx, obj))
-                return false;
-
+            JSAutoCompartment ac(cx, obj);
             if (!JS_GetPropertyDescriptorById(cx, obj, id,
                                               (set ? JSRESOLVE_ASSIGNING : 0) | JSRESOLVE_QUALIFIED,
                                               desc)) {
                 return false;
             }
         }
 
         if (desc->obj)
@@ -1345,20 +1322,17 @@ XrayWrapper<Base, Traits>::getOwnPropert
     typename Traits::ResolvingId resolving(wrapper, id);
 
     // NB: Nothing we do here acts on the wrapped native itself, so we don't
     // enter our policy.
     // Redirect access straight to the wrapper if we should be transparent.
     if (XrayUtils::IsTransparent(cx, wrapper)) {
         JSObject *obj = Traits::getInnerObject(wrapper);
         {
-            JSAutoEnterCompartment ac;
-            if (!ac.enter(cx, obj))
-                return false;
-
+            JSAutoCompartment ac(cx, obj);
             if (!JS_GetPropertyDescriptorById(cx, obj, id,
                                               (set ? JSRESOLVE_ASSIGNING : 0) | JSRESOLVE_QUALIFIED,
                                               desc)) {
                 return false;
             }
         }
 
         desc->obj = (desc->obj == obj) ? wrapper : nullptr;
@@ -1398,20 +1372,17 @@ XrayWrapper<Base, Traits>::definePropert
             JS_ReportError(cx, "Permission denied to shadow native property");
             return false;
         }
     }
 
     // Redirect access straight to the wrapper if we should be transparent.
     if (XrayUtils::IsTransparent(cx, wrapper)) {
         JSObject *obj = Traits::getInnerObject(wrapper);
-        JSAutoEnterCompartment ac;
-        if (!ac.enter(cx, obj))
-            return false;
-
+        JSAutoCompartment ac(cx, obj);
         if (!JS_WrapPropertyDescriptor(cx, desc))
             return false;
 
         return JS_DefinePropertyById(cx, obj, id, desc->value, desc->getter, desc->setter,
                                      desc->attrs);
     }
 
     PropertyDescriptor existing_desc;
@@ -1435,19 +1406,17 @@ XrayWrapper<Base, Traits>::getOwnPropert
 template <typename Base, typename Traits>
 bool
 XrayWrapper<Base, Traits>::delete_(JSContext *cx, JSObject *wrapper, jsid id, bool *bp)
 {
     // Redirect access straight to the wrapper if we should be transparent.
     if (XrayUtils::IsTransparent(cx, wrapper)) {
         JSObject *obj = Traits::getInnerObject(wrapper);
 
-        JSAutoEnterCompartment ac;
-        if (!ac.enter(cx, obj))
-            return false;
+        JSAutoCompartment ac(cx, obj);
 
         JSBool b;
         jsval v;
         if (!JS_DeletePropertyById2(cx, obj, id, &v) || !JS_ValueToBoolean(cx, v, &b))
             return false;
         *bp = !!b;
         return true;
     }
@@ -1458,20 +1427,17 @@ XrayWrapper<Base, Traits>::delete_(JSCon
 template <typename Base, typename Traits>
 bool
 XrayWrapper<Base, Traits>::enumerate(JSContext *cx, JSObject *wrapper, unsigned flags,
                                      JS::AutoIdVector &props)
 {
     // Redirect access straight to the wrapper if we should be transparent.
     if (XrayUtils::IsTransparent(cx, wrapper)) {
         JSObject *obj = Traits::getInnerObject(wrapper);
-        JSAutoEnterCompartment ac;
-        if (!ac.enter(cx, obj))
-            return false;
-
+        JSAutoCompartment ac(cx, obj);
         return js::GetPropertyNames(cx, obj, flags, &props);
     }
 
     if (WrapperFactory::IsPartiallyTransparent(wrapper)) {
         JS_ReportError(cx, "Not allowed to enumerate cross origin objects");
         return false;
     }
 
--- a/security/manager/ssl/src/nsCrypto.cpp
+++ b/security/manager/ssl/src/nsCrypto.cpp
@@ -2203,21 +2203,17 @@ nsCryptoRunnable::~nsCryptoRunnable()
 //crypto.generateCRMFRequest as an event.
 NS_IMETHODIMP
 nsCryptoRunnable::Run()
 {
   nsNSSShutDownPreventionLock locker;
   JSContext *cx = m_args->m_cx;
 
   JSAutoRequest ar(cx);
-  JSAutoEnterCompartment ac;
-
-  if (!ac.enter(cx, m_args->m_scope)) {
-    return NS_ERROR_FAILURE;
-  }
+  JSAutoCompartment ac(cx, m_args->m_scope);
 
   // make sure the right context is on the stack. must not return w/out popping
   nsCOMPtr<nsIJSContextStack> stack(do_GetService("@mozilla.org/js/xpc/ContextStack;1"));
   if (!stack || NS_FAILED(stack->Push(cx))) {
     return NS_ERROR_FAILURE;
   }
 
   JSBool ok =
--- a/toolkit/components/alerts/mac/ObserverPair.h
+++ b/toolkit/components/alerts/mac/ObserverPair.h
@@ -46,20 +46,17 @@ GetWindowOfObserver(nsIObserver* aObserv
   nsCOMPtr<nsIThreadJSContextStack> stack =
     do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv);
   NS_ENSURE_SUCCESS(rv, nullptr);
 
   JSContext* cx = stack->GetSafeJSContext();
   NS_ENSURE_TRUE(cx, nullptr);
 
   JSAutoRequest ar(cx);
-  JSAutoEnterCompartment ac;
-  if (!ac.enter(cx, obj)) {
-    return nullptr;
-  }
+  JSAutoEnterCompartment ac(cx, obj);
 
   JSObject* global = JS_GetGlobalForObject(cx, obj);
   NS_ENSURE_TRUE(global, nullptr);
 
   nsCOMPtr<nsIXPConnect> xpc(do_GetService(nsIXPConnect::GetCID()));
   NS_ENSURE_TRUE(xpc, nullptr);
 
   nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
--- a/tools/profiler/TableTicker.cpp
+++ b/tools/profiler/TableTicker.cpp
@@ -520,24 +520,20 @@ public:
       stream.open(tmpPath.get());
       // Pause the profiler during saving.
       // This will prevent us from recording sampling
       // regarding profile saving. This will also
       // prevent bugs caused by the circular buffer not
       // being thread safe. Bug 750989.
       t->SetPaused(true);
       if (stream.is_open()) {
-        JSAutoEnterCompartment autoComp;
-        if (autoComp.enter(cx, obj)) {
-          JSObject* profileObj = mozilla_sampler_get_profile_data(cx);
-          jsval val = OBJECT_TO_JSVAL(profileObj);
-          JS_Stringify(cx, &val, nullptr, JSVAL_NULL, WriteCallback, &stream);
-        } else {
-          LOG("Failed to enter compartment");
-        }
+        JSAutoCompartment autoComp(cx, obj);
+        JSObject* profileObj = mozilla_sampler_get_profile_data(cx);
+        jsval val = OBJECT_TO_JSVAL(profileObj);
+        JS_Stringify(cx, &val, nullptr, JSVAL_NULL, WriteCallback, &stream);
         stream.close();
         LOGF("Saved to %s", tmpPath.get());
       } else {
         LOG("Fail to open profile log file.");
       }
     }
     JS_EndRequest(cx);
     JS_DestroyContext(cx);