Always create a dummy stack frame when crossing compartment boundaries (bug 600015, r=mrbkap).
authorAndreas Gal <gal@mozilla.com>
Mon, 27 Sep 2010 15:55:15 -0700
changeset 54733 4c7b72e4d2004137d9a5253363e1210b78df7b04
parent 54732 bc478d4ae805da2a3092f5adf7ff927e8abc92d0
child 54734 878819fe78eace6aede3d5392cd30228f57f96ad
push idunknown
push userunknown
push dateunknown
reviewersmrbkap
bugs600015
milestone2.0b7pre
Always create a dummy stack frame when crossing compartment boundaries (bug 600015, r=mrbkap).
dom/base/nsJSEnvironment.cpp
dom/src/threads/nsDOMThreadService.cpp
dom/src/threads/nsDOMWorker.cpp
dom/src/threads/nsDOMWorker.h
js/jetpack/JetpackChild.cpp
js/jsd/jsd_high.c
js/src/jsapi-tests/testContexts.cpp
js/src/jsapi-tests/tests.h
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jsatom.cpp
js/src/jscompartment.h
js/src/shell/js.cpp
js/src/xpconnect/loader/mozJSComponentLoader.cpp
js/src/xpconnect/loader/mozJSComponentLoader.h
js/src/xpconnect/shell/xpcshell.cpp
js/src/xpconnect/src/XPCSafeJSObjectWrapper.cpp
js/src/xpconnect/src/nsXPConnect.cpp
js/src/xpconnect/src/xpccomponents.cpp
js/src/xpconnect/src/xpcjsruntime.cpp
js/src/xpconnect/src/xpcwrappedjsclass.cpp
js/src/xpconnect/src/xpcwrappednative.cpp
js/src/xpconnect/src/xpcwrappednativescope.cpp
js/src/xpconnect/tests/TestXPC.cpp
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -1481,18 +1481,18 @@ nsJSContext::EvaluateStringWithValue(con
 
   // 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) {
 
     JSAutoRequest ar(mContext);
 
-    JSAutoCrossCompartmentCall accc;
-    if (!accc.enter(mContext, (JSObject *)aScopeObject)) {
+    JSAutoEnterCompartment ac;
+    if (!ac.enter(mContext, (JSObject *)aScopeObject)) {
       JSPRINCIPALS_DROP(mContext, jsprin);
       stack->Pop(nsnull);
       return NS_ERROR_FAILURE;
     }
 
     ++mExecuteDepth;
 
     ok = ::JS_EvaluateUCScriptForPrincipalsVersion(mContext,
@@ -1681,18 +1681,18 @@ 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) {
     JSAutoRequest ar(mContext);
-    JSAutoCrossCompartmentCall accc;
-    if (!accc.enter(mContext, (JSObject *)aScopeObject)) {
+    JSAutoEnterCompartment ac;
+    if (!ac.enter(mContext, (JSObject *)aScopeObject)) {
       stack->Pop(nsnull);
       JSPRINCIPALS_DROP(mContext, jsprin);
       return NS_ERROR_FAILURE;
     }
 
     ok = ::JS_EvaluateUCScriptForPrincipalsVersion(mContext,
                                                    (JSObject *)aScopeObject,
                                                    jsprin,
@@ -2124,18 +2124,18 @@ nsJSContext::CallEventHandler(nsISupport
     rv = ConvertSupportsTojsvals(aargv, target, &argc,
                                  &argv, poolRelease, tvr);
     if (NS_FAILED(rv)) {
       stack->Pop(nsnull);
       return rv;
     }
 
     jsval funval = OBJECT_TO_JSVAL(static_cast<JSObject *>(aHandler));
-    JSAutoCrossCompartmentCall accc;
-    if (!accc.enter(mContext, target)) {
+    JSAutoEnterCompartment ac;
+    if (!ac.enter(mContext, target)) {
       stack->Pop(nsnull);
       return NS_ERROR_FAILURE;
     }
 
     ++mExecuteDepth;
     PRBool ok = ::JS_CallFunctionValue(mContext, target,
                                        funval, argc, argv, &rval);
     --mExecuteDepth;
--- a/dom/src/threads/nsDOMThreadService.cpp
+++ b/dom/src/threads/nsDOMThreadService.cpp
@@ -392,33 +392,33 @@ public:
     // Go ahead and trigger the operation callback for this context before we
     // try to run any JS. That way we'll be sure to cancel or suspend as soon as
     // possible if the compilation takes too long.
     JS_TriggerOperationCallback(cx);
 
     PRBool killWorkerWhenDone;
     {
       nsLazyAutoRequest ar;
-      JSAutoCrossCompartmentCall axcc;
+      JSAutoEnterCompartment ac;
 
       // Tell the worker which context it will be using
-      if (mWorker->SetGlobalForContext(cx, &ar, &axcc)) {
+      if (mWorker->SetGlobalForContext(cx, &ar, &ac)) {
         NS_ASSERTION(ar.entered(), "SetGlobalForContext must enter request on success");
-        NS_ASSERTION(axcc.entered(), "SetGlobalForContext must enter xcc on success");
+        NS_ASSERTION(ac.entered(), "SetGlobalForContext must enter compartment on success");
 
         RunQueue(cx, &killWorkerWhenDone);
 
         // Remove the global object from the context so that it might be garbage
         // collected.
         JS_SetGlobalObject(cx, NULL);
         JS_SetContextPrivate(cx, NULL);
       }
       else {
         NS_ASSERTION(!ar.entered(), "SetGlobalForContext must not enter request on failure");
-        NS_ASSERTION(!axcc.entered(), "SetGlobalForContext must not enter xcc on failure");
+        NS_ASSERTION(!ac.entered(), "SetGlobalForContext must not enter compartment on failure");
 
         {
           // Code in XPConnect assumes that the context's global object won't be
           // replaced outside of a request.
           JSAutoRequest ar2(cx);
 
           // This is usually due to a parse error in the worker script...
           JS_SetGlobalObject(cx, NULL);
--- a/dom/src/threads/nsDOMWorker.cpp
+++ b/dom/src/threads/nsDOMWorker.cpp
@@ -1583,50 +1583,50 @@ nsDOMWorker::PostMessageInternal(PRBool 
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   return NS_OK;
 }
 
 PRBool
 nsDOMWorker::SetGlobalForContext(JSContext* aCx, nsLazyAutoRequest *aRequest,
-                                 JSAutoCrossCompartmentCall *aCall)
+                                 JSAutoEnterCompartment *aComp)
 {
   NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
 
-  if (!CompileGlobalObject(aCx, aRequest, aCall)) {
+  if (!CompileGlobalObject(aCx, aRequest, aComp)) {
     return PR_FALSE;
   }
 
   JS_SetGlobalObject(aCx, mGlobal);
   return PR_TRUE;
 }
 
 PRBool
 nsDOMWorker::CompileGlobalObject(JSContext* aCx, nsLazyAutoRequest *aRequest,
-                                 JSAutoCrossCompartmentCall *aCall)
+                                 JSAutoEnterCompartment *aComp)
 {
   NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
 
   // On success, we enter a request and a cross-compartment call that both
   // belong to the caller. But on failure, we must not remain in a request or
   // cross-compartment call. So we enter both only locally at first. On
   // failure, the local request and call will automatically get cleaned
   // up. Once success is certain, we swap them into *aRequest and *aCall.
   nsLazyAutoRequest localRequest;
-  JSAutoCrossCompartmentCall localCall;
+  JSAutoEnterCompartment localAutoCompartment;
   localRequest.enter(aCx);
 
   PRBool success;
   if (mGlobal) {
-    success = localCall.enter(aCx, mGlobal);
+    success = localAutoCompartment.enter(aCx, mGlobal);
     NS_ENSURE_TRUE(success, PR_FALSE);
 
     aRequest->swap(localRequest);
-    aCall->swap(localCall);
+    aComp->swap(localAutoCompartment);
     return PR_TRUE;
   }
 
   if (mCompileAttempted) {
     // Don't try to recompile a bad script.
     return PR_FALSE;
   }
   mCompileAttempted = PR_TRUE;
@@ -1657,17 +1657,17 @@ nsDOMWorker::CompileGlobalObject(JSConte
   NS_ENSURE_SUCCESS(rv, PR_FALSE);
 
   JSObject* global;
   rv = globalWrapper->GetJSObject(&global);
   NS_ENSURE_SUCCESS(rv, PR_FALSE);
 
   NS_ASSERTION(JS_GetGlobalObject(aCx) == global, "Global object mismatch!");
 
-  success = localCall.enter(aCx, global);
+  success = localAutoCompartment.enter(aCx, global);
   NS_ENSURE_TRUE(success, PR_FALSE);
 
 #ifdef DEBUG
   {
     jsval components;
     if (JS_GetProperty(aCx, global, "Components", &components)) {
       NS_ASSERTION(components == JSVAL_VOID,
                    "Components property still defined!");
@@ -1729,17 +1729,17 @@ nsDOMWorker::CompileGlobalObject(JSConte
     mInnerScope = nsnull;
     mScopeWN = nsnull;
     return PR_FALSE;
   }
 
   NS_ASSERTION(mPrincipal && mURI, "Script loader didn't set our principal!");
 
   aRequest->swap(localRequest);
-  aCall->swap(localCall);
+  aComp->swap(localAutoCompartment);
   return PR_TRUE;
 }
 
 void
 nsDOMWorker::SetPool(nsDOMWorkerPool* aPool)
 {
   NS_ASSERTION(!mPool, "Shouldn't ever set pool more than once!");
   mPool = aPool;
--- a/dom/src/threads/nsDOMWorker.h
+++ b/dom/src/threads/nsDOMWorker.h
@@ -196,17 +196,17 @@ public:
   void Resume();
 
   // This just calls IsCanceledNoLock with an autolock around the call.
   PRBool IsCanceled();
 
   PRBool IsClosing();
   PRBool IsSuspended();
 
-  PRBool SetGlobalForContext(JSContext* aCx, nsLazyAutoRequest *aRequest, JSAutoCrossCompartmentCall *aCall);
+  PRBool SetGlobalForContext(JSContext* aCx, nsLazyAutoRequest *aRequest, JSAutoEnterCompartment *aComp);
 
   void SetPool(nsDOMWorkerPool* aPool);
 
   nsDOMWorkerPool* Pool() {
     return mPool;
   }
 
   PRLock* Lock() {
@@ -280,17 +280,17 @@ public:
     eKilled
   };
 
 private:
   ~nsDOMWorker();
 
   nsresult PostMessageInternal(PRBool aToInner);
 
-  PRBool CompileGlobalObject(JSContext* aCx, nsLazyAutoRequest *aRequest, JSAutoCrossCompartmentCall *aCall);
+  PRBool CompileGlobalObject(JSContext* aCx, nsLazyAutoRequest *aRequest, JSAutoEnterCompartment *aComp);
 
   PRUint32 NextTimeoutId() {
     return ++mNextTimeoutId;
   }
 
   nsresult AddFeature(nsDOMWorkerFeature* aFeature,
                       JSContext* aCx);
   void RemoveFeature(nsDOMWorkerFeature* aFeature,
--- a/js/jetpack/JetpackChild.cpp
+++ b/js/jetpack/JetpackChild.cpp
@@ -426,17 +426,17 @@ JetpackChild::CreateSandbox(JSContext* c
     JS_ReportError(cx, "createSandbox takes zero arguments");
     return JS_FALSE;
   }
 
   JSObject* obj = JS_NewCompartmentAndGlobalObject(cx, const_cast<JSClass*>(&sGlobalClass), NULL);
   if (!obj)
     return JS_FALSE;
 
-  JSAutoCrossCompartmentCall ac;
+  JSAutoEnterCompartment ac;
   if (!ac.enter(cx, obj))
     return JS_FALSE;
 
   JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(obj));
   return JS_InitStandardClasses(cx, obj);
 }
 
 JSBool
@@ -457,17 +457,17 @@ JetpackChild::EvalInSandbox(JSContext* c
     JS_ReportError(cx, "The first argument to evalInSandbox must be a global object created using createSandbox.");
     return JS_FALSE;
   }
 
   JSString* str = JS_ValueToString(cx, argv[1]);
   if (!str)
     return JS_FALSE;
 
-  JSAutoCrossCompartmentCall ac;
+  JSAutoEnterCompartment ac;
   if (!ac.enter(cx, obj))
     return JS_FALSE;
 
   js::AutoValueRooter ignored(cx);
   return JS_EvaluateUCScript(cx, obj, JS_GetStringChars(str), JS_GetStringLength(str), "", 1,
                              ignored.jsval_addr());
 }
 
--- a/js/jsd/jsd_high.c
+++ b/js/jsd/jsd_high.c
@@ -85,17 +85,16 @@ static JSBool
 
 static JSDContext*
 _newJSDContext(JSRuntime*         jsrt, 
                JSD_UserCallbacks* callbacks, 
                void*              user,
                JSObject*          scopeobj)
 {
     JSDContext* jsdc = NULL;
-    JSCompartment *compartment;
 
     if( ! jsrt )
         return NULL;
 
     if( ! _validateUserCallbacks(callbacks) )
         return NULL;
 
     jsdc = (JSDContext*) calloc(1, sizeof(JSDContext));
@@ -134,21 +133,22 @@ static JSDContext*
         goto label_newJSDContext_failure;
 
     jsdc->dumbContext = JS_NewContext(jsdc->jsrt, 256);
     if( ! jsdc->dumbContext )
         goto label_newJSDContext_failure;
 
     JS_BeginRequest(jsdc->dumbContext);
 
+    JSCrossCompartmentCall *call = NULL;
     if( scopeobj )
-        compartment = js_SwitchToObjectCompartment(jsdc->dumbContext, scopeobj);
+        call = JS_EnterCrossCompartmentCall(jsdc->dumbContext, scopeobj);
     jsdc->glob = JS_NewGlobalObject(jsdc->dumbContext, &global_class);
-    if( scopeobj )
-        js_SwitchToCompartment(jsdc->dumbContext, compartment);
+    if( call )
+        JS_LeaveCrossCompartmentCall(call);
     if( ! jsdc->glob )
         goto label_newJSDContext_failure;
 
     if( ! JS_InitStandardClasses(jsdc->dumbContext, jsdc->glob) )
         goto label_newJSDContext_failure;
 
     JS_EndRequest(jsdc->dumbContext);
 
--- a/js/src/jsapi-tests/testContexts.cpp
+++ b/js/src/jsapi-tests/testContexts.cpp
@@ -63,18 +63,20 @@ BEGIN_TEST(testContexts_bug561444)
         ThreadData *d = (ThreadData *) arg;
 
         JSContext *cx = JS_NewContext(d->rt, 8192);
         if (!cx)
             return;
         JS_BeginRequest(cx);
         {
             jsvalRoot v(cx);
-            JSAutoCrossCompartmentCall crossCall;
-            crossCall.enter(cx, d->obj);            
+
+            JSAutoEnterCompartment ac;
+            ac.enterAndIgnoreErrors(cx, d->obj);
+
             if (!JS_EvaluateScript(cx, d->obj, d->code, strlen(d->code), __FILE__, __LINE__, v.addr()))
                 return;
         }
         JS_DestroyContext(cx);
         d->ok = true;
     }
 END_TEST(testContexts_bug561444)
 #endif
@@ -82,18 +84,18 @@ END_TEST(testContexts_bug561444)
 BEGIN_TEST(testContexts_bug563735)
 {
     JSContext *cx2 = JS_NewContext(rt, 8192);
     CHECK(cx2);
 
     JSBool ok;
     {
         JSAutoRequest req(cx2);
-        JSAutoCrossCompartmentCall crossCall;
-        CHECK(crossCall.enter(cx2, global));
+        JSAutoEnterCompartment ac;
+        CHECK(ac.enter(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/tests.h
+++ b/js/src/jsapi-tests/tests.h
@@ -281,17 +281,20 @@ protected:
     }
 
     virtual JSObject * createGlobal() {
         /* Create the global object. */
         JSObject *global = JS_NewCompartmentAndGlobalObject(cx, getGlobalClass(), NULL);
         if (!global)
             return NULL;
 
-        JSAutoEnterCompartment enter(cx, global);
+        JSAutoEnterCompartment ac;
+        if (!ac.enter(cx, global))
+            return NULL;
+
         /* Populate the global object with the standard globals,
            like Object and Array. */
         if (!JS_InitStandardClasses(cx, global))
             return NULL;
         return global;
     }
 };
 
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -1176,39 +1176,29 @@ JS_LeaveCrossCompartmentCall(JSCrossComp
 {
     AutoCompartment *realcall = reinterpret_cast<AutoCompartment *>(call);
     CHECK_REQUEST(realcall->context);
     realcall->leave();
     delete realcall;
 }
 
 bool
-JSAutoCrossCompartmentCall::enter(JSContext *cx, JSObject *target)
+JSAutoEnterCompartment::enter(JSContext *cx, JSObject *target)
 {
     JS_ASSERT(!call);
     if (cx->compartment == target->getCompartment(cx))
         return true;
     call = JS_EnterCrossCompartmentCall(cx, target);
     return call != NULL;
 }
 
-JS_FRIEND_API(JSCompartment *)
-js_SwitchToCompartment(JSContext *cx, JSCompartment *compartment)
-{
-    JSCompartment *c = cx->compartment;
-    cx->compartment = compartment;
-    return c;
-}
-
-JS_FRIEND_API(JSCompartment *)
-js_SwitchToObjectCompartment(JSContext *cx, JSObject *obj)
-{
-    JSCompartment *c = cx->compartment;
-    cx->compartment = obj->getCompartment(cx);
-    return c;
+void
+JSAutoEnterCompartment::enterAndIgnoreErrors(JSContext *cx, JSObject *target)
+{
+    (void) enter(cx, target);
 }
 
 JS_PUBLIC_API(void *)
 JS_SetCompartmentPrivate(JSContext *cx, JSCompartment *compartment, void *data)
 {
     CHECK_REQUEST(cx);
     void *old = compartment->data;
     compartment->data = data;
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -952,63 +952,44 @@ extern JS_PUBLIC_API(void *)
 JS_GetCompartmentPrivate(JSContext *cx, JSCompartment *compartment);
 
 extern JS_PUBLIC_API(JSBool)
 JS_WrapObject(JSContext *cx, JSObject **objp);
 
 extern JS_PUBLIC_API(JSBool)
 JS_WrapValue(JSContext *cx, jsval *vp);
 
-extern JS_FRIEND_API(JSCompartment *)
-js_SwitchToCompartment(JSContext *cx, JSCompartment *compartment);
-
-extern JS_FRIEND_API(JSCompartment *)
-js_SwitchToObjectCompartment(JSContext *cx, JSObject *obj);
-
 #ifdef __cplusplus
 JS_END_EXTERN_C
 
-class JS_PUBLIC_API(JSAutoCrossCompartmentCall)
+class JS_PUBLIC_API(JSAutoEnterCompartment)
 {
     JSCrossCompartmentCall *call;
+
   public:
-    JSAutoCrossCompartmentCall() : call(NULL) {}
+    JSAutoEnterCompartment() : call(NULL) {}
 
     bool enter(JSContext *cx, JSObject *target);
 
+    void enterAndIgnoreErrors(JSContext *cx, JSObject *target);
+
     bool entered() const { return call != NULL; }
 
-    ~JSAutoCrossCompartmentCall() {
+    ~JSAutoEnterCompartment() {
         if (call)
             JS_LeaveCrossCompartmentCall(call);
     }
 
-    void swap(JSAutoCrossCompartmentCall &other) {
+    void swap(JSAutoEnterCompartment &other) {
         JSCrossCompartmentCall *tmp = call;
         call = other.call;
         other.call = tmp;
     }
 };
 
-class JSAutoEnterCompartment
-{
-    JSContext *cx;
-    JSCompartment *compartment;
-  public:
-    JSAutoEnterCompartment(JSContext *cx, JSCompartment *newCompartment) : cx(cx) {
-        compartment = js_SwitchToCompartment(cx, newCompartment);
-    }
-    JSAutoEnterCompartment(JSContext *cx, JSObject *target) : cx(cx) {
-        compartment = js_SwitchToObjectCompartment(cx, target);
-    }
-    ~JSAutoEnterCompartment() {
-        js_SwitchToCompartment(cx, compartment);
-    }
-};
-
 JS_BEGIN_EXTERN_C
 #endif
 
 extern JS_PUBLIC_API(JSObject *)
 JS_GetGlobalObject(JSContext *cx);
 
 extern JS_PUBLIC_API(void)
 JS_SetGlobalObject(JSContext *cx, JSObject *obj);
--- a/js/src/jsatom.cpp
+++ b/js/src/jsatom.cpp
@@ -516,17 +516,18 @@ js_AtomizeString(JSContext *cx, JSString
          * and make the entry invalid.
          */
         if (!(flags & ATOM_TMPSTR) && str->isFlat()) {
             str->flatClearMutable();
             key = str;
             atoms.add(p, StringToInitialAtomEntry(key));
         } else {
             if (flags & ATOM_TMPSTR) {
-                JSAutoEnterCompartment ac(cx, cx->runtime->defaultCompartment);
+                SwitchToCompartment sc(cx, cx->runtime->defaultCompartment);
+
                 if (flags & ATOM_NOCOPY) {
                     key = js_NewString(cx, str->flatChars(), str->flatLength());
                     if (!key)
                         return NULL;
 
                     /* Finish handing off chars to the GC'ed key string. */
                     str->mChars = NULL;
                 } else {
--- a/js/src/jscompartment.h
+++ b/js/src/jscompartment.h
@@ -35,16 +35,17 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef jscompartment_h___
 #define jscompartment_h___
 
+#include "jscntxt.h"
 #include "jsgc.h"
 #include "jsobj.h"
 #include "jsfun.h"
 #include "jsgcstats.h"
 #include "jsclist.h"
 #include "jsxml.h"
 
 struct JSCompartment {
@@ -94,9 +95,39 @@ struct JSCompartment {
     bool addScript(JSContext *cx, JSScript *script);
     void removeScript(JSScript *script);
 #endif
     void purge(JSContext *cx);
     void finishArenaLists();
     bool arenaListsAreEmpty();
 };
 
-#endif /* jscompartment_h___ */
\ No newline at end of file
+namespace js {
+
+class PreserveCompartment {
+  protected:
+    JSContext *cx;
+  private:
+    JSCompartment *oldCompartment;
+  public:
+     PreserveCompartment(JSContext *cx) : cx(cx) {
+        oldCompartment = cx->compartment;
+    }
+
+    ~PreserveCompartment() {
+        cx->compartment = oldCompartment;
+    }
+};
+
+class SwitchToCompartment : public PreserveCompartment {
+  public:
+    SwitchToCompartment(JSContext *cx, JSCompartment *newCompartment) : PreserveCompartment(cx) {
+        cx->compartment = newCompartment;
+    }
+
+    SwitchToCompartment(JSContext *cx, JSObject *target) : PreserveCompartment(cx) {
+        cx->compartment = target->getCompartment(cx);
+    }
+};
+
+}
+
+#endif /* jscompartment_h___ */
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -3160,17 +3160,17 @@ static JSClass sandbox_class = {
 static JSObject *
 NewSandbox(JSContext *cx, bool lazy, bool split)
 {
     JSObject *obj = JS_NewCompartmentAndGlobalObject(cx, &sandbox_class, NULL);
     if (!obj)
         return NULL;
 
     {
-        JSAutoCrossCompartmentCall ac;
+        JSAutoEnterCompartment ac;
         if (!ac.enter(cx, obj))
             return NULL;
 
         if (split) {
             obj = split_setup(cx, JS_TRUE);
             if (!obj)
                 return NULL;
         }
@@ -3221,17 +3221,17 @@ EvalInContext(JSContext *cx, uintN argc,
     }
 
     *vp = OBJECT_TO_JSVAL(sobj);
     if (srclen == 0)
         return true;
 
     JSStackFrame *fp = JS_GetScriptedCaller(cx, NULL);
     {
-        JSAutoCrossCompartmentCall ac;
+        JSAutoEnterCompartment ac;
         if (JSCrossCompartmentWrapper::isCrossCompartmentWrapper(sobj)) {
             sobj = sobj->unwrap();
             if (!ac.enter(cx, sobj))
                 return false;
         }
 
         OBJ_TO_INNER_OBJECT(cx, sobj);
         if (!sobj)
@@ -5147,22 +5147,24 @@ DestroyContext(JSContext *cx, bool withG
 {
     JSShellContextData *data = GetContextData(cx);
     JS_SetContextPrivate(cx, NULL);
     free(data);
     WITH_SIGNALS_DISABLED(withGC ? JS_DestroyContext(cx) : JS_DestroyContextNoGC(cx));
 }
 
 static JSObject *
-NewGlobalObject(JSContext *cx, JSAutoCrossCompartmentCall &call)
+NewGlobalObject(JSContext *cx)
 {
     JSObject *glob = JS_NewCompartmentAndGlobalObject(cx, &global_class, NULL);
     if (!glob)
         return NULL;
-    if (!call.enter(cx, glob))
+
+    JSAutoEnterCompartment ac;
+    if (!ac.enter(cx, glob))
         return NULL;
 
 #ifdef LAZY_STANDARD_CLASSES
     JS_SetGlobalObject(cx, glob);
 #else
     if (!JS_InitStandardClasses(cx, glob))
         return NULL;
 #endif
@@ -5192,22 +5194,25 @@ NewGlobalObject(JSContext *cx, JSAutoCro
 
     return glob;
 }
 
 int
 shell(JSContext *cx, int argc, char **argv, char **envp)
 {
     JSAutoRequest ar(cx);
-    JSAutoCrossCompartmentCall ac;
-
-    JSObject *glob = NewGlobalObject(cx, ac);
+
+    JSObject *glob = NewGlobalObject(cx);
     if (!glob)
         return 1;
 
+    JSAutoEnterCompartment ac;
+    if (!ac.enter(cx, glob))
+        return 1;
+
     JSObject *envobj = JS_DefineObject(cx, glob, "environment", &env_class, NULL, 0);
     if (!envobj || !JS_SetPrivate(cx, envobj, envp))
         return 1;
 
 #ifdef JSDEBUGGER
     /*
     * XXX A command line option to enable debugging (or not) would be good
     */
@@ -5234,18 +5239,17 @@ shell(JSContext *cx, int argc, char **ar
     jsdbc = JSDB_InitDebugger(rt, jsdc, 0);
 #endif /* JSDEBUGGER_C_UI */
 #endif /* JSDEBUGGER */
 
 #ifdef JS_THREADSAFE
     class ShellWorkerHooks : public js::workers::WorkerHooks {
     public:
         JSObject *newGlobalObject(JSContext *cx) {
-            JSAutoCrossCompartmentCall ac;
-            return NewGlobalObject(cx, ac);
+            return NewGlobalObject(cx);
         }
     };
     ShellWorkerHooks hooks;
     if (!JS_AddNamedObjectRoot(cx, &gWorkers, "Workers") ||
         !js::workers::init(cx, &hooks, glob, &gWorkers)) {
         return 1;
     }
 #endif
--- a/js/src/xpconnect/loader/mozJSComponentLoader.cpp
+++ b/js/src/xpconnect/loader/mozJSComponentLoader.cpp
@@ -69,16 +69,17 @@
 #ifndef XPCONNECT_STANDALONE
 #include "nsIScriptSecurityManager.h"
 #include "nsIURI.h"
 #include "nsIFileURL.h"
 #include "nsIJARURI.h"
 #include "nsNetUtil.h"
 #endif
 #include "jsxdrapi.h"
+#include "jscompartment.h"
 #include "jsprf.h"
 // For reporting errors with the console service
 #include "nsIScriptError.h"
 #include "nsIConsoleService.h"
 #include "nsIStorageStream.h"
 #include "nsIStringStream.h"
 #include "prmem.h"
 #include "plbase64.h"
@@ -738,17 +739,17 @@ mozJSComponentLoader::LoadModuleImpl(nsI
         return NULL;
 
     nsCOMPtr<nsIComponentManager> cm;
     rv = NS_GetComponentManager(getter_AddRefs(cm));
     if (NS_FAILED(rv))
         return NULL;
 
     JSCLContextHelper cx(this);
-    JSAutoCrossCompartmentCall ac;
+    JSAutoEnterCompartment ac;
     if (!ac.enter(cx, entry->global))
         return NULL;
 
     JSObject* cm_jsobj;
     nsCOMPtr<nsIXPConnectJSObjectHolder> cm_holder;
     rv = xpc->WrapNative(cx, entry->global, cm, 
                          NS_GET_IID(nsIComponentManager),
                          getter_AddRefs(cm_holder));
@@ -936,18 +937,19 @@ mozJSComponentLoader::GlobalForLocation(
                                         JSObject **aGlobal,
                                         char **aLocation,
                                         jsval *exception)
 {
     nsresult rv;
 
     JSPrincipals* jsPrincipals = nsnull;
     JSCLContextHelper cx(this);
+
     // preserve caller's compartment
-    JSAutoEnterCompartment ac1(cx, (JSCompartment *)NULL);
+    js::PreserveCompartment pc(cx);
     
 #ifndef XPCONNECT_STANDALONE
     rv = mSystemPrincipal->GetJSPrincipals(cx, &jsPrincipals);
     NS_ENSURE_SUCCESS(rv, rv);
 
     JSPrincipalsHolder princHolder(mContext, jsPrincipals);
 #endif
 
@@ -974,17 +976,17 @@ mozJSComponentLoader::GlobalForLocation(
                                                   FLAG_SYSTEM_GLOBAL_OBJECT,
                                               getter_AddRefs(holder));
     NS_ENSURE_SUCCESS(rv, rv);
 
     JSObject *global;
     rv = holder->GetJSObject(&global);
     NS_ENSURE_SUCCESS(rv, rv);
 
-    JSAutoCrossCompartmentCall ac;
+    JSAutoEnterCompartment ac;
     if (!ac.enter(cx, global))
         return NS_ERROR_FAILURE;
 
     if (!JS_DefineFunctions(cx, global, gGlobalFun)) {
         return NS_ERROR_FAILURE;
     }
 
     bool realFile = false;
@@ -1469,17 +1471,18 @@ mozJSComponentLoader::ImportInto(const n
     }
 
     NS_ASSERTION(mod->global, "Import table contains entry with no global");
     *_retval = mod->global;
 
     jsval symbols;
     if (targetObj) {
         JSCLContextHelper cxhelper(this);
-        JSAutoCrossCompartmentCall ac;
+
+        JSAutoEnterCompartment ac;
         if (!ac.enter(mContext, mod->global))
             return NULL;
 
         if (!JS_GetProperty(mContext, mod->global,
                             "EXPORTED_SYMBOLS", &symbols)) {
             return ReportOnCaller(cxhelper, ERROR_NOT_PRESENT,
                                   PromiseFlatCString(aLocation).get());
         }
--- a/js/src/xpconnect/loader/mozJSComponentLoader.h
+++ b/js/src/xpconnect/loader/mozJSComponentLoader.h
@@ -169,17 +169,20 @@ class mozJSComponentLoader : public mozi
             Clear();
         }
 
         void Clear() {
             getfactoryobj = NULL;
 
             if (global) {
                 JSAutoRequest ar(sSelf->mContext);
-                JSAutoEnterCompartment ac(sSelf->mContext, global);
+
+                JSAutoEnterCompartment ac;
+                ac.enterAndIgnoreErrors(sSelf->mContext, global);
+
                 JS_ClearScope(sSelf->mContext, global);
                 JS_RemoveObjectRoot(sSelf->mContext, &global);
             }
 
             if (location)
                 NS_Free(location);
 
             global = NULL;
--- a/js/src/xpconnect/shell/xpcshell.cpp
+++ b/js/src/xpconnect/shell/xpcshell.cpp
@@ -1964,17 +1964,17 @@ main(int argc, char **argv)
         rv = holder->GetJSObject(&glob);
         if (NS_FAILED(rv)) {
             NS_ASSERTION(glob == nsnull, "bad GetJSObject?");
             return 1;
         }
 
         JS_BeginRequest(cx);
         {
-            JSAutoCrossCompartmentCall ac;
+            JSAutoEnterCompartment ac;
             if (!ac.enter(cx, glob)) {
                 JS_EndRequest(cx);
                 return 1;
             }
 
             if (!JS_DefineFunctions(cx, glob, glob_functions)) {
                 JS_EndRequest(cx);
                 return 1;
--- a/js/src/xpconnect/src/XPCSafeJSObjectWrapper.cpp
+++ b/js/src/xpconnect/src/XPCSafeJSObjectWrapper.cpp
@@ -928,18 +928,18 @@ XPC_SJOW_Create(JSContext *cx, uintN arg
   }
 
   {
     SafeCallGuard guard(cx, FindObjectPrincipals(cx, callee, unsafeObj));
     if (!guard.ready()) {
       return JS_FALSE;
     }
 
-    JSAutoCrossCompartmentCall accc;
-    if (!accc.enter(cx, unsafeObj)) {
+    JSAutoEnterCompartment ac;
+    if (!ac.enter(cx, unsafeObj)) {
       return JS_FALSE;
     }
 
     JSObject *scope = JS_GetGlobalForObject(cx, unsafeObj);
     jsval *argv = JS_ARGV(cx, vp);
     for (uintN i = 0; i < argc; ++i) {
       // NB: Passing NONE for a hint here.
       if (!JSVAL_IS_PRIMITIVE(argv[i]) &&
--- a/js/src/xpconnect/src/nsXPConnect.cpp
+++ b/js/src/xpconnect/src/nsXPConnect.cpp
@@ -943,17 +943,19 @@ nsXPConnect::InitClasses(JSContext * aJS
     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);
     SaveFrame sf(aJSContext);
 
-    JSAutoEnterCompartment autoCompartment(ccx, aGlobalJSObj);
+    JSAutoEnterCompartment ac;
+    if (!ac.enter(ccx, aGlobalJSObj))
+        return UnexpectedFailure(NS_ERROR_FAILURE);
 
     xpc_InitJSxIDClassObjects();
 
     XPCWrappedNativeScope* scope =
         XPCWrappedNativeScope::GetNewOrUsed(ccx, aGlobalJSObj);
 
     if(!scope)
         return UnexpectedFailure(NS_ERROR_FAILURE);
@@ -1003,27 +1005,27 @@ xpc_CreateGlobalObject(JSContext *cx, JS
             principal->GetJSPrincipals(cx, &principals);
         tempGlobal = JS_NewCompartmentAndGlobalObject(cx, clasp, principals);
         if(principals)
             JSPRINCIPALS_DROP(cx, principals);
 
         if(!tempGlobal)
             return UnexpectedFailure(NS_ERROR_FAILURE);
 
-        JSAutoEnterCompartment autocompartment(cx, tempGlobal);
-
         *global = tempGlobal;
         *compartment = tempGlobal->getCompartment(cx);
 
+        js::SwitchToCompartment(cx, *compartment);
+
         JS_SetCompartmentPrivate(cx, *compartment, ToNewCString(origin));
         map.Put(origin, *compartment);
     }
     else
     {
-        JSAutoEnterCompartment autocompartment(cx, *compartment);
+        js::SwitchToCompartment(cx, *compartment);
 
         tempGlobal = JS_NewGlobalObject(cx, clasp);
         if(!tempGlobal)
             return UnexpectedFailure(NS_ERROR_FAILURE);
         *global = tempGlobal;
     }
 
     return NS_OK;
@@ -1061,17 +1063,19 @@ nsXPConnect::InitClassesWithNewWrappedGl
 
     JSCompartment* compartment;
     JSObject* tempGlobal;
 
     nsresult rv = xpc_CreateGlobalObject(ccx, &xpcTempGlobalClass, origin,
                                          aPrincipal, &tempGlobal, &compartment);
     NS_ENSURE_SUCCESS(rv, rv);
 
-    JSAutoEnterCompartment autocompartment(ccx, compartment);
+    JSAutoEnterCompartment ac;
+    if (!ac.enter(ccx, tempGlobal))
+        return UnexpectedFailure(NS_ERROR_FAILURE);
 
     PRBool system = (aFlags & nsIXPConnect::FLAG_SYSTEM_GLOBAL_OBJECT) != 0;
     if(system && !JS_MakeSystemObject(aJSContext, tempGlobal))
         return UnexpectedFailure(NS_ERROR_FAILURE);
 
     jsval v;
     nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
     {
--- a/js/src/xpconnect/src/xpccomponents.cpp
+++ b/js/src/xpconnect/src/xpccomponents.cpp
@@ -3265,17 +3265,17 @@ xpc_CreateSandboxObject(JSContext * cx, 
 
     rv = xpc_CreateGlobalObject(cx, &SandboxClass, origin, principal, &sandbox,
                                 &compartment);
     NS_ENSURE_SUCCESS(rv, rv);
 
     js::AutoObjectRooter tvr(cx, sandbox);
 
     {
-        JSAutoCrossCompartmentCall ac;
+        JSAutoEnterCompartment ac;
         if (!ac.enter(cx, sandbox))
             return NS_ERROR_XPC_UNEXPECTED;
 
         // Pass on ownership of sop to |sandbox|.
         if (!JS_SetPrivate(cx, sandbox, sop.forget().get())) {
             return NS_ERROR_XPC_UNEXPECTED;
         }
 
--- a/js/src/xpconnect/src/xpcjsruntime.cpp
+++ b/js/src/xpconnect/src/xpcjsruntime.cpp
@@ -86,17 +86,17 @@ WrappedJSDyingJSObjectFinder(JSDHashTabl
     nsXPCWrappedJS* wrapper = ((JSObject2WrappedJSMap::Entry*)hdr)->value;
     NS_ASSERTION(wrapper, "found a null JS wrapper!");
 
     // walk the wrapper chain and find any whose JSObject is to be finalized
     while(wrapper)
     {
         if(wrapper->IsSubjectToFinalization())
         {
-            JSAutoEnterCompartment ac(data->cx, wrapper->GetJSObject());
+            js::SwitchToCompartment sc(data->cx, wrapper->GetJSObject());
             if(JS_IsAboutToBeFinalized(data->cx, wrapper->GetJSObject()))
                 data->array->AppendElement(wrapper);
         }
         wrapper = wrapper->GetNextWrapper();
     }
     return JS_DHASH_NEXT;
 }
 
--- a/js/src/xpconnect/src/xpcwrappedjsclass.cpp
+++ b/js/src/xpconnect/src/xpcwrappedjsclass.cpp
@@ -242,19 +242,19 @@ nsXPCWrappedJSClass::CallQueryInterfaceO
 {
     JSContext* cx = ccx.GetJSContext();
     JSObject* id;
     jsval retval;
     JSObject* retObj;
     JSBool success = JS_FALSE;
     jsid funid;
     jsval fun;
-    JSAutoCrossCompartmentCall accc;
 
-    if(!accc.enter(cx, jsobj))
+    JSAutoEnterCompartment ac;
+    if(!ac.enter(cx, jsobj))
         return nsnull;
 
     // Don't call the actual function on a content object. We'll determine
     // whether or not a content object is capable of implementing the
     // interface (i.e. whether the interface is scriptable) and most content
     // objects don't have QI implementations anyway. Also see bug 503926.
     if(XPCPerThreadData::IsMainThread(ccx) &&
        !JS_GetGlobalForObject(ccx, jsobj)->isSystem())
@@ -1306,17 +1306,19 @@ nsXPCWrappedJSClass::CallMethod(nsXPCWra
     }
 
     AutoScriptEvaluate scriptEval(cx);
     js::AutoValueVector args(cx);
     ContextPrincipalGuard principalGuard(ccx);
 
     obj = thisObj = wrapper->GetJSObject();
 
-    JSAutoEnterCompartment autoCompartment(ccx, obj);
+    JSAutoEnterCompartment ac;
+    if(!ac.enter(ccx, obj))
+        goto pre_call_clean_up;
 
     // XXX ASSUMES that retval is last arg. The xpidl compiler ensures this.
     paramCount = info->num_args;
     argc = paramCount -
         (paramCount && XPT_PD_IS_RETVAL(info->params[paramCount-1].flags) ? 1 : 0);
 
     if(!cx || !xpcc || !IsReflectable(methodIndex))
         goto pre_call_clean_up;
--- a/js/src/xpconnect/src/xpcwrappednative.cpp
+++ b/js/src/xpconnect/src/xpcwrappednative.cpp
@@ -422,17 +422,17 @@ XPCWrappedNative::GetNewOrUsed(XPCCallCo
 
     jsval newParentVal = JSVAL_NULL;
     XPCMarkableJSVal newParentVal_markable(&newParentVal);
     AutoMarkingJSVal newParentVal_automarker(ccx, &newParentVal_markable);
     JSBool needsSOW = JS_FALSE;
     JSBool needsCOW = JS_FALSE;
     JSBool needsXOW = JS_FALSE;
 
-    JSAutoCrossCompartmentCall accc;
+    JSAutoEnterCompartment ac;
 
     if(sciWrapper.GetFlags().WantPreCreate())
     {
         JSObject* plannedParent = parent;
         nsresult rv = sciWrapper.GetCallback()->PreCreate(identity, ccx,
                                                           parent, &parent);
         if(NS_FAILED(rv))
             return rv;
@@ -452,17 +452,17 @@ XPCWrappedNative::GetNewOrUsed(XPCCallCo
                 XPCWrappedNativeScope::FindInJSObjectScope(ccx, parent);
             if(betterScope != Scope)
                 return GetNewOrUsed(ccx, helper, betterScope, Interface,
                                     isGlobal, resultWrapper);
 
             newParentVal = OBJECT_TO_JSVAL(parent);
         }
 
-        if(!accc.enter(ccx, parent))
+        if(!ac.enter(ccx, parent))
             return NS_ERROR_FAILURE;
 
         // Take the performance hit of checking the hashtable again in case
         // the preCreate call caused the wrapper to get created through some
         // interesting path (the DOM code tends to make this happen sometimes).
 
         if(cache)
         {
@@ -503,17 +503,17 @@ XPCWrappedNative::GetNewOrUsed(XPCCallCo
             }
             DEBUG_CheckWrapperThreadSafety(wrapper);
             *resultWrapper = wrapper;
             return NS_OK;
         }
     }
     else
     {
-        if(!accc.enter(ccx, parent))
+        if(!ac.enter(ccx, parent))
             return NS_ERROR_FAILURE;
 
         nsISupports *Object = helper.Object();
         if(nsXPCWrappedJSClass::IsWrappedJS(Object))
         {
             nsCOMPtr<nsIXPConnectWrappedJS> wrappedjs(do_QueryInterface(Object));
             JSObject *obj;
             wrappedjs->GetJSObject(&obj);
--- a/js/src/xpconnect/src/xpcwrappednativescope.cpp
+++ b/js/src/xpconnect/src/xpcwrappednativescope.cpp
@@ -464,17 +464,19 @@ XPCWrappedNativeScope::FinishedMarkPhase
                  "JSGC_MARK_END without JSGC_FINALIZE_END");
 
     XPCWrappedNativeScope* prev = nsnull;
     XPCWrappedNativeScope* cur = gScopes;
 
     while(cur)
     {
         XPCWrappedNativeScope* next = cur->mNext;
-        JSAutoEnterCompartment ac(cx, cur->mGlobalJSObject);
+
+        js::SwitchToCompartment sc(cx, cur->mGlobalJSObject);
+
         if(cur->mGlobalJSObject &&
            JS_IsAboutToBeFinalized(cx, cur->mGlobalJSObject))
         {
             cur->mGlobalJSObject = nsnull;
 #ifndef XPCONNECT_STANDALONE
             cur->mScriptObjectPrincipal = nsnull;
 #endif
             // Move this scope from the live list to the dying list.
--- a/js/src/xpconnect/tests/TestXPC.cpp
+++ b/js/src/xpconnect/tests/TestXPC.cpp
@@ -817,17 +817,19 @@ int main()
         // is not working now in the new xpconnect code.
 
         {
             JSAutoRequest ar(jscontext);
             glob = JS_NewCompartmentAndGlobalObject(jscontext, &global_class, NULL);
             if (!glob)
                 DIE("FAILED to create global object");
 
-            JSAutoEnterCompartment autoCompartment(jscontext, glob);
+            JSAutoEnterCompartment ac;
+            if (!ac.enter(jscontext, glob))
+                DIE("FAILED to enter compartment");
 
             if (!JS_InitStandardClasses(jscontext, glob))
                 DIE("FAILED to init standard classes");
             if (!JS_DefineFunctions(jscontext, glob, glob_functions))
                 DIE("FAILED to define global functions");
             if (NS_FAILED(xpc->InitClasses(jscontext, glob)))
                 DIE("FAILED to init xpconnect classes");
         }