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 103233 0d61ae018d9f97407a37e327ee526fb018619f62
parent 103232 986c07b3f3e68af098d7e85fd507a7d4139b4eb3
child 103234 1bed30d952cc688c1c5d7575c4bf6574aedfe570
push idunknown
push userunknown
push dateunknown
reviewersbholley
bugs625199
milestone17.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 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);