Merge inbound to mozilla-central. a=merge
authorBogdan Tara <btara@mozilla.com>
Sun, 29 Jul 2018 00:48:22 +0300
changeset 483969 71922e0cd9e1
parent 483950 33ff92501b9b (current diff)
parent 483968 a05794e50453 (diff)
child 483972 aeb561443c6d
child 483974 f73745f402df
push id9719
push userffxbld-merge
push dateFri, 24 Aug 2018 17:49:46 +0000
treeherdermozilla-beta@719ec98fba77 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone63.0a1
first release with
nightly linux32
71922e0cd9e1 / 63.0a1 / 20180728220145 / files
nightly linux64
71922e0cd9e1 / 63.0a1 / 20180728220145 / files
nightly mac
71922e0cd9e1 / 63.0a1 / 20180728220145 / files
nightly win32
71922e0cd9e1 / 63.0a1 / 20180728220145 / files
nightly win64
71922e0cd9e1 / 63.0a1 / 20180728220145 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to mozilla-central. a=merge
--- a/build/clang-plugin/mozsearch-plugin/MozsearchIndexer.cpp
+++ b/build/clang-plugin/mozsearch-plugin/MozsearchIndexer.cpp
@@ -568,17 +568,17 @@ public:
     const FunctionDecl *Def;
     // See TraverseFunctionDecl.
     if (TemplateStack && D->isDefined(Def) && Def && D != Def) {
       TraverseFunctionDecl(const_cast<FunctionDecl *>(Def));
     }
     return Super::TraverseCXXMethodDecl(D);
   }
   bool TraverseCXXConstructorDecl(CXXConstructorDecl *D) {
-    AutoSetContext Asc(this, D, true);
+    AutoSetContext Asc(this, D, /*VisitImplicit=*/true);
     const FunctionDecl *Def;
     // See TraverseFunctionDecl.
     if (TemplateStack && D->isDefined(Def) && Def && D != Def) {
       TraverseFunctionDecl(const_cast<FunctionDecl *>(Def));
     }
     return Super::TraverseCXXConstructorDecl(D);
   }
   bool TraverseCXXConversionDecl(CXXConversionDecl *D) {
@@ -794,18 +794,17 @@ public:
   bool shouldVisitTemplateInstantiations() const {
     if (TemplateStack) {
       return TemplateStack->shouldVisitTemplateInstantiations();
     }
     return false;
   }
 
   bool shouldVisitImplicitCode() const {
-    AutoSetContext *Ctxt = CurDeclContext;
-    return Ctxt ? Ctxt->VisitImplicit : false;
+    return CurDeclContext && CurDeclContext->VisitImplicit;
   }
 
   bool TraverseClassTemplateDecl(ClassTemplateDecl *D) {
     AutoTemplateContext Atc(this);
     Super::TraverseClassTemplateDecl(D);
 
     if (!Atc.needsAnalysis()) {
       return true;
--- a/devtools/shared/heapsnapshot/tests/gtest/DevTools.h
+++ b/devtools/shared/heapsnapshot/tests/gtest/DevTools.h
@@ -89,17 +89,17 @@ struct DevTools : public ::testing::Test
     /* Create the global object. */
     JS::RootedObject newGlobal(cx);
     JS::RealmOptions options;
     newGlobal = JS_NewGlobalObject(cx, getGlobalClass(), nullptr,
                                    JS::FireOnNewGlobalHook, options);
     if (!newGlobal)
       return nullptr;
 
-    JSAutoRealm ar(cx, newGlobal);
+    JSAutoRealmAllowCCW ar(cx, newGlobal);
 
     /* Populate the global object with the standard globals, like Object and
        Array. */
     if (!JS::InitRealmStandardClasses(cx))
       return nullptr;
 
     return newGlobal;
   }
--- a/devtools/shared/heapsnapshot/tests/gtest/DoesCrossCompartmentBoundaries.cpp
+++ b/devtools/shared/heapsnapshot/tests/gtest/DoesCrossCompartmentBoundaries.cpp
@@ -13,17 +13,17 @@ DEF_TEST(DoesCrossCompartmentBoundaries,
     JS::RootedObject newGlobal(cx, JS_NewGlobalObject(cx,
                                                       getGlobalClass(),
                                                       nullptr,
                                                       JS::FireOnNewGlobalHook,
                                                       options));
     ASSERT_TRUE(newGlobal);
     JS::Compartment* newCompartment = nullptr;
     {
-      JSAutoRealm ar(cx, newGlobal);
+      JSAutoRealmAllowCCW ar(cx, newGlobal);
       ASSERT_TRUE(JS::InitRealmStandardClasses(cx));
       newCompartment = js::GetContextCompartment(cx);
     }
     ASSERT_TRUE(newCompartment);
     ASSERT_NE(newCompartment, compartment);
 
     // Our set of target compartments is both the old and new compartments.
     JS::CompartmentSet targetCompartments;
--- a/devtools/shared/heapsnapshot/tests/gtest/DoesntCrossCompartmentBoundaries.cpp
+++ b/devtools/shared/heapsnapshot/tests/gtest/DoesntCrossCompartmentBoundaries.cpp
@@ -13,17 +13,17 @@ DEF_TEST(DoesntCrossCompartmentBoundarie
     JS::RootedObject newGlobal(cx, JS_NewGlobalObject(cx,
                                                       getGlobalClass(),
                                                       nullptr,
                                                       JS::FireOnNewGlobalHook,
                                                       options));
     ASSERT_TRUE(newGlobal);
     JS::Compartment* newCompartment = nullptr;
     {
-      JSAutoRealm ar(cx, newGlobal);
+      JSAutoRealmAllowCCW ar(cx, newGlobal);
       ASSERT_TRUE(JS::InitRealmStandardClasses(cx));
       newCompartment = js::GetContextCompartment(cx);
     }
     ASSERT_TRUE(newCompartment);
     ASSERT_NE(newCompartment, compartment);
 
     // Our set of target compartments is only the pre-existing compartment and
     // does not include the new compartment.
--- a/dom/base/ChromeUtils.cpp
+++ b/dom/base/ChromeUtils.cpp
@@ -212,17 +212,17 @@ ChromeUtils::ShallowClone(GlobalObject& 
       return;
     }
 
     if (js::IsScriptedProxy(obj)) {
       JS_ReportErrorASCII(cx, "Shallow cloning a proxy object is not allowed");
       return;
     }
 
-    JSAutoRealm ar(cx, obj);
+    JSAutoRealmAllowCCW ar(cx, obj);
 
     if (!JS_Enumerate(cx, obj, &ids) ||
         !values.reserve(ids.length())) {
       return;
     }
 
     JS::Rooted<JS::PropertyDescriptor> desc(cx);
     JS::RootedId id(cx);
@@ -235,17 +235,17 @@ ChromeUtils::ShallowClone(GlobalObject& 
         continue;
       }
       values.infallibleAppend(desc.value());
     }
   }
 
   JS::RootedObject obj(cx);
   {
-    Maybe<JSAutoRealm> ar;
+    Maybe<JSAutoRealmAllowCCW> ar;
     if (aTarget) {
       JS::RootedObject target(cx, js::CheckedUnwrap(aTarget));
       if (!target) {
         js::ReportAccessDenied(cx);
         return;
       }
       ar.emplace(cx, target);
     }
@@ -478,17 +478,17 @@ namespace module_getter {
     nsresult rv = moduleloader->Import(aCx, uri, &moduleGlobal, &moduleExports);
     if (NS_FAILED(rv)) {
       Throw(aCx, rv);
       return false;
     }
 
     JS::RootedValue value(aCx);
     {
-      JSAutoRealm ar(aCx, moduleExports);
+      JSAutoRealmAllowCCW ar(aCx, moduleExports);
 
       if (!JS_GetPropertyById(aCx, moduleExports, id, &value)) {
         return false;
       }
     }
 
     if (!JS_WrapValue(aCx, &value) ||
         !JS_DefinePropertyById(aCx, thisObj, id, value,
@@ -721,17 +721,17 @@ ChromeUtils::CreateError(const GlobalObj
   });
 
   JS::RootedObject retVal(cx);
   {
     JS::RootedString fileName(cx, JS_GetEmptyString(cx));
     uint32_t line = 0;
     uint32_t column = 0;
 
-    Maybe<JSAutoRealm> ar;
+    Maybe<JSAutoRealmAllowCCW> ar;
     JS::RootedObject stack(cx);
     if (aStack) {
       stack = UncheckedUnwrap(aStack);
       ar.emplace(cx, stack);
 
       JSPrincipals* principals = JS::GetRealmPrincipals(js::GetContextRealm(cx));
       if (JS::GetSavedFrameLine(cx, principals, stack, &line) != JS::SavedFrameResult::Ok ||
           JS::GetSavedFrameColumn(cx, principals, stack, &column) != JS::SavedFrameResult::Ok ||
--- a/dom/base/Element.cpp
+++ b/dom/base/Element.cpp
@@ -3742,17 +3742,17 @@ Element::Animate(const Nullable<ElementO
     KeyframeEffect::Constructor(global, aTarget, aKeyframes, aOptions,
                                 aError);
   if (aError.Failed()) {
     return nullptr;
   }
 
   // Animation constructor follows the standard Xray calling convention and
   // needs to be called in the target element's realm.
-  Maybe<JSAutoRealm> ar;
+  Maybe<JSAutoRealmAllowCCW> ar;
   if (js::GetContextCompartment(aContext) !=
       js::GetObjectCompartment(ownerGlobal->GetGlobalJSObject())) {
     ar.emplace(aContext, ownerGlobal->GetGlobalJSObject());
   }
 
   AnimationTimeline* timeline = referenceElement->OwnerDoc()->Timeline();
   RefPtr<Animation> animation =
     Animation::Constructor(global, effect,
--- a/dom/base/IntlUtils.cpp
+++ b/dom/base/IntlUtils.cpp
@@ -83,17 +83,17 @@ IntlUtils::GetDisplayNames(const Sequenc
   }
 
   if (!retVal.isObject()) {
     aError.Throw(NS_ERROR_FAILURE);
     return;
   }
 
   // Return the result as DisplayNameResult.
-  JSAutoRealm ar(cx, &retVal.toObject());
+  JSAutoRealmAllowCCW ar(cx, &retVal.toObject());
   if (!aResult.Init(cx, retVal)) {
     aError.Throw(NS_ERROR_FAILURE);
   }
 }
 
 void
 IntlUtils::GetLocaleInfo(const Sequence<nsString>& aLocales,
                          LocaleInfo& aResult, ErrorResult& aError)
@@ -130,16 +130,16 @@ IntlUtils::GetLocaleInfo(const Sequence<
   }
 
   if (!retVal.isObject()) {
     aError.Throw(NS_ERROR_FAILURE);
     return;
   }
 
   // Return the result as LocaleInfo.
-  JSAutoRealm ar(cx, &retVal.toObject());
+  JSAutoRealmAllowCCW ar(cx, &retVal.toObject());
   if (!aResult.Init(cx, retVal)) {
     aError.Throw(NS_ERROR_FAILURE);
   }
 }
 
 } // dom namespace
 } // mozilla namespace
--- a/dom/base/PostMessageEvent.cpp
+++ b/dom/base/PostMessageEvent.cpp
@@ -72,17 +72,17 @@ PostMessageEvent::Run()
   // that's probably better than crashing.
 
   RefPtr<nsGlobalWindowInner> targetWindow;
   if (mTargetWindow->IsClosedOrClosing() ||
       !(targetWindow = mTargetWindow->GetCurrentInnerWindowInternal()) ||
       targetWindow->IsDying())
     return NS_OK;
 
-  JSAutoRealm ar(cx, targetWindow->GetWrapper());
+  JSAutoRealmAllowCCW ar(cx, targetWindow->GetWrapper());
 
   // Ensure that any origin which might have been provided is the origin of this
   // window's document.  Note that we do this *now* instead of when postMessage
   // is called because the target window might have been navigated to a
   // different location between then and now.  If this check happened when
   // postMessage was called, it would be fairly easy for a malicious webpage to
   // intercept messages intended for another site by carefully timing navigation
   // of the target window so it changed location after postMessage but before
--- a/dom/base/StructuredCloneBlob.cpp
+++ b/dom/base/StructuredCloneBlob.cpp
@@ -33,17 +33,17 @@ StructuredCloneBlob::~StructuredCloneBlo
 StructuredCloneBlob::Constructor(GlobalObject& aGlobal, JS::HandleValue aValue,
                                  JS::HandleObject aTargetGlobal,
                                  ErrorResult& aRv)
 {
   JSContext* cx = aGlobal.Context();
 
   RefPtr<StructuredCloneBlob> holder = StructuredCloneBlob::Create();
 
-  Maybe<JSAutoRealm> ar;
+  Maybe<JSAutoRealmAllowCCW> ar;
   JS::RootedValue value(cx, aValue);
 
   if (aTargetGlobal) {
     JS::RootedObject targetGlobal(cx, js::CheckedUnwrap(aTargetGlobal));
     if (!targetGlobal) {
       js::ReportAccessDenied(cx);
       aRv.NoteJSContextException(cx);
       return nullptr;
@@ -82,17 +82,17 @@ StructuredCloneBlob::Deserialize(JSConte
   JS::RootedObject scope(aCx, js::CheckedUnwrap(aTargetScope));
   if (!scope) {
     js::ReportAccessDenied(aCx);
     aRv.NoteJSContextException(aCx);
     return;
   }
 
   {
-    JSAutoRealm ar(aCx, scope);
+    JSAutoRealmAllowCCW ar(aCx, scope);
 
     Read(xpc::NativeGlobal(scope), aCx, aResult, aRv);
     if (aRv.Failed()) {
       return;
     }
   }
 
   if (!JS_WrapValue(aCx, aResult)) {
--- a/dom/base/nsContentPermissionHelper.cpp
+++ b/dom/base/nsContentPermissionHelper.cpp
@@ -708,17 +708,17 @@ nsContentPermissionRequestProxy::Allow(J
     for (uint32_t i = 0; i < mPermissionRequests.Length(); ++i) {
       nsCString type = mPermissionRequests[i].type();
 
       AutoJSAPI jsapi;
       jsapi.Init();
 
       JSContext* cx = jsapi.cx();
       JS::Rooted<JSObject*> obj(cx, &aChoices.toObject());
-      JSAutoRealm ar(cx, obj);
+      JSAutoRealmAllowCCW ar(cx, obj);
 
       JS::Rooted<JS::Value> val(cx);
 
       if (!JS_GetProperty(cx, obj, type.BeginReading(), &val) ||
           !val.isString()) {
         // no setting for the permission type, clear exception and skip it
         jsapi.ClearException();
       } else {
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -7023,17 +7023,17 @@ nsContentUtils::IsPatternMatching(nsAStr
 {
   NS_ASSERTION(aDocument, "aDocument should be a valid pointer (not null)");
 
   AutoJSContext cx;
   AutoDisableJSInterruptCallback disabler(cx);
 
   // We can use the junk scope here, because we're just using it for
   // regexp evaluation, not actual script execution.
-  JSAutoRealm ar(cx, xpc::UnprivilegedJunkScope());
+  JSAutoRealmAllowCCW ar(cx, xpc::UnprivilegedJunkScope());
 
   // The pattern has to match the entire value.
   aPattern.InsertLiteral(u"^(?:", 0);
   aPattern.AppendLiteral(")$");
 
   JS::Rooted<JSObject*> re(cx,
     JS_NewUCRegExpObject(cx,
                          static_cast<char16_t*>(aPattern.BeginWriting()),
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -6965,17 +6965,17 @@ nsIDocument::AdoptNode(nsINode& aAdopted
   JS::Rooted<JSObject*> newScope(cx, nullptr);
   if (!sameDocument) {
     newScope = GetWrapper();
     if (!newScope && GetScopeObject() && GetScopeObject()->GetGlobalJSObject()) {
       // Make sure cx is in a semi-sane compartment before we call WrapNative.
       // It's kind of irrelevant, given that we're passing aAllowWrapping =
       // false, and documents should always insist on being wrapped in an
       // canonical scope. But we try to pass something sane anyway.
-      JSAutoRealm ar(cx, GetScopeObject()->GetGlobalJSObject());
+      JSAutoRealmAllowCCW ar(cx, GetScopeObject()->GetGlobalJSObject());
       JS::Rooted<JS::Value> v(cx);
       rv = nsContentUtils::WrapNative(cx, this, this, &v,
                                       /* aAllowWrapping = */ false);
       if (rv.Failed())
         return nullptr;
       newScope = &v.toObject();
     }
   }
@@ -9610,17 +9610,17 @@ nsIDocument::GetStateObject(nsIVariant**
   // current state object.
 
   if (!mStateObjectCached && mStateObjectContainer) {
     AutoJSContext cx;
     nsIGlobalObject* sgo = GetScopeObject();
     NS_ENSURE_TRUE(sgo, NS_ERROR_UNEXPECTED);
     JS::Rooted<JSObject*> global(cx, sgo->GetGlobalJSObject());
     NS_ENSURE_TRUE(global, NS_ERROR_UNEXPECTED);
-    JSAutoRealm ar(cx, global);
+    JSAutoRealmAllowCCW ar(cx, global);
 
     mStateObjectContainer->
       DeserializeToVariant(cx, getter_AddRefs(mStateObjectCached));
   }
 
   NS_IF_ADDREF(*aState = mStateObjectCached);
   return NS_OK;
 }
--- a/dom/base/nsFrameLoader.cpp
+++ b/dom/base/nsFrameLoader.cpp
@@ -1890,17 +1890,17 @@ nsFrameLoader::SetOwnerContent(Element* 
   }
   mOwnerContent = aContent;
 
   AutoJSAPI jsapi;
   jsapi.Init();
 
   JS::RootedObject wrapper(jsapi.cx(), GetWrapper());
   if (wrapper) {
-    JSAutoRealm ar(jsapi.cx(), wrapper);
+    JSAutoRealmAllowCCW ar(jsapi.cx(), wrapper);
     IgnoredErrorResult rv;
     ReparentWrapper(jsapi.cx(), wrapper, rv);
     Unused << NS_WARN_IF(rv.Failed());
   }
 
   if (RenderFrameParent* rfp = GetCurrentRenderFrame()) {
     rfp->OwnerContentChanged(aContent);
   }
--- a/dom/base/nsFrameMessageManager.cpp
+++ b/dom/base/nsFrameMessageManager.cpp
@@ -750,17 +750,17 @@ nsFrameMessageManager::ReceiveMessage(ns
 
       AutoEntryScript aes(js::UncheckedUnwrap(object), "message manager handler");
       JSContext* cx = aes.cx();
 
       // We passed the unwrapped object to AutoEntryScript so we now need to
       // enter the (maybe wrapper) object's realm. We will have to revisit this
       // later because CCWs are not associated with a single realm so this
       // doesn't make much sense. See bug 1477923.
-      JSAutoRealm ar(cx, object);
+      JSAutoRealmAllowCCW ar(cx, object);
 
       RootedDictionary<ReceiveMessageArgument> argument(cx);
 
       JS::Rooted<JSObject*> cpows(cx);
       if (aCpows && !aCpows->ToObject(cx, &cpows)) {
         aError.Throw(NS_ERROR_UNEXPECTED);
         return;
       }
@@ -996,17 +996,17 @@ nsFrameMessageManager::GetInitialProcess
   MOZ_ASSERT(mIsProcessManager);
   MOZ_ASSERT_IF(mChrome, IsBroadcaster());
 
   JS::RootedValue init(aCx, mInitialProcessData);
   if (mChrome && init.isUndefined()) {
     // We create the initial object in the junk scope. If we created it in a
     // normal realm, that realm would leak until shutdown.
     JS::RootedObject global(aCx, xpc::PrivilegedJunkScope());
-    JSAutoRealm ar(aCx, global);
+    JSAutoRealmAllowCCW ar(aCx, global);
 
     JS::RootedObject obj(aCx, JS_NewPlainObject(aCx));
     if (!obj) {
       aError.NoteJSContextException(aCx);
       return;
     }
 
     mInitialProcessData.setObject(*obj);
--- a/dom/base/nsGlobalWindowInner.cpp
+++ b/dom/base/nsGlobalWindowInner.cpp
@@ -4158,17 +4158,17 @@ nsGlobalWindowInner::CallerInnerWindow()
 
   // When Jetpack runs content scripts inside a sandbox, it uses
   // sandboxPrototype to make them appear as though they're running in the
   // scope of the page. So when a content script invokes postMessage, it expects
   // the |source| of the received message to be the window set as the
   // sandboxPrototype. This used to work incidentally for unrelated reasons, but
   // now we need to do some special handling to support it.
   if (xpc::IsSandbox(scope)) {
-    JSAutoRealm ar(cx, scope);
+    JSAutoRealmAllowCCW ar(cx, scope);
     JS::Rooted<JSObject*> scopeProto(cx);
     bool ok = JS_GetPrototype(cx, scope, &scopeProto);
     NS_ENSURE_TRUE(ok, nullptr);
     if (scopeProto && xpc::IsSandboxPrototypeProxy(scopeProto) &&
         (scopeProto = js::CheckedUnwrap(scopeProto, /* stopAtWindowProxy = */ false)))
     {
       global = xpc::NativeGlobal(scopeProto);
       NS_ENSURE_TRUE(global, nullptr);
--- a/dom/base/nsGlobalWindowOuter.cpp
+++ b/dom/base/nsGlobalWindowOuter.cpp
@@ -791,17 +791,17 @@ nsChromeOuterWindowProxy::className(JSCo
 const nsChromeOuterWindowProxy
 nsChromeOuterWindowProxy::singleton;
 
 static JSObject*
 NewOuterWindowProxy(JSContext *cx, JS::Handle<JSObject*> global, bool isChrome)
 {
   MOZ_ASSERT(JS_IsGlobalObject(global));
 
-  JSAutoRealm ar(cx, global);
+  JSAutoRealmAllowCCW ar(cx, global);
 
   js::WrapperOptions options;
   options.setClass(&OuterWindowProxyClass);
   options.setSingleton(true);
   JSObject *obj = js::Wrapper::New(cx, global,
                                    isChrome ? &nsChromeOuterWindowProxy::singleton
                                             : &nsOuterWindowProxy::singleton,
                                    options);
@@ -1526,17 +1526,17 @@ EnablePrivilege(JSContext* cx, unsigned 
 static const JSFunctionSpec EnablePrivilegeSpec[] = {
   JS_FN("enablePrivilege", EnablePrivilege, 1, 0),
   JS_FS_END
 };
 
 static bool
 InitializeLegacyNetscapeObject(JSContext* aCx, JS::Handle<JSObject*> aGlobal)
 {
-  JSAutoRealm ar(aCx, aGlobal);
+  JSAutoRealmAllowCCW ar(aCx, aGlobal);
 
   // Note: MathJax depends on window.netscape being exposed. See bug 791526.
   JS::Rooted<JSObject*> obj(aCx);
   obj = JS_DefineObject(aCx, aGlobal, "netscape", nullptr);
   NS_ENSURE_TRUE(obj, false);
 
   obj = JS_DefineObject(aCx, obj, "security", nullptr);
   NS_ENSURE_TRUE(obj, false);
@@ -1863,17 +1863,17 @@ nsGlobalWindowOuter::SetNewDocument(nsID
 
       MOZ_ASSERT(JS::GetNonCCWObjectGlobal(outerObject) == newInnerGlobal);
 
       // Inform the nsJSContext, which is the canonical holder of the outer.
       mContext->SetWindowProxy(outerObject);
     }
 
     // Enter the new global's realm.
-    JSAutoRealm ar(cx, GetWrapperPreserveColor());
+    JSAutoRealmAllowCCW ar(cx, GetWrapperPreserveColor());
 
     {
       JS::Rooted<JSObject*> outer(cx, GetWrapperPreserveColor());
       js::SetWindowProxy(cx, newInnerGlobal, outer);
     }
 
     // Set scriptability based on the state of the docshell.
     bool allow = GetDocShell()->GetCanExecuteScripts();
@@ -1895,17 +1895,17 @@ nsGlobalWindowOuter::SetNewDocument(nsID
       // And same thing for the "self" property.
       if (!JS_GetProperty(cx, newInnerGlobal, "self", &unused)) {
         NS_ERROR("can't create the 'self' property");
         return NS_ERROR_FAILURE;
       }
     }
   }
 
-  JSAutoRealm ar(cx, GetWrapperPreserveColor());
+  JSAutoRealmAllowCCW ar(cx, GetWrapperPreserveColor());
 
   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.
     MOZ_ASSERT(mContext->GetWindowProxy() == GetWrapperPreserveColor());
@@ -3792,17 +3792,17 @@ nsGlobalWindowOuter::DispatchResizeEvent
     return false;
   }
 
   // We don't init the AutoJSAPI with ourselves because we don't want it
   // reporting errors to our onerror handlers.
   AutoJSAPI jsapi;
   jsapi.Init();
   JSContext* cx = jsapi.cx();
-  JSAutoRealm ar(cx, GetWrapperPreserveColor());
+  JSAutoRealmAllowCCW ar(cx, GetWrapperPreserveColor());
 
   DOMWindowResizeEventDetail detail;
   detail.mWidth = aSize.width;
   detail.mHeight = aSize.height;
   JS::Rooted<JS::Value> detailValue(cx);
   if (!ToJSValue(cx, detail, &detailValue)) {
     return false;
   }
@@ -5659,17 +5659,17 @@ nsGlobalWindowOuter::CallerInnerWindow()
 
   // When Jetpack runs content scripts inside a sandbox, it uses
   // sandboxPrototype to make them appear as though they're running in the
   // scope of the page. So when a content script invokes postMessage, it expects
   // the |source| of the received message to be the window set as the
   // sandboxPrototype. This used to work incidentally for unrelated reasons, but
   // now we need to do some special handling to support it.
   if (xpc::IsSandbox(scope)) {
-    JSAutoRealm ar(cx, scope);
+    JSAutoRealmAllowCCW ar(cx, scope);
     JS::Rooted<JSObject*> scopeProto(cx);
     bool ok = JS_GetPrototype(cx, scope, &scopeProto);
     NS_ENSURE_TRUE(ok, nullptr);
     if (scopeProto && xpc::IsSandboxPrototypeProxy(scopeProto) &&
         (scopeProto = js::CheckedUnwrap(scopeProto, /* stopAtWindowProxy = */ false)))
     {
       global = xpc::NativeGlobal(scopeProto);
       NS_ENSURE_TRUE(global, nullptr);
@@ -7210,17 +7210,17 @@ nsresult
 nsGlobalWindowOuter::SecurityCheckURL(const char *aURL, nsIURI** aURI)
 {
   nsCOMPtr<nsPIDOMWindowInner> sourceWindow = do_QueryInterface(GetEntryGlobal());
   if (!sourceWindow) {
     sourceWindow = GetCurrentInnerWindow();
   }
   AutoJSContext cx;
   nsGlobalWindowInner* sourceWin = nsGlobalWindowInner::Cast(sourceWindow);
-  JSAutoRealm ar(cx, sourceWin->GetGlobalJSObject());
+  JSAutoRealmAllowCCW ar(cx, sourceWin->GetGlobalJSObject());
 
   // Resolve the baseURI, which could be relative to the calling window.
   //
   // Note the algorithm to get the base URI should match the one
   // used to actually kick off the load in nsWindowWatcher.cpp.
   nsCOMPtr<nsIDocument> doc = sourceWindow->GetDoc();
   nsIURI* baseURI = nullptr;
   auto encoding = UTF_8_ENCODING; // default to utf-8
--- a/dom/base/nsINode.cpp
+++ b/dom/base/nsINode.cpp
@@ -1291,17 +1291,17 @@ CheckForOutdatedParent(nsINode* aParent,
     JS::Rooted<JSObject*> existingObj(RootingCx(), existingObjUnrooted);
 
     AutoJSContext cx;
     nsIGlobalObject* global = aParent->OwnerDoc()->GetScopeObject();
     MOZ_ASSERT(global);
 
     if (JS::GetNonCCWObjectGlobal(existingObj) !=
         global->GetGlobalJSObject()) {
-      JSAutoRealm ar(cx, existingObj);
+      JSAutoRealmAllowCCW ar(cx, existingObj);
       ReparentWrapper(cx, existingObj, aError);
     }
   }
 }
 
 static nsresult
 ReparentWrappersInSubtree(nsIContent* aRoot)
 {
@@ -1311,17 +1311,17 @@ ReparentWrappersInSubtree(nsIContent* aR
   jsapi.Init();
 
   JSContext* cx = jsapi.cx();
 
   ErrorResult rv;
   JS::Rooted<JSObject*> reflector(cx);
   for (nsIContent* cur = aRoot; cur; cur = cur->GetNextNode(aRoot)) {
     if ((reflector = cur->GetWrapper())) {
-      JSAutoRealm ar(cx, reflector);
+      JSAutoRealmAllowCCW ar(cx, reflector);
       ReparentWrapper(cx, reflector, rv);
       rv.WouldReportJSException();
       if (rv.Failed()) {
         // We _could_ consider BlastSubtreeToPieces here, but it's not really
         // needed.  Having some nodes in here accessible to content while others
         // are not is probably OK.  We just need to fail out of the actual
         // insertion, so they're not in the DOM.  Returning a failure here will
         // do that.
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -808,17 +808,17 @@ nsJSContext::ConvertSupportsTojsvals(nsI
           // just wrap it.
 #ifdef DEBUG
           // but first, check its not another nsISupportsPrimitive, as
           // these are now deprecated for use with script contexts.
           nsCOMPtr<nsISupportsPrimitive> prim(do_QueryInterface(arg));
           NS_ASSERTION(prim == nullptr,
                        "Don't pass nsISupportsPrimitives - use nsIVariant!");
 #endif
-          JSAutoRealm ar(cx, aScope);
+          JSAutoRealmAllowCCW ar(cx, aScope);
           rv = nsContentUtils::WrapNative(cx, arg, thisVal);
         }
       }
     }
   } else {
     nsCOMPtr<nsIVariant> variant = do_QueryInterface(aArgs);
     if (variant) {
       rv = xpc->VariantToJS(cx, aScope, variant, aArgsOut[0]);
@@ -999,17 +999,17 @@ nsJSContext::AddSupportsPrimitiveTojsval
       p->GetData(getter_AddRefs(data));
       p->GetDataIID(&iid);
       NS_ENSURE_TRUE(iid, NS_ERROR_UNEXPECTED);
 
       AutoFree iidGuard(iid); // Free iid upon destruction.
 
       JS::Rooted<JSObject*> scope(cx, GetWindowProxy());
       JS::Rooted<JS::Value> v(cx);
-      JSAutoRealm ar(cx, scope);
+      JSAutoRealmAllowCCW ar(cx, scope);
       nsresult rv = nsContentUtils::WrapNative(cx, data, iid, &v);
       NS_ENSURE_SUCCESS(rv, rv);
 
       *aArgv = v;
 
       break;
     }
     case nsISupportsPrimitive::TYPE_ID :
@@ -1134,17 +1134,17 @@ static const JSFunctionSpec JProfFunctio
 #endif /* defined(MOZ_JPROF) */
 
 nsresult
 nsJSContext::InitClasses(JS::Handle<JSObject*> aGlobalObj)
 {
   AutoJSAPI jsapi;
   jsapi.Init();
   JSContext* cx = jsapi.cx();
-  JSAutoRealm ar(cx, aGlobalObj);
+  JSAutoRealmAllowCCW ar(cx, aGlobalObj);
 
   // Attempt to initialize profiling functions
   ::JS_DefineProfilingFunctions(cx, aGlobalObj);
 
 #ifdef MOZ_JPROF
   // Attempt to initialize JProf functions
   ::JS_DefineFunctions(cx, aGlobalObj, JProfFunctions);
 #endif
--- a/dom/base/nsJSUtils.h
+++ b/dom/base/nsJSUtils.h
@@ -69,17 +69,17 @@ public:
 #ifdef MOZ_GECKO_PROFILER
     // Register stack annotations for the Gecko profiler.
     mozilla::AutoProfilerLabel mAutoProfilerLabel;
 #endif
 
     JSContext* mCx;
 
     // Handles switching to our global's realm.
-    JSAutoRealm mRealm;
+    JSAutoRealmAllowCCW mRealm;
 
     // Set to a valid handle if a return value is expected.
     JS::Rooted<JS::Value> mRetValue;
 
     // Scope chain in which the execution takes place.
     JS::AutoObjectVector mScopeChain;
 
     // returned value forwarded when we have to interupt the execution eagerly
--- a/dom/base/nsNodeUtils.cpp
+++ b/dom/base/nsNodeUtils.cpp
@@ -557,17 +557,17 @@ nsNodeUtils::CloneAndAdopt(nsINode *aNod
       elem->RecompileScriptEventListeners();
     }
 
     if (aReparentScope) {
       AutoJSContext cx;
       JS::Rooted<JSObject*> wrapper(cx);
       if ((wrapper = aNode->GetWrapper())) {
         MOZ_ASSERT(IsDOMObject(wrapper));
-        JSAutoRealm ar(cx, wrapper);
+        JSAutoRealmAllowCCW ar(cx, wrapper);
         ReparentWrapper(cx, wrapper, aError);
         if (aError.Failed()) {
           if (wasRegistered) {
             aNode->OwnerDoc()->UnregisterActivityObserver(aNode->AsElement());
           }
           aNode->mNodeInfo.swap(newNodeInfo);
           if (elem) {
             elem->NodeInfoChanged(newDoc);
--- a/dom/base/nsObjectLoadingContent.cpp
+++ b/dom/base/nsObjectLoadingContent.cpp
@@ -3564,17 +3564,17 @@ nsObjectLoadingContent::SetupProtoChain(
     return;
   }
 
   // We get called on random realms here for some reason
   // (perhaps because WrapObject can happen on a random realm?)
   // so make sure to enter the realm of aObject.
   MOZ_ASSERT(aCx == nsContentUtils::GetCurrentJSContext());
 
-  JSAutoRealm ar(aCx, aObject);
+  JSAutoRealmAllowCCW ar(aCx, aObject);
 
   RefPtr<nsNPAPIPluginInstance> pi;
   nsresult rv = ScriptRequestPluginInstance(aCx, getter_AddRefs(pi));
   if (NS_FAILED(rv)) {
     return;
   }
 
   if (!pi) {
@@ -3697,17 +3697,17 @@ nsObjectLoadingContent::TeardownProtoCha
   // reporting errors to our window's onerror listeners.
   AutoJSAPI jsapi;
   jsapi.Init();
   JSContext* cx = jsapi.cx();
   JS::Rooted<JSObject*> obj(cx, thisContent->GetWrapper());
   MOZ_ASSERT(obj);
 
   JS::Rooted<JSObject*> proto(cx);
-  JSAutoRealm ar(cx, obj);
+  JSAutoRealmAllowCCW ar(cx, obj);
 
   // Loop over the DOM element's JS object prototype chain and remove
   // all JS objects of the class sNPObjectJSWrapperClass
   DebugOnly<bool> removed = false;
   while (obj) {
     if (!::JS_GetPrototype(cx, obj, &proto)) {
       return;
     }
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -1647,17 +1647,17 @@ static bool
 ResolvePrototypeOrConstructor(JSContext* cx, JS::Handle<JSObject*> wrapper,
                               JS::Handle<JSObject*> obj,
                               size_t protoAndIfaceCacheIndex, unsigned attrs,
                               JS::MutableHandle<JS::PropertyDescriptor> desc,
                               bool& cacheOnHolder)
 {
   JS::Rooted<JSObject*> global(cx, JS::GetNonCCWObjectGlobal(obj));
   {
-    JSAutoRealm ar(cx, global);
+    JSAutoRealmAllowCCW ar(cx, global);
     ProtoAndIfaceCache& protoAndIfaceCache = *GetProtoAndIfaceCache(global);
     // This function is called when resolving the "constructor" and "prototype"
     // properties of Xrays for DOM prototypes and constructors respectively.
     // This means the relevant Xray exists, which means its _target_ exists.
     // And that means we managed to successfullly create the prototype or
     // constructor, respectively, and hence must have managed to create the
     // thing it's pointing to as well.  So our entry slot must exist.
     JSObject* protoOrIface =
@@ -2292,17 +2292,17 @@ ReparentWrapper(JSContext* aCx, JS::Hand
   // DOM things are always parented to globals.
   JS::Rooted<JSObject*> oldParent(aCx, JS::GetNonCCWObjectGlobal(aObj));
   MOZ_ASSERT(JS_IsGlobalObject(oldParent));
 
   JS::Rooted<JSObject*> newParent(aCx,
                                   domClass->mGetAssociatedGlobal(aCx, aObj));
   MOZ_ASSERT(JS_IsGlobalObject(newParent));
 
-  JSAutoRealm oldAr(aCx, oldParent);
+  JSAutoRealmAllowCCW oldAr(aCx, oldParent);
 
   JS::Compartment* oldCompartment = js::GetObjectCompartment(oldParent);
   JS::Compartment* newCompartment = js::GetObjectCompartment(newParent);
   if (oldCompartment == newCompartment) {
     MOZ_ASSERT(oldParent == newParent);
     return;
   }
 
@@ -2312,17 +2312,17 @@ ReparentWrapper(JSContext* aCx, JS::Hand
   }
 
   bool isProxy = js::IsProxy(aObj);
   JS::Rooted<JSObject*> expandoObject(aCx);
   if (isProxy) {
     expandoObject = DOMProxyHandler::GetAndClearExpandoObject(aObj);
   }
 
-  JSAutoRealm newAr(aCx, newParent);
+  JSAutoRealmAllowCCW newAr(aCx, newParent);
 
   // First we clone the reflector. We get a copy of its properties and clone its
   // expando chain.
 
   JS::Handle<JSObject*> proto = (domClass->mGetProto)(aCx);
   if (!proto) {
     aError.StealExceptionFromJSContext(aCx);
     return;
@@ -3559,17 +3559,17 @@ GetMaplikeSetlikeBackingObject(JSContext
   // Retrieve the backing object from the reserved slot on the maplike/setlike
   // object. If it doesn't exist yet, create it.
   JS::Rooted<JS::Value> slotValue(aCx);
   slotValue = js::GetReservedSlot(reflector, aSlotIndex);
   if (slotValue.isUndefined()) {
     // Since backing object access can happen in non-originating realms,
     // make sure to create the backing object in reflector realm.
     {
-      JSAutoRealm ar(aCx, reflector);
+      JSAutoRealmAllowCCW ar(aCx, reflector);
       JS::Rooted<JSObject*> newBackingObj(aCx);
       newBackingObj.set(Method(aCx));
       if (NS_WARN_IF(!newBackingObj)) {
         return false;
       }
       js::SetReservedSlot(reflector, aSlotIndex, JS::ObjectValue(*newBackingObj));
     }
     slotValue = js::GetReservedSlot(reflector, aSlotIndex);
@@ -3782,17 +3782,17 @@ HTMLConstructor(JSContext* aCx, unsigned
   // Enter the compartment of our underlying newTarget object, so we end
   // up comparing to the constructor object for our interface from that global.
   // XXXbz This is not what the spec says to do, and it's not super-clear to me
   // at this point why we're doing it.  Why not just compare |newTarget| and
   // |callee| if the intent is just to prevent registration of HTML interface
   // objects as constructors?  Of course it's not clear that the spec check
   // makes sense to start with: https://github.com/whatwg/html/issues/3575
   {
-    JSAutoRealm ar(aCx, newTarget);
+    JSAutoRealmAllowCCW ar(aCx, newTarget);
     JS::Handle<JSObject*> constructor =
       GetPerInterfaceObjectHandle(aCx, aConstructorId, aCreator,
                                   true);
     if (!constructor) {
       return false;
     }
     if (newTarget == constructor) {
       return ThrowErrorMessage(aCx, MSG_ILLEGAL_CONSTRUCTOR);
@@ -3817,17 +3817,17 @@ HTMLConstructor(JSContext* aCx, unsigned
 
   int32_t tag = eHTMLTag_userdefined;
   if (!definition->IsCustomBuiltIn()) {
     // Step 4.
     // If the definition is for an autonomous custom element, the active
     // function should be HTMLElement or XULElement.  We want to get the actual
     // functions to compare to from our global's realm, not the caller
     // realm.
-    JSAutoRealm ar(aCx, global.Get());
+    JSAutoRealmAllowCCW ar(aCx, global.Get());
 
     JS::Rooted<JSObject*> constructor(aCx);
     if (ns == kNameSpaceID_XUL) {
       constructor = XULElement_Binding::GetConstructorObject(aCx);
     } else {
       constructor = HTMLElement_Binding::GetConstructorObject(aCx);
     }
 
@@ -3872,17 +3872,17 @@ HTMLConstructor(JSContext* aCx, unsigned
     }
 
     if (!cb) {
       return ThrowErrorMessage(aCx, MSG_ILLEGAL_CONSTRUCTOR);
     }
 
     // We want to get the constructor from our global's realm, not the
     // caller realm.
-    JSAutoRealm ar(aCx, global.Get());
+    JSAutoRealmAllowCCW ar(aCx, global.Get());
     JS::Rooted<JSObject*> constructor(aCx, cb(aCx));
     if (!constructor) {
       return false;
     }
 
     if (constructor != js::CheckedUnwrap(callee)) {
       return ThrowErrorMessage(aCx, MSG_ILLEGAL_CONSTRUCTOR);
     }
@@ -3899,17 +3899,17 @@ HTMLConstructor(JSContext* aCx, unsigned
     // This fallback behavior is designed to match analogous behavior for the
     // JavaScript built-ins. So we enter the realm of our underlying newTarget
     // object and fall back to the prototype object from that global.
     // XXX The spec says to use GetFunctionRealm(), which is not actually
     // the same thing as what we have here (e.g. in the case of scripted callable proxies
     // whose target is not same-realm with the proxy, or bound functions, etc).
     // https://bugzilla.mozilla.org/show_bug.cgi?id=1317658
     {
-      JSAutoRealm ar(aCx, newTarget);
+      JSAutoRealmAllowCCW ar(aCx, newTarget);
       desiredProto = GetPerInterfaceObjectHandle(aCx, aProtoId, aCreator, true);
       if (!desiredProto) {
           return false;
       }
     }
 
     // desiredProto is in the realm of the underlying newTarget object.
     // Wrap it into the context realm.
@@ -3924,17 +3924,17 @@ HTMLConstructor(JSContext* aCx, unsigned
   RefPtr<Element> element;
   nsTArray<RefPtr<Element>>& constructionStack =
     definition->mConstructionStack;
   if (constructionStack.IsEmpty()) {
     // Step 8.
     // Now we go to construct an element.  We want to do this in global's
     // realm, not caller realm (the normal constructor behavior),
     // just in case those elements create JS things.
-    JSAutoRealm ar(aCx, global.Get());
+    JSAutoRealmAllowCCW ar(aCx, global.Get());
 
     RefPtr<NodeInfo> nodeInfo =
       doc->NodeInfoManager()->GetNodeInfo(definition->mLocalName,
                                           nullptr,
                                           ns,
                                           nsINode::ELEMENT_NODE);
     MOZ_ASSERT(nodeInfo);
 
@@ -3967,32 +3967,32 @@ HTMLConstructor(JSContext* aCx, unsigned
     // Step 11.
     // Do prototype swizzling for upgrading a custom element here, for cases
     // when we have a reflector already.  If we don't have one yet, we will
     // create it with the right proto (by calling DoGetOrCreateDOMReflector with
     // that proto).
     JS::Rooted<JSObject*> reflector(aCx, element->GetWrapper());
     if (reflector) {
       // reflector might be in different realm.
-      JSAutoRealm ar(aCx, reflector);
+      JSAutoRealmAllowCCW ar(aCx, reflector);
       JS::Rooted<JSObject*> givenProto(aCx, desiredProto);
       if (!JS_WrapObject(aCx, &givenProto) ||
           !JS_SetPrototype(aCx, reflector, givenProto)) {
         return false;
       }
     }
 
     // Step 12.
     constructionStack.LastElement() = ALREADY_CONSTRUCTED_MARKER;
   }
 
   // Tail end of step 8 and step 13: returning the element.  We want to do this
   // part in the global's realm, though in practice it won't matter much
   // because Element always knows which realm it should be created in.
-  JSAutoRealm ar(aCx, global.Get());
+  JSAutoRealmAllowCCW ar(aCx, global.Get());
   if (!js::IsObjectInContextCompartment(desiredProto, aCx) &&
       !JS_WrapObject(aCx, &desiredProto)) {
     return false;
   }
 
   return GetOrCreateDOMReflector(aCx, element, args.rval(), desiredProto);
 }
 } // namespace binding_detail
@@ -4004,17 +4004,17 @@ AssertReflectorHasGivenProto(JSContext* 
                              JS::Handle<JSObject*> aGivenProto)
 {
   if (!aGivenProto) {
     // Nothing to assert here
     return;
   }
 
   JS::Rooted<JSObject*> reflector(aCx, aReflector);
-  JSAutoRealm ar(aCx, reflector);
+  JSAutoRealmAllowCCW ar(aCx, reflector);
   JS::Rooted<JSObject*> reflectorProto(aCx);
   bool ok = JS_GetPrototype(aCx, reflector, &reflectorProto);
   MOZ_ASSERT(ok);
   // aGivenProto may not be in the right realm here, so we
   // have to wrap it to compare.
   JS::Rooted<JSObject*> givenProto(aCx, aGivenProto);
   ok = JS_WrapObject(aCx, &givenProto);
   MOZ_ASSERT(ok);
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -1112,17 +1112,17 @@ DoGetOrCreateDOMReflector(JSContext* cx,
   rval.set(JS::ObjectValue(*obj));
 
   if (js::GetObjectCompartment(obj) == js::GetContextCompartment(cx)) {
     return TypeNeedsOuterization<T>::value ? TryToOuterize(rval) : true;
   }
 
   if (wrapBehavior == eDontWrapIntoContextCompartment) {
     if (TypeNeedsOuterization<T>::value) {
-      JSAutoRealm ar(cx, obj);
+      JSAutoRealmAllowCCW ar(cx, obj);
       return TryToOuterize(rval);
     }
 
     return true;
   }
 
   return JS_WrapValue(cx, rval);
 }
@@ -1176,19 +1176,19 @@ WrapNewBindingNonWrapperCachedObject(JSC
                                      JS::MutableHandle<JS::Value> rval,
                                      JS::Handle<JSObject*> givenProto = nullptr)
 {
   static_assert(IsRefcounted<T>::value, "Don't pass owned classes in here.");
   MOZ_ASSERT(value);
   // We try to wrap in the realm of the underlying object of "scope"
   JS::Rooted<JSObject*> obj(cx);
   {
-    // scope for the JSAutoRealm so that we restore the realm
+    // scope for the JSAutoRealmAllowCCW so that we restore the realm
     // before we call JS_WrapValue.
-    Maybe<JSAutoRealm> ar;
+    Maybe<JSAutoRealmAllowCCW> ar;
     // Maybe<Handle> doesn't so much work, and in any case, adding
     // more Maybe (one for a Rooted and one for a Handle) adds more
     // code (and branches!) than just adding a single rooted.
     JS::Rooted<JSObject*> scope(cx, scopeArg);
     JS::Rooted<JSObject*> proto(cx, givenProto);
     if (js::IsWrapper(scope)) {
       scope = js::CheckedUnwrap(scope, /* stopAtWindowProxy = */ false);
       if (!scope)
@@ -1229,19 +1229,19 @@ WrapNewBindingNonWrapperCachedObject(JSC
   // We do a runtime check on value, because otherwise we might in
   // fact end up wrapping a null and invoking methods on it later.
   if (!value) {
     MOZ_CRASH("Don't try to wrap null objects");
   }
   // We try to wrap in the realm of the underlying object of "scope"
   JS::Rooted<JSObject*> obj(cx);
   {
-    // scope for the JSAutoRealm so that we restore the realm
+    // scope for the JSAutoRealmAllowCCW so that we restore the realm
     // before we call JS_WrapValue.
-    Maybe<JSAutoRealm> ar;
+    Maybe<JSAutoRealmAllowCCW> ar;
     // Maybe<Handle> doesn't so much work, and in any case, adding
     // more Maybe (one for a Rooted and one for a Handle) adds more
     // code (and branches!) than just adding a single rooted.
     JS::Rooted<JSObject*> scope(cx, scopeArg);
     JS::Rooted<JSObject*> proto(cx, givenProto);
     if (js::IsWrapper(scope)) {
       scope = js::CheckedUnwrap(scope, /* stopAtWindowProxy = */ false);
       if (!scope)
@@ -2411,17 +2411,17 @@ XrayOwnPropertyKeys(JSContext* cx, JS::H
  *     interface or interface prototype object.
  */
 inline bool
 XrayGetNativeProto(JSContext* cx, JS::Handle<JSObject*> obj,
                    JS::MutableHandle<JSObject*> protop)
 {
   JS::Rooted<JSObject*> global(cx, JS::GetNonCCWObjectGlobal(obj));
   {
-    JSAutoRealm ar(cx, global);
+    JSAutoRealmAllowCCW ar(cx, global);
     const DOMJSClass* domClass = GetDOMClass(obj);
     if (domClass) {
       ProtoHandleGetter protoGetter = domClass->mGetProto;
       if (protoGetter) {
         protop.set(protoGetter(cx));
       } else {
         protop.set(JS::GetRealmObjectPrototype(cx));
       }
@@ -3082,17 +3082,17 @@ CreateGlobal(JSContext* aCx, T* aNative,
 
   aGlobal.set(JS_NewGlobalObject(aCx, aClass, aPrincipal,
                                  JS::DontFireOnNewGlobalHook, aOptions));
   if (!aGlobal) {
     NS_WARNING("Failed to create global");
     return false;
   }
 
-  JSAutoRealm ar(aCx, aGlobal);
+  JSAutoRealmAllowCCW ar(aCx, aGlobal);
 
   {
     js::SetReservedSlot(aGlobal, DOM_OBJECT_SLOT, JS::PrivateValue(aNative));
     NS_ADDREF(aNative);
 
     aCache->SetWrapper(aGlobal);
     RecordReplayRegisterDeferredFinalize<T>(aNative);
 
@@ -3271,17 +3271,17 @@ WrappedJSToDictionary(JSContext* aCx, ns
     return false;
   }
 
   JS::Rooted<JSObject*> obj(aCx, wrappedObj->GetJSObject());
   if (!obj) {
     return false;
   }
 
-  JSAutoRealm ar(aCx, obj);
+  JSAutoRealmAllowCCW ar(aCx, obj);
   JS::Rooted<JS::Value> v(aCx, JS::ObjectValue(*obj));
   return aDictionary.Init(aCx, v);
 }
 
 template<class T>
 inline bool
 WrappedJSToDictionary(nsISupports* aObject, T& aDictionary)
 {
--- a/dom/bindings/CallbackObject.cpp
+++ b/dom/bindings/CallbackObject.cpp
@@ -371,17 +371,17 @@ CallbackObjectHolderBase::ToXPCOMCallbac
   jsapi.Init();
   JSContext* cx = jsapi.cx();
 
   JS::Rooted<JSObject*> callback(cx, aCallback->CallbackOrNull());
   if (!callback) {
     return nullptr;
   }
 
-  JSAutoRealm ar(cx, callback);
+  JSAutoRealmAllowCCW ar(cx, callback);
   RefPtr<nsXPCWrappedJS> wrappedJS;
   nsresult rv =
     nsXPCWrappedJS::GetNewOrUsed(callback, aIID, getter_AddRefs(wrappedJS));
   if (NS_FAILED(rv) || !wrappedJS) {
     return nullptr;
   }
 
   nsCOMPtr<nsISupports> retval;
--- a/dom/bindings/CallbackObject.h
+++ b/dom/bindings/CallbackObject.h
@@ -335,17 +335,17 @@ protected:
     // Members which are used to set the async stack.
     Maybe<JS::Rooted<JSObject*>> mAsyncStack;
     Maybe<JS::AutoSetAsyncStackForNewCalls> mAsyncStackSetter;
 
     // Can't construct a JSAutoRealm without a JSContext either.  Also,
     // Put mAr after mAutoEntryScript so that we exit the realm before we
     // pop the script settings stack. Though in practice we'll often manually
     // order those two things.
-    Maybe<JSAutoRealm> mAr;
+    Maybe<JSAutoRealmAllowCCW> mAr;
 
     // An ErrorResult to possibly re-throw exceptions on and whether
     // we should re-throw them.
     ErrorResult& mErrorResult;
     const ExceptionHandling mExceptionHandling;
     const bool mIsMainThread;
   };
 };
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -7867,17 +7867,17 @@ class CGPerSignatureCall(CGThing):
                 conversionScope = "isXray ? obj : slotStorage"
             else:
                 conversionScope = "slotStorage"
 
             wrapCode = fill(
                 """
                 {
                   JS::Rooted<JSObject*> conversionScope(cx, ${conversionScope});
-                  JSAutoRealm ar(cx, conversionScope);
+                  JSAutoRealmAllowCCW ar(cx, conversionScope);
                   do { // block we break out of when done wrapping
                     $*{wrapCode}
                   } while (false);
                   $*{postConversionSteps}
                 }
                 { // And now store things in the realm of our slotStorage.
                   JSAutoRealm ar(cx, slotStorage);
                   $*{slotStorageSteps}
@@ -15271,17 +15271,17 @@ class CGJSImplClass(CGBindingImplClass):
         return fill(
             """
             JS::Rooted<JSObject*> obj(aCx, ${name}_Binding::Wrap(aCx, this, aGivenProto));
             if (!obj) {
               return nullptr;
             }
 
             // Now define it on our chrome object
-            JSAutoRealm ar(aCx, mImpl->CallbackOrNull());
+            JSAutoRealmAllowCCW ar(aCx, mImpl->CallbackOrNull());
             if (!JS_WrapObject(aCx, &obj)) {
               return nullptr;
             }
             if (!JS_DefineProperty(aCx, mImpl->CallbackOrNull(), "__DOM_IMPL__", obj, 0)) {
               return nullptr;
             }
             return obj;
             """,
--- a/dom/bindings/SimpleGlobalObject.cpp
+++ b/dom/bindings/SimpleGlobalObject.cpp
@@ -129,17 +129,17 @@ SimpleGlobalObject::Create(GlobalType gl
                                   JS::DontFireOnNewGlobalHook, options);
     }
 
     if (!global) {
       jsapi.ClearException();
       return nullptr;
     }
 
-    JSAutoRealm ar(cx, global);
+    JSAutoRealmAllowCCW ar(cx, global);
 
     // It's important to create the nsIGlobalObject for our new global before we
     // start trying to wrap things like the prototype into its compartment,
     // because the wrap operation relies on the global having its
     // nsIGlobalObject already.
     RefPtr<SimpleGlobalObject> globalObject =
       new SimpleGlobalObject(global, globalType);
 
--- a/dom/bindings/StructuredClone.cpp
+++ b/dom/bindings/StructuredClone.cpp
@@ -42,17 +42,17 @@ ReadStructuredCloneImageData(JSContext* 
 bool
 WriteStructuredCloneImageData(JSContext* aCx, JSStructuredCloneWriter* aWriter,
                               ImageData* aImageData)
 {
   uint32_t width = aImageData->Width();
   uint32_t height = aImageData->Height();
   JS::Rooted<JSObject*> dataArray(aCx, aImageData->GetDataObject());
 
-  JSAutoRealm ar(aCx, dataArray);
+  JSAutoRealmAllowCCW ar(aCx, dataArray);
   JS::Rooted<JS::Value> arrayValue(aCx, JS::ObjectValue(*dataArray));
   return JS_WriteUint32Pair(aWriter, SCTAG_DOM_IMAGEDATA, 0) &&
          JS_WriteUint32Pair(aWriter, width, height) &&
          JS_WriteTypedArray(aWriter, arrayValue);
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/bindings/TypedArray.h
+++ b/dom/bindings/TypedArray.h
@@ -167,17 +167,17 @@ public:
     : Base(std::move(aOther))
   {
   }
 
   static inline JSObject*
   Create(JSContext* cx, nsWrapperCache* creator, uint32_t length,
          const T* data = nullptr) {
     JS::Rooted<JSObject*> creatorWrapper(cx);
-    Maybe<JSAutoRealm> ar;
+    Maybe<JSAutoRealmAllowCCW> ar;
     if (creator && (creatorWrapper = creator->GetWrapperPreserveColor())) {
       ar.emplace(cx, creatorWrapper);
     }
 
     return CreateCommon(cx, length, data);
   }
 
   static inline JSObject*
--- a/dom/bindings/WebIDLGlobalNameHash.cpp
+++ b/dom/bindings/WebIDLGlobalNameHash.cpp
@@ -304,17 +304,17 @@ WebIDLGlobalNameHash::DefineIfEnabled(JS
   //   slots are set up. In the Xray case, this means unwrapping and doing
   //   a non-Xray resolve before doing the Xray resolve.
   //
   // This all could use some grand refactoring, but for now we just limp
   // along.
   if (xpc::WrapperFactory::IsXrayWrapper(aObj)) {
     JS::Rooted<JSObject*> constructor(aCx);
     {
-      JSAutoRealm ar(aCx, global);
+      JSAutoRealmAllowCCW ar(aCx, global);
       constructor = FindNamedConstructorForXray(aCx, aId, entry);
     }
     if (NS_WARN_IF(!constructor)) {
       return Throw(aCx, NS_ERROR_FAILURE);
     }
     if (!JS_WrapObject(aCx, &constructor)) {
       return Throw(aCx, NS_ERROR_FAILURE);
     }
--- a/dom/browser-element/BrowserElementParent.cpp
+++ b/dom/browser-element/BrowserElementParent.cpp
@@ -141,17 +141,17 @@ BrowserElementParent::DispatchOpenWindow
   JS::Rooted<JS::Value> val(cx);
 
   nsIGlobalObject* sgo = aPopupFrameElement->OwnerDoc()->GetScopeObject();
   if (!sgo) {
     return BrowserElementParent::OPEN_WINDOW_IGNORED;
   }
 
   JS::Rooted<JSObject*> global(cx, sgo->GetGlobalJSObject());
-  JSAutoRealm ar(cx, global);
+  JSAutoRealmAllowCCW ar(cx, global);
   if (!ToJSValue(cx, detail, &val)) {
     MOZ_CRASH("Failed to convert dictionary to JS::Value due to OOM.");
     return BrowserElementParent::OPEN_WINDOW_IGNORED;
   }
 
   nsEventStatus status = nsEventStatus_eIgnore;
   bool dispatchSucceeded =
     DispatchCustomDOMEvent(aOpenerFrameElement,
--- a/dom/canvas/WebGLContextUtils.h
+++ b/dom/canvas/WebGLContextUtils.h
@@ -62,17 +62,17 @@ WebGLContext::WebGLObjectAsJSValue(JSCon
                                    ErrorResult& rv) const
 {
     if (!object)
         return JS::NullValue();
 
     MOZ_ASSERT(this == object->mContext);
     JS::Rooted<JS::Value> v(cx);
     JS::Rooted<JSObject*> wrapper(cx, GetWrapper());
-    JSAutoRealm ar(cx, wrapper);
+    JSAutoRealmAllowCCW ar(cx, wrapper);
     if (!dom::GetOrCreateDOMReflector(cx, const_cast<WebGLObjectType*>(object), &v)) {
         rv.Throw(NS_ERROR_FAILURE);
         return JS::NullValue();
     }
     return v;
 }
 
 template <typename WebGLObjectType>
--- a/dom/clients/manager/ClientOpenWindowUtils.cpp
+++ b/dom/clients/manager/ClientOpenWindowUtils.cpp
@@ -193,17 +193,17 @@ OpenWindow(const ClientOpenWindowArgs& a
     MOZ_DIAGNOSTIC_ASSERT(xpc);
 
     JS::Rooted<JSObject*> sandbox(cx);
     rv = xpc->CreateSandbox(cx, principal, sandbox.address());
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return NS_ERROR_TYPE_ERR;
     }
 
-    JSAutoRealm ar(cx, sandbox);
+    JSAutoRealmAllowCCW ar(cx, sandbox);
 
     // ContentProcess
     nsCOMPtr<nsIWindowWatcher> wwatch =
       do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
     nsCOMPtr<nsPIWindowWatcher> pwwatch(do_QueryInterface(wwatch));
--- a/dom/console/Console.cpp
+++ b/dom/console/Console.cpp
@@ -639,17 +639,17 @@ private:
     if (NS_WARN_IF(!global)) {
       return;
     }
 
     // The CreateSandbox call returns a proxy to the actual sandbox object. We
     // don't need a proxy here.
     global = js::UncheckedUnwrap(global);
 
-    JSAutoRealm ar(cx, global);
+    JSAutoRealmAllowCCW ar(cx, global);
 
     // We don't need to set a parent object in mCallData bacause there are not
     // DOM objects exposed to worklet.
 
     ProcessCallData(cx, mConsole, mCallData);
   }
 
   virtual void
@@ -757,17 +757,17 @@ protected:
     if (NS_WARN_IF(!global)) {
       return;
     }
 
     // The GetOrCreateSandbox call returns a proxy to the actual sandbox object.
     // We don't need a proxy here.
     global = js::UncheckedUnwrap(global);
 
-    JSAutoRealm ar(cx, global);
+    JSAutoRealmAllowCCW ar(cx, global);
 
     RunConsole(cx, aWorkerPrivate, nullptr, nullptr);
   }
 
   void
   RunBackOnWorkerThreadForCleanup(WorkerPrivate* aWorkerPrivate) override
   {
     MOZ_ASSERT(aWorkerPrivate);
@@ -923,17 +923,17 @@ private:
     if (NS_WARN_IF(!global)) {
       return;
     }
 
     // The CreateSandbox call returns a proxy to the actual sandbox object. We
     // don't need a proxy here.
     global = js::UncheckedUnwrap(global);
 
-    JSAutoRealm ar(cx, global);
+    JSAutoRealmAllowCCW ar(cx, global);
 
     // We don't need to set a parent object in mCallData bacause there are not
     // DOM objects exposed to worklet.
 
     ProcessProfileData(cx, mConsole, mName, mAction);
   }
 
   virtual void
@@ -1922,17 +1922,17 @@ Console::PopulateConsoleNotificationInTh
   }
 
   else if (aData->mMethodName == MethodCount ||
            aData->mMethodName == MethodCountReset) {
     event.mCounter = CreateCounterOrResetCounterValue(aCx, aData->mCountLabel,
                                                       aData->mCountValue);
   }
 
-  JSAutoRealm ar2(aCx, targetScope);
+  JSAutoRealmAllowCCW ar2(aCx, targetScope);
 
   if (NS_WARN_IF(!ToJSValue(aCx, event, aEventValue))) {
     return false;
   }
 
   JS::Rooted<JSObject*> eventObj(aCx, &aEventValue.toObject());
   if (NS_WARN_IF(!JS_DefineProperty(aCx, eventObj, "wrappedJSObject", eventObj,
                                     JSPROP_ENUMERATE))) {
@@ -2721,17 +2721,17 @@ Console::RetrieveConsoleEvents(JSContext
   MOZ_ASSERT(!NS_IsMainThread());
 
   JS::Rooted<JSObject*> targetScope(aCx, JS::CurrentGlobalOrNull(aCx));
 
   for (uint32_t i = 0; i < mCallDataStorage.Length(); ++i) {
     JS::Rooted<JS::Value> value(aCx);
 
     JS::Rooted<JSObject*> sequenceScope(aCx, mCallDataStorage[i]->mGlobal);
-    JSAutoRealm ar(aCx, sequenceScope);
+    JSAutoRealmAllowCCW ar(aCx, sequenceScope);
 
     Sequence<JS::Value> sequence;
     SequenceRooter<JS::Value> arguments(aCx, &sequence);
 
     if (!mCallDataStorage[i]->PopulateArgumentsSequence(sequence)) {
       aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
       return;
     }
--- a/dom/console/ConsoleUtils.cpp
+++ b/dom/console/ConsoleUtils.cpp
@@ -75,17 +75,17 @@ ConsoleUtils::ReportForServiceWorkerScop
   if (NS_WARN_IF(!global)) {
     return;
   }
 
   // The GetOrCreateSandbox call returns a proxy to the actual sandbox object.
   // We don't need a proxy here.
   global = js::UncheckedUnwrap(global);
 
-  JSAutoRealm ar(cx, global);
+  JSAutoRealmAllowCCW ar(cx, global);
 
   RootedDictionary<ConsoleEvent> event(cx);
 
   event.mID.Construct();
   event.mID.Value().SetAsString() = aScope;
 
   event.mInnerID.Construct();
   event.mInnerID.Value().SetAsString() = NS_LITERAL_STRING("ServiceWorker");
--- a/dom/encoding/TextEncoder.cpp
+++ b/dom/encoding/TextEncoder.cpp
@@ -26,17 +26,17 @@ TextEncoder::Encode(JSContext* aCx,
   nsresult rv;
   const Encoding* ignored;
   Tie(rv, ignored) = UTF_8_ENCODING->Encode(aString, utf8);
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return;
   }
 
-  JSAutoRealm ar(aCx, aObj);
+  JSAutoRealmAllowCCW ar(aCx, aObj);
   JSObject* outView = Uint8Array::Create(
     aCx, utf8.Length(), reinterpret_cast<const uint8_t*>(utf8.BeginReading()));
   if (!outView) {
     aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
     return;
   }
 
   aRetval.set(outView);
--- a/dom/events/EventListenerManager.cpp
+++ b/dom/events/EventListenerManager.cpp
@@ -1001,26 +1001,26 @@ EventListenerManager::CompileEventHandle
   // handler. Note that mTarget is different from aElement in the <body> case,
   // where mTarget is a Window.
   //
   // The wrapScope doesn't really matter here, because the target will create
   // its reflector in the proper scope, and then we'll enter that realm.
   JS::Rooted<JSObject*> wrapScope(cx, global->GetGlobalJSObject());
   JS::Rooted<JS::Value> v(cx);
   {
-    JSAutoRealm ar(cx, wrapScope);
+    JSAutoRealmAllowCCW ar(cx, wrapScope);
     nsresult rv = nsContentUtils::WrapNative(cx, mTarget, &v,
                                              /* aAllowWrapping = */ false);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
   }
 
   JS::Rooted<JSObject*> target(cx, &v.toObject());
-  JSAutoRealm ar(cx, target);
+  JSAutoRealmAllowCCW ar(cx, target);
 
   // Now that we've entered the realm we actually care about, create our
   // scope chain.  Note that we start with |element|, not aElement, because
   // mTarget is different from aElement in the <body> case, where mTarget is a
   // Window, and in that case we do not want the scope chain to include the body
   // or the document.
   JS::AutoObjectVector scopeChain(cx);
   if (!nsJSUtils::GetScopeChainForElement(cx, element, scopeChain)) {
--- a/dom/events/EventListenerService.cpp
+++ b/dom/events/EventListenerService.cpp
@@ -147,30 +147,30 @@ EventListenerInfo::GetInSystemEventGroup
   *aInSystemEventGroup = mInSystemEventGroup;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 EventListenerInfo::GetListenerObject(JSContext* aCx,
                                      JS::MutableHandle<JS::Value> aObject)
 {
-  Maybe<JSAutoRealm> ar;
+  Maybe<JSAutoRealmAllowCCW> ar;
   GetJSVal(aCx, ar, aObject);
   return NS_OK;
 }
 
 /******************************************************************************
  * mozilla::EventListenerService
  ******************************************************************************/
 
 NS_IMPL_ISUPPORTS(EventListenerService, nsIEventListenerService)
 
 bool
 EventListenerInfo::GetJSVal(JSContext* aCx,
-                            Maybe<JSAutoRealm>& aAr,
+                            Maybe<JSAutoRealmAllowCCW>& aAr,
                             JS::MutableHandle<JS::Value> aJSVal)
 {
   if (mScriptedListener) {
     aJSVal.setObject(*mScriptedListener);
     aAr.emplace(aCx, mScriptedListener);
     return true;
   }
 
@@ -179,17 +179,17 @@ EventListenerInfo::GetJSVal(JSContext* a
 }
 
 NS_IMETHODIMP
 EventListenerInfo::ToSource(nsAString& aResult)
 {
   aResult.SetIsVoid(true);
 
   AutoSafeJSContext cx;
-  Maybe<JSAutoRealm> ar;
+  Maybe<JSAutoRealmAllowCCW> ar;
   JS::Rooted<JS::Value> v(cx);
   if (GetJSVal(cx, ar, &v)) {
     JSString* str = JS_ValueToSource(cx, v);
     if (str) {
       nsAutoJSString autoStr;
       if (autoStr.init(cx, str)) {
         aResult.Assign(autoStr);
       }
--- a/dom/events/EventListenerService.h
+++ b/dom/events/EventListenerService.h
@@ -56,17 +56,17 @@ public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(EventListenerInfo)
   NS_DECL_NSIEVENTLISTENERINFO
 
 protected:
  virtual ~EventListenerInfo();
 
   bool GetJSVal(JSContext* aCx,
-                Maybe<JSAutoRealm>& aAr,
+                Maybe<JSAutoRealmAllowCCW>& aAr,
                 JS::MutableHandle<JS::Value> aJSVal);
 
   nsString mType;
   JS::Heap<JSObject*> mScriptedListener;  // May be null.
   bool mCapturing;
   bool mAllowsUntrusted;
   bool mInSystemEventGroup;
 };
--- a/dom/html/nsHTMLDocument.cpp
+++ b/dom/html/nsHTMLDocument.cpp
@@ -1515,17 +1515,17 @@ nsHTMLDocument::Open(JSContext* cx,
     // Now make sure we're not flagged as the initial document anymore, now
     // that we've had stuff done to us.  From now on, if anyone tries to
     // document.open() us, they get a new inner window.
     SetIsInitialDocument(false);
 
     nsCOMPtr<nsIScriptGlobalObject> newScope(do_QueryReferent(mScopeObject));
     JS::Rooted<JSObject*> wrapper(cx, GetWrapper());
     if (oldScope && newScope != oldScope && wrapper) {
-      JSAutoRealm ar(cx, wrapper);
+      JSAutoRealmAllowCCW ar(cx, wrapper);
       mozilla::dom::ReparentWrapper(cx, wrapper, aError);
       if (aError.Failed()) {
         return nullptr;
       }
 
       // Also reparent the template contents owner document
       // because its global is set to the same as this document.
       if (mTemplateContentsOwner) {
--- a/dom/indexedDB/IDBObjectStore.cpp
+++ b/dom/indexedDB/IDBObjectStore.cpp
@@ -1658,17 +1658,17 @@ public:
     JSContext* cx = jsapi.cx();
 
     JS::Rooted<JSObject*> global(cx, SandboxHolder::GetSandbox(cx));
     if (NS_WARN_IF(!global)) {
       OperationCompleted(NS_ERROR_FAILURE);
       return NS_OK;
     }
 
-    JSAutoRealm ar(cx, global);
+    JSAutoRealmAllowCCW ar(cx, global);
 
     JS::Rooted<JS::Value> value(cx);
     nsresult rv = DeserializeIndexValue(cx, &value);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       OperationCompleted(rv);
       return NS_OK;
     }
 
@@ -1780,17 +1780,17 @@ public:
     JSContext* cx = jsapi.cx();
 
     JS::Rooted<JSObject*> global(cx, SandboxHolder::GetSandbox(cx));
     if (NS_WARN_IF(!global)) {
       OperationCompleted(NS_ERROR_FAILURE);
       return NS_OK;
     }
 
-    JSAutoRealm ar(cx, global);
+    JSAutoRealmAllowCCW ar(cx, global);
 
     JS::Rooted<JS::Value> value(cx);
     nsresult rv = DeserializeUpgradeValue(cx, &value);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       OperationCompleted(rv);
       return NS_OK;
     }
 
--- a/dom/indexedDB/IDBRequest.cpp
+++ b/dom/indexedDB/IDBRequest.cpp
@@ -311,17 +311,17 @@ IDBRequest::SetResultCallback(ResultCall
 
   // See if our window is still valid.
   if (NS_WARN_IF(NS_FAILED(CheckInnerWindowCorrectness()))) {
     SetError(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     return;
   }
 
   AutoJSAPI autoJS;
-  Maybe<JSAutoRealm> ar;
+  Maybe<JSAutoRealmAllowCCW> ar;
 
   if (GetScriptOwner()) {
     // If we have a script owner we want the SafeJSContext and then to enter the
     // script owner's realm.
     autoJS.Init();
     ar.emplace(autoJS.cx(), GetScriptOwner());
   } else {
     // Otherwise our owner is a window and we use that to initialize.
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -473,17 +473,17 @@ ConsoleListener::Observe(nsIConsoleMessa
       jsapi.Init();
       JSContext* cx = jsapi.cx();
 
       JS::RootedValue stack(cx);
       rv = scriptError->GetStack(&stack);
       NS_ENSURE_SUCCESS(rv, rv);
 
       if (stack.isObject()) {
-        JSAutoRealm ar(cx, &stack.toObject());
+        JSAutoRealmAllowCCW ar(cx, &stack.toObject());
 
         StructuredCloneData data;
         ErrorResult err;
         data.Write(cx, stack, err);
         if (err.Failed()) {
           return err.StealNSResult();
         }
 
--- a/dom/media/webaudio/AudioContext.cpp
+++ b/dom/media/webaudio/AudioContext.cpp
@@ -583,17 +583,17 @@ AudioContext::DecodeAudioData(const Arra
                               const Optional<OwningNonNull<DecodeErrorCallback> >& aFailureCallback,
                               ErrorResult& aRv)
 {
   nsCOMPtr<nsIGlobalObject> parentObject = do_QueryInterface(GetParentObject());
   RefPtr<Promise> promise;
   AutoJSAPI jsapi;
   jsapi.Init();
   JSContext* cx = jsapi.cx();
-  JSAutoRealm ar(cx, aBuffer.Obj());
+  JSAutoRealmAllowCCW ar(cx, aBuffer.Obj());
 
   promise = Promise::Create(parentObject, aRv);
   if (aRv.Failed()) {
     return nullptr;
   }
 
   aBuffer.ComputeLengthAndData();
 
--- a/dom/network/TCPSocket.cpp
+++ b/dom/network/TCPSocket.cpp
@@ -854,17 +854,17 @@ TCPSocket::Send(JSContext* aCx,
   if (mSocketBridgeChild) {
     nsresult rv = mSocketBridgeChild->SendSend(aData, aByteOffset, byteLength, ++mTrackingNumber);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       aRv.Throw(rv);
       return false;
     }
   } else {
     JS::Rooted<JSObject*> obj(aCx, aData.Obj());
-    JSAutoRealm ar(aCx, obj);
+    JSAutoRealmAllowCCW ar(aCx, obj);
     JS::Rooted<JS::Value> value(aCx, JS::ObjectValue(*obj));
 
     stream = do_CreateInstance("@mozilla.org/io/arraybuffer-input-stream;1");
     nsresult rv = stream->SetData(value, aByteOffset, byteLength, aCx);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       aRv.Throw(rv);
       return false;
     }
--- a/dom/plugins/base/nsJSNPRuntime.cpp
+++ b/dom/plugins/base/nsJSNPRuntime.cpp
@@ -733,17 +733,17 @@ nsJSObjWrapper::NP_HasMethod(NPObject *n
     ThrowJSExceptionASCII(cx,
                           "Null npobj in nsJSObjWrapper::NP_HasMethod!");
 
     return false;
   }
 
   nsJSObjWrapper *npjsobj = (nsJSObjWrapper *)npobj;
 
-  JSAutoRealm ar(cx, npjsobj->mJSObj);
+  JSAutoRealmAllowCCW ar(cx, npjsobj->mJSObj);
   MarkCrossZoneNPIdentifier(cx, id);
 
   AutoJSExceptionSuppressor suppressor(aes, npjsobj);
 
   JS::Rooted<JS::Value> v(cx);
   bool ok = GetProperty(cx, npjsobj->mJSObj, id, &v);
 
   return ok && !v.isPrimitive() &&
@@ -773,17 +773,17 @@ doInvoke(NPObject *npobj, NPIdentifier m
   }
 
   // Initialize *result
   VOID_TO_NPVARIANT(*result);
 
   nsJSObjWrapper *npjsobj = (nsJSObjWrapper *)npobj;
 
   JS::Rooted<JSObject*> jsobj(cx, npjsobj->mJSObj);
-  JSAutoRealm ar(cx, jsobj);
+  JSAutoRealmAllowCCW ar(cx, jsobj);
   MarkCrossZoneNPIdentifier(cx, method);
   JS::Rooted<JS::Value> fv(cx);
 
   AutoJSExceptionSuppressor suppressor(aes, npjsobj);
 
   if (method != NPIdentifier_VOID) {
     if (!GetProperty(cx, jsobj, method, &fv) ||
         ::JS_TypeOfValue(cx, fv) != JSTYPE_FUNCTION) {
@@ -866,17 +866,17 @@ nsJSObjWrapper::NP_HasProperty(NPObject 
     return false;
   }
 
   nsJSObjWrapper *npjsobj = (nsJSObjWrapper *)npobj;
   bool found, ok = false;
 
   AutoJSExceptionSuppressor suppressor(aes, npjsobj);
   JS::Rooted<JSObject*> jsobj(cx, npjsobj->mJSObj);
-  JSAutoRealm ar(cx, jsobj);
+  JSAutoRealmAllowCCW ar(cx, jsobj);
   MarkCrossZoneNPIdentifier(cx, npid);
 
   NS_ASSERTION(NPIdentifierIsInt(npid) || NPIdentifierIsString(npid),
                "id must be either string or int!\n");
   JS::Rooted<jsid> id(cx, NPIdentifierToJSId(npid));
   ok = ::JS_HasPropertyById(cx, jsobj, id, &found);
   return ok && found;
 }
@@ -903,17 +903,17 @@ nsJSObjWrapper::NP_GetProperty(NPObject 
                           "Null npobj in nsJSObjWrapper::NP_GetProperty!");
 
     return false;
   }
 
   nsJSObjWrapper *npjsobj = (nsJSObjWrapper *)npobj;
 
   AutoJSExceptionSuppressor suppressor(aes, npjsobj);
-  JSAutoRealm ar(cx, npjsobj->mJSObj);
+  JSAutoRealmAllowCCW ar(cx, npjsobj->mJSObj);
   MarkCrossZoneNPIdentifier(cx, id);
 
   JS::Rooted<JS::Value> v(cx);
   return (GetProperty(cx, npjsobj->mJSObj, id, &v) &&
           JSValToNPVariant(npp, cx, v, result));
 }
 
 // static
@@ -940,17 +940,17 @@ nsJSObjWrapper::NP_SetProperty(NPObject 
     return false;
   }
 
   nsJSObjWrapper *npjsobj = (nsJSObjWrapper *)npobj;
   bool ok = false;
 
   AutoJSExceptionSuppressor suppressor(aes, npjsobj);
   JS::Rooted<JSObject*> jsObj(cx, npjsobj->mJSObj);
-  JSAutoRealm ar(cx, jsObj);
+  JSAutoRealmAllowCCW ar(cx, jsObj);
   MarkCrossZoneNPIdentifier(cx, npid);
 
   JS::Rooted<JS::Value> v(cx, NPVariantToJSVal(npp, cx, value));
 
   NS_ASSERTION(NPIdentifierIsInt(npid) || NPIdentifierIsString(npid),
                "id must be either string or int!\n");
   JS::Rooted<jsid> id(cx, NPIdentifierToJSId(npid));
   ok = ::JS_SetPropertyById(cx, jsObj, id, v);
@@ -978,17 +978,17 @@ nsJSObjWrapper::NP_RemoveProperty(NPObje
     return false;
   }
 
   nsJSObjWrapper *npjsobj = (nsJSObjWrapper *)npobj;
 
   AutoJSExceptionSuppressor suppressor(aes, npjsobj);
   JS::ObjectOpResult result;
   JS::Rooted<JSObject*> obj(cx, npjsobj->mJSObj);
-  JSAutoRealm ar(cx, obj);
+  JSAutoRealmAllowCCW ar(cx, obj);
   MarkCrossZoneNPIdentifier(cx, npid);
 
   NS_ASSERTION(NPIdentifierIsInt(npid) || NPIdentifierIsString(npid),
                "id must be either string or int!\n");
   JS::Rooted<jsid> id(cx, NPIdentifierToJSId(npid));
   if (!::JS_DeletePropertyById(cx, obj, id, result))
     return false;
 
@@ -1032,17 +1032,17 @@ nsJSObjWrapper::NP_Enumerate(NPObject *n
 
     return false;
   }
 
   nsJSObjWrapper *npjsobj = (nsJSObjWrapper *)npobj;
 
   AutoJSExceptionSuppressor suppressor(aes, npjsobj);
   JS::Rooted<JSObject*> jsobj(cx, npjsobj->mJSObj);
-  JSAutoRealm ar(cx, jsobj);
+  JSAutoRealmAllowCCW ar(cx, jsobj);
 
   JS::Rooted<JS::IdVector> ida(cx, JS::IdVector(cx));
   if (!JS_Enumerate(cx, jsobj, &ida)) {
     return false;
   }
 
   *count = ida.length();
   *idarray = (NPIdentifier*) malloc(*count * sizeof(NPIdentifier));
@@ -1174,17 +1174,17 @@ GetNPObjectWrapper(JSContext *cx, JS::Ha
   while (obj && (obj = js::CheckedUnwrap(obj))) {
     if (nsNPObjWrapper::IsWrapper(obj)) {
       if (wrapResult && !JS_WrapObject(cx, &obj)) {
         return nullptr;
       }
       return obj;
     }
 
-    JSAutoRealm ar(cx, obj);
+    JSAutoRealmAllowCCW ar(cx, obj);
     if (!::JS_GetPrototype(cx, obj, &obj)) {
       return nullptr;
     }
   }
   return nullptr;
 }
 
 static NPObject *
--- a/dom/promise/Promise.cpp
+++ b/dom/promise/Promise.cpp
@@ -101,33 +101,33 @@ Promise::Create(nsIGlobalObject* aGlobal
   return p.forget();
 }
 
 // static
 already_AddRefed<Promise>
 Promise::Resolve(nsIGlobalObject* aGlobal, JSContext* aCx,
                  JS::Handle<JS::Value> aValue, ErrorResult& aRv)
 {
-  JSAutoRealm ar(aCx, aGlobal->GetGlobalJSObject());
+  JSAutoRealmAllowCCW ar(aCx, aGlobal->GetGlobalJSObject());
   JS::Rooted<JSObject*> p(aCx,
                           JS::CallOriginalPromiseResolve(aCx, aValue));
   if (!p) {
     aRv.NoteJSContextException(aCx);
     return nullptr;
   }
 
   return CreateFromExisting(aGlobal, p);
 }
 
 // static
 already_AddRefed<Promise>
 Promise::Reject(nsIGlobalObject* aGlobal, JSContext* aCx,
                 JS::Handle<JS::Value> aValue, ErrorResult& aRv)
 {
-  JSAutoRealm ar(aCx, aGlobal->GetGlobalJSObject());
+  JSAutoRealmAllowCCW ar(aCx, aGlobal->GetGlobalJSObject());
   JS::Rooted<JSObject*> p(aCx,
                           JS::CallOriginalPromiseReject(aCx, aValue));
   if (!p) {
     aRv.NoteJSContextException(aCx);
     return nullptr;
   }
 
   return CreateFromExisting(aGlobal, p);
--- a/dom/promise/PromiseDebugging.cpp
+++ b/dom/promise/PromiseDebugging.cpp
@@ -274,17 +274,17 @@ PromiseDebugging::FlushUncaughtRejection
     }
 
     for (size_t j = 0; j < observers.Length(); ++j) {
       RefPtr<UncaughtRejectionObserver> obs =
         static_cast<UncaughtRejectionObserver*>(observers[j].get());
 
       obs->OnLeftUncaught(promise, IgnoreErrors());
     }
-    JSAutoRealm ar(cx, promise);
+    JSAutoRealmAllowCCW ar(cx, promise);
     Promise::ReportRejectedPromise(cx, promise);
   }
   storage->mUncaughtRejections.clear();
 
   // Notify observers of consumed Promise.
 
   for (size_t i = 0; i < consumed.length(); i++) {
     JS::RootedObject promise(cx, consumed[i]);
--- a/dom/script/ScriptSettings.cpp
+++ b/dom/script/ScriptSettings.cpp
@@ -374,17 +374,17 @@ AutoJSAPI::InitInternal(nsIGlobalObject*
     if (exn.isObject()) {
       JS::Rooted<JSObject*> exnObj(aCx, &exn.toObject());
 
       // Make sure we can actually read things from it.  This UncheckedUwrap is
       // safe because we're only getting data for a debug printf.  In
       // particular, we do not expose this data to anyone, which is very
       // important; otherwise it could be a cross-origin information leak.
       exnObj = js::UncheckedUnwrap(exnObj);
-      JSAutoRealm ar(aCx, exnObj);
+      JSAutoRealmAllowCCW ar(aCx, exnObj);
 
       nsAutoJSString stack, filename, name, message;
       int32_t line;
 
       JS::Rooted<JS::Value> tmp(aCx);
       if (!JS_GetProperty(aCx, exnObj, "filename", &tmp)) {
         JS_ClearPendingException(aCx);
       }
@@ -565,17 +565,17 @@ AutoJSAPI::ReportException()
   if (!errorGlobal) {
     if (mIsMainThread) {
       errorGlobal = xpc::PrivilegedJunkScope();
     } else {
       errorGlobal = GetCurrentThreadWorkerGlobal();
     }
   }
   MOZ_ASSERT(JS_IsGlobalObject(errorGlobal));
-  JSAutoRealm ar(cx(), errorGlobal);
+  JSAutoRealmAllowCCW ar(cx(), errorGlobal);
   JS::Rooted<JS::Value> exn(cx());
   js::ErrorReport jsReport(cx());
   if (StealException(&exn) &&
       jsReport.init(cx(), exn, js::ErrorReport::WithSideEffects)) {
     if (mIsMainThread) {
       RefPtr<xpc::ErrorReport> xpcReport = new xpc::ErrorReport();
 
       RefPtr<nsGlobalWindowInner> win = xpc::WindowOrNull(errorGlobal);
@@ -821,14 +821,14 @@ AutoSlowOperation::AutoSlowOperation(MOZ
 }
 
 void
 AutoSlowOperation::CheckForInterrupt()
 {
   // For now we support only main thread!
   if (mIsMainThread) {
     // JS_CheckForInterrupt expects us to be in a realm.
-    JSAutoRealm ar(cx(), xpc::UnprivilegedJunkScope());
+    JSAutoRealmAllowCCW ar(cx(), xpc::UnprivilegedJunkScope());
     JS_CheckForInterrupt(cx());
   }
 }
 
 } // namespace mozilla
--- a/dom/workers/WorkerDebugger.cpp
+++ b/dom/workers/WorkerDebugger.cpp
@@ -98,17 +98,17 @@ private:
 
     if (NS_WARN_IF(!aWorkerPrivate->EnsureClientSource())) {
       return false;
     }
 
     JS::Rooted<JSObject*> global(aCx, globalScope->GetWrapper());
 
     ErrorResult rv;
-    JSAutoRealm ar(aCx, global);
+    JSAutoRealmAllowCCW ar(aCx, global);
     workerinternals::LoadMainScript(aWorkerPrivate, mScriptURL,
                                     DebuggerScript, rv);
     rv.WouldReportJSException();
     // Explicitly ignore NS_BINDING_ABORTED on rv.  Or more precisely, still
     // return false and don't SetWorkerScriptExecutedSuccessfully() in that
     // case, but don't throw anything on aCx.  The idea is to not dispatch error
     // events if our load is canceled with that error code.
     if (rv.ErrorCodeIs(NS_BINDING_ABORTED)) {
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -400,17 +400,17 @@ private:
       return false;
     }
 
     // This is a little dumb, but aCx is in the null realm here because we
     // set it up that way in our Run(), since we had not created the global at
     // that point yet.  So we need to enter the realm of our global,
     // because setting a pending exception on aCx involves wrapping into its
     // current compartment.  Luckily we have a global now.
-    JSAutoRealm ar(aCx, globalScope->GetGlobalJSObject());
+    JSAutoRealmAllowCCW ar(aCx, globalScope->GetGlobalJSObject());
     if (rv.MaybeSetPendingException(aCx)) {
       return false;
     }
 
     aWorkerPrivate->SetWorkerScriptExecutedSuccessfully();
     return true;
   }
 
@@ -3173,17 +3173,17 @@ WorkerPrivate::DoRunLoop(JSContext* aCx)
   AutoJSAPI jsapi;
   jsapi.Init();
   MOZ_ASSERT(jsapi.cx() == aCx);
 
   EnableMemoryReporter();
 
   InitializeGCTimers();
 
-  Maybe<JSAutoRealm> workerCompartment;
+  Maybe<JSAutoRealmAllowCCW> workerCompartment;
 
   for (;;) {
     WorkerStatus currentStatus;
     bool debuggerRunnablesPending = false;
     bool normalRunnablesPending = false;
 
     {
       MutexAutoLock lock(mMutex);
@@ -3286,27 +3286,27 @@ WorkerPrivate::DoRunLoop(JSContext* aCx)
       CycleCollectedJSContext* ccjs = CycleCollectedJSContext::Get();
       ccjs->PerformDebuggerMicroTaskCheckpoint();
 
       if (debuggerRunnablesPending) {
         WorkerDebuggerGlobalScope* globalScope = DebuggerGlobalScope();
         MOZ_ASSERT(globalScope);
 
         // Now *might* be a good time to GC. Let the JS engine make the decision.
-        JSAutoRealm ar(aCx, globalScope->GetGlobalJSObject());
+        JSAutoRealmAllowCCW ar(aCx, globalScope->GetGlobalJSObject());
         JS_MaybeGC(aCx);
       }
     } else if (normalRunnablesPending) {
       // Process a single runnable from the main queue.
       NS_ProcessNextEvent(mThread, false);
 
       normalRunnablesPending = NS_HasPendingEvents(mThread);
       if (normalRunnablesPending && GlobalScope()) {
         // Now *might* be a good time to GC. Let the JS engine make the decision.
-        JSAutoRealm ar(aCx, GlobalScope()->GetGlobalJSObject());
+        JSAutoRealmAllowCCW ar(aCx, GlobalScope()->GetGlobalJSObject());
         JS_MaybeGC(aCx);
       }
     }
 
     if (!debuggerRunnablesPending && !normalRunnablesPending) {
       // Both the debugger event queue and the normal event queue has been
       // exhausted, cancel the periodic GC timer and schedule the idle GC timer.
       SetGCTimerMode(IdleTimer);
@@ -5292,17 +5292,17 @@ WorkerPrivate::GetOrCreateGlobalScope(JS
                                      GetServiceWorkerRegistrationDescriptor());
     } else {
       globalScope = new DedicatedWorkerGlobalScope(this, WorkerName());
     }
 
     JS::Rooted<JSObject*> global(aCx);
     NS_ENSURE_TRUE(globalScope->WrapGlobalObject(aCx, &global), nullptr);
 
-    JSAutoRealm ar(aCx, global);
+    JSAutoRealmAllowCCW ar(aCx, global);
 
     // RegisterBindings() can spin a nested event loop so we have to set mScope
     // before calling it, and we have to make sure to unset mScope if it fails.
     mScope = std::move(globalScope);
 
     if (!RegisterBindings(aCx, global)) {
       mScope = nullptr;
       return nullptr;
@@ -5322,17 +5322,17 @@ WorkerPrivate::CreateDebuggerGlobalScope
   MOZ_ASSERT(!mDebuggerScope);
 
   RefPtr<WorkerDebuggerGlobalScope> globalScope =
     new WorkerDebuggerGlobalScope(this);
 
   JS::Rooted<JSObject*> global(aCx);
   NS_ENSURE_TRUE(globalScope->WrapGlobalObject(aCx, &global), nullptr);
 
-  JSAutoRealm ar(aCx, global);
+  JSAutoRealmAllowCCW ar(aCx, global);
 
   // RegisterDebuggerBindings() can spin a nested event loop so we have to set
   // mDebuggerScope before calling it, and we have to make sure to unset
   // mDebuggerScope if it fails.
   mDebuggerScope = std::move(globalScope);
 
   if (!RegisterDebuggerBindings(aCx, global)) {
     mDebuggerScope = nullptr;
--- a/dom/workers/WorkerRunnable.cpp
+++ b/dom/workers/WorkerRunnable.cpp
@@ -343,17 +343,17 @@ WorkerRunnable::Run()
   // sadly.
   MOZ_ASSERT_IF(!targetIsWorkerThread && !isMainThread,
                 mWorkerPrivate->IsDedicatedWorker() && globalObject);
 
   // If we're on the parent thread we might be in a null realm in the
   // situation described above when globalObject is null.  Make sure to enter
   // the realm of the worker's reflector if there is one.  There might
   // not be one if we're just starting to compile the script for this worker.
-  Maybe<JSAutoRealm> ar;
+  Maybe<JSAutoRealmAllowCCW> ar;
   if (!targetIsWorkerThread &&
       mWorkerPrivate->IsDedicatedWorker() &&
       mWorkerPrivate->ParentEventTargetRef()->GetWrapper()) {
     JSObject* wrapper = mWorkerPrivate->ParentEventTargetRef()->GetWrapper();
 
     // If we're on the parent thread and have a reflector and a globalObject,
     // then the realms of cx, globalObject, and the worker's reflector
     // should all match.
--- a/dom/workers/WorkerScope.cpp
+++ b/dom/workers/WorkerScope.cpp
@@ -1014,17 +1014,17 @@ WorkerDebuggerGlobalScope::CreateSandbox
 void
 WorkerDebuggerGlobalScope::LoadSubScript(JSContext* aCx,
                                          const nsAString& aURL,
                                          const Optional<JS::Handle<JSObject*>>& aSandbox,
                                          ErrorResult& aRv)
 {
   mWorkerPrivate->AssertIsOnWorkerThread();
 
-  Maybe<JSAutoRealm> ar;
+  Maybe<JSAutoRealmAllowCCW> ar;
   if (aSandbox.WasPassed()) {
     JS::Rooted<JSObject*> sandbox(aCx, js::CheckedUnwrap(aSandbox.Value()));
     if (!IsWorkerDebuggerSandbox(sandbox)) {
       aRv.Throw(NS_ERROR_INVALID_ARG);
       return;
     }
 
     ar.emplace(aCx, sandbox);
--- a/dom/worklet/Worklet.cpp
+++ b/dom/worklet/Worklet.cpp
@@ -397,17 +397,17 @@ ExecutionRunnable::RunOnWorkletThread()
   NS_ConvertUTF16toUTF8 url(mHandler->URL());
 
   JS::CompileOptions compileOptions(cx);
   compileOptions.setIntroductionType("Worklet");
   compileOptions.setFileAndLine(url.get(), 0);
   compileOptions.setIsRunOnce(true);
   compileOptions.setNoScriptRval(true);
 
-  JSAutoRealm ar(cx, globalObj);
+  JSAutoRealmAllowCCW ar(cx, globalObj);
 
   JS::SourceBufferHolder buffer(mScriptBuffer.release(), mScriptLength,
                                 JS::SourceBufferHolder::GiveOwnership);
   JS::Rooted<JS::Value> unused(cx);
   if (!JS::Evaluate(cx, compileOptions, buffer, &unused)) {
     ErrorResult error;
     error.MightThrowJSException();
     error.StealExceptionFromJSContext(cx);
@@ -535,17 +535,17 @@ Worklet::CreateGlobalScope(JSContext* aC
     case ePaintWorklet:
       scope = new PaintWorkletGlobalScope();
       break;
   }
 
   JS::Rooted<JSObject*> global(aCx);
   NS_ENSURE_TRUE(scope->WrapGlobalObject(aCx, &global), nullptr);
 
-  JSAutoRealm ar(aCx, global);
+  JSAutoRealmAllowCCW ar(aCx, global);
 
   // Init Web IDL bindings
   if (!RegisterWorkletBindings(aCx, global)) {
     return nullptr;
   }
 
   JS_FireOnNewGlobalObject(aCx, global);
 
--- a/dom/xbl/nsBindingManager.cpp
+++ b/dom/xbl/nsBindingManager.cpp
@@ -635,17 +635,17 @@ nsBindingManager::GetBindingImplementati
       // binding, some of which may not be exposed on the prototype of
       // untrusted content. We don't need to consider add-on scopes here
       // because they're chrome-only and no Xrays are involved.
       //
       // If there's no separate XBL scope, or if the reflector itself lives in
       // the XBL scope, we'll end up with the global of the reflector.
       JS::Rooted<JSObject*> xblScope(cx, xpc::GetXBLScopeOrGlobal(cx, jsobj));
       NS_ENSURE_TRUE(xblScope, NS_ERROR_UNEXPECTED);
-      JSAutoRealm ar(cx, xblScope);
+      JSAutoRealmAllowCCW ar(cx, xblScope);
       bool ok = JS_WrapObject(cx, &jsobj);
       NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY);
       MOZ_ASSERT_IF(js::IsWrapper(jsobj), xpc::IsXrayWrapper(jsobj));
 
       nsresult rv = xpConnect->WrapJSAggregatedToNative(aContent, cx,
                                                         jsobj, aIID, aResult);
       if (NS_FAILED(rv))
         return rv;
--- a/dom/xbl/nsXBLBinding.cpp
+++ b/dom/xbl/nsXBLBinding.cpp
@@ -734,17 +734,17 @@ nsXBLBinding::ChangeDocument(nsIDocument
       if (scriptObject) {
         // XXX Stay in sync! What if a layered binding has an
         // <interface>?!
         // 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.
-        JSAutoRealm ar(cx, scriptObject);
+        JSAutoRealmAllowCCW ar(cx, scriptObject);
 
         JS::Rooted<JSObject*> base(cx, scriptObject);
         JS::Rooted<JSObject*> proto(cx);
         for ( ; true; base = proto) { // Will break out on null proto
           if (!JS_GetPrototype(cx, base, &proto)) {
             return;
           }
           if (!proto) {
@@ -893,17 +893,17 @@ GetOrCreateMapEntryForPrototype(JSContex
   // the proto accordingly. We hang the map off of the content XBL scope for
   // content, and the Window for chrome (whether add-ons are involved or not).
   JS::Rooted<JSObject*> scope(cx,
     xpc::GetXBLScopeOrGlobal(cx, JS::CurrentGlobalOrNull(cx)));
   NS_ENSURE_TRUE(scope, nullptr);
   MOZ_ASSERT(JS_IsGlobalObject(scope));
 
   JS::Rooted<JSObject*> wrappedProto(cx, proto);
-  JSAutoRealm ar(cx, scope);
+  JSAutoRealmAllowCCW ar(cx, scope);
   if (!JS_WrapObject(cx, &wrappedProto)) {
     return nullptr;
   }
 
   // Grab the appropriate WeakMap.
   JS::Rooted<JSObject*> map(cx, GetOrCreateClassObjectMap(cx, scope, name));
   if (!map) {
     return nullptr;
@@ -966,17 +966,17 @@ nsXBLBinding::DoInitJSClass(JSContext *c
 
   // We never store class objects in add-on scopes.
   JS::Rooted<JSObject*> xblScope(cx, xpc::GetXBLScopeOrGlobal(cx, global));
   NS_ENSURE_TRUE(xblScope, NS_ERROR_UNEXPECTED);
 
   JS::Rooted<JSObject*> parent_proto(cx);
   {
     JS::RootedObject wrapped(cx, obj);
-    JSAutoRealm ar(cx, xblScope);
+    JSAutoRealmAllowCCW ar(cx, xblScope);
     if (!JS_WrapObject(cx, &wrapped)) {
       return NS_ERROR_FAILURE;
     }
     if (!JS_GetPrototype(cx, wrapped, &parent_proto)) {
       return NS_ERROR_FAILURE;
     }
   }
   if (!JS_WrapObject(cx, &parent_proto)) {
@@ -985,24 +985,24 @@ nsXBLBinding::DoInitJSClass(JSContext *c
 
   // Get the map entry for the parent prototype. In the one-off case that the
   // parent prototype is null, we somewhat hackily just use the WeakMap itself
   // as a property holder.
   JS::Rooted<JSObject*> holder(cx);
   if (parent_proto) {
     holder = GetOrCreateMapEntryForPrototype(cx, parent_proto);
   } else {
-    JSAutoRealm innerAR(cx, xblScope);
+    JSAutoRealmAllowCCW innerAR(cx, xblScope);
     holder = GetOrCreateClassObjectMap(cx, xblScope, "__ContentClassObjectMap__");
   }
   if (NS_WARN_IF(!holder)) {
     return NS_ERROR_FAILURE;
   }
   js::AssertSameCompartment(holder, xblScope);
-  JSAutoRealm ar(cx, holder);
+  JSAutoRealmAllowCCW ar(cx, holder);
 
   // Look up the class on the property holder. The only properties on the
   // holder should be class objects. If we don't find the class object, we need
   // to create and define it.
   JS::Rooted<JSObject*> proto(cx);
   JS::Rooted<JS::PropertyDescriptor> desc(cx);
   if (!JS_GetOwnUCPropertyDescriptor(cx, holder, aClassName.get(), &desc)) {
     return NS_ERROR_OUT_OF_MEMORY;
@@ -1012,17 +1012,17 @@ nsXBLBinding::DoInitJSClass(JSContext *c
     proto = &desc.value().toObject();
     DebugOnly<nsXBLPrototypeBinding*> cachedBinding =
       GetProtoBindingFromClassObject(js::UncheckedUnwrap(proto));
     MOZ_ASSERT(cachedBinding == aProtoBinding);
   } else {
 
     // We need to create the prototype. First, enter the realm where it's
     // going to live, and create it.
-    JSAutoRealm ar2(cx, global);
+    JSAutoRealmAllowCCW ar2(cx, global);
     proto = JS_NewObjectWithGivenProto(cx, &gPrototypeJSClass, parent_proto);
     if (!proto) {
       return NS_ERROR_OUT_OF_MEMORY;
     }
 
     // Keep this proto binding alive while we're alive.  Do this first so that
     // we can guarantee that in XBLFinalize this will be non-null.
     // Note that we can't just store aProtoBinding in the private and
@@ -1032,28 +1032,28 @@ nsXBLBinding::DoInitJSClass(JSContext *c
     nsXBLDocumentInfo* docInfo = aProtoBinding->XBLDocumentInfo();
     ::JS_SetPrivate(proto, docInfo);
     NS_ADDREF(docInfo);
     RecordReplayRegisterDeferredFinalize(docInfo);
     JS_SetReservedSlot(proto, 0, JS::PrivateValue(aProtoBinding));
 
     // Next, enter the realm of the property holder, wrap the proto, and
     // stick it on.
-    JSAutoRealm ar3(cx, holder);
+    JSAutoRealmAllowCCW ar3(cx, holder);
     if (!JS_WrapObject(cx, &proto) ||
         !JS_DefineUCProperty(cx, holder, aClassName.get(), -1, proto,
                              JSPROP_READONLY | JSPROP_PERMANENT))
     {
       return NS_ERROR_OUT_OF_MEMORY;
     }
   }
 
   // Whew. We have the proto. Wrap it back into the realm of |obj|,
   // splice it in, and return it.
-  JSAutoRealm ar4(cx, obj);
+  JSAutoRealmAllowCCW ar4(cx, obj);
   if (!JS_WrapObject(cx, &proto) || !JS_SetPrototype(cx, obj, proto)) {
     return NS_ERROR_FAILURE;
   }
   aClassObject.set(proto);
   return NS_OK;
 }
 
 bool
@@ -1122,17 +1122,17 @@ nsXBLBinding::LookupMember(JSContext* aC
     JS::GetNonCCWObjectGlobal(mBoundElement->GetWrapper()));
   MOZ_RELEASE_ASSERT(!xpc::IsInContentXBLScope(boundScope));
   JS::Rooted<JSObject*> xblScope(aCx, xpc::GetXBLScope(aCx, boundScope));
   NS_ENSURE_TRUE(xblScope, false);
   MOZ_ASSERT(boundScope != xblScope);
 
   // Enter the xbl scope and invoke the internal version.
   {
-    JSAutoRealm ar(aCx, xblScope);
+    JSAutoRealmAllowCCW ar(aCx, xblScope);
     JS::Rooted<jsid> id(aCx, aId);
     if (!LookupMemberInternal(aCx, name, id, aDesc, xblScope)) {
       return false;
     }
   }
 
   // Wrap into the caller's scope.
   return JS_WrapPropertyDescriptor(aCx, aDesc);
--- a/dom/xbl/nsXBLProtoImpl.cpp
+++ b/dom/xbl/nsXBLProtoImpl.cpp
@@ -80,17 +80,17 @@ nsXBLProtoImpl::InstallImplementation(ns
 
   // First, start by entering the realm of the XBL scope. This may or may
   // not be the same realm as globalObject.
   JS::Rooted<JSObject*> globalObject(cx,
     JS::GetNonCCWObjectGlobal(targetClassObject));
   JS::Rooted<JSObject*> scopeObject(cx, xpc::GetXBLScopeOrGlobal(cx, globalObject));
   NS_ENSURE_TRUE(scopeObject, NS_ERROR_OUT_OF_MEMORY);
   MOZ_ASSERT(JS_IsGlobalObject(scopeObject));
-  JSAutoRealm ar(cx, scopeObject);
+  JSAutoRealmAllowCCW ar(cx, scopeObject);
 
   // Determine the appropriate property holder.
   //
   // Note: If |targetIsNew| is false, we'll early-return above. However, that only
   // tells us if the content-side object is new, which may be the case even if
   // we've already set up the binding on the XBL side. For example, if we apply
   // a binding #foo to a <span> when we've already applied it to a <div>, we'll
   // end up with a different content prototype, but we'll already have a property
@@ -157,17 +157,17 @@ nsXBLProtoImpl::InstallImplementation(ns
 
         ok = JS_CopyPropertyFrom(cx, id, targetClassObject, propertyHolder);
         NS_ENSURE_TRUE(ok, NS_ERROR_UNEXPECTED);
       }
     }
   }
 
   // From here on out, work in the scope of the bound element.
-  JSAutoRealm ar2(cx, targetClassObject);
+  JSAutoRealmAllowCCW ar2(cx, targetClassObject);
 
   // Install all of our field accessors.
   for (nsXBLProtoImplField* curr = mFields;
        curr;
        curr = curr->GetNext())
     curr->InstallAccessors(cx, targetClassObject);
 
   return NS_OK;
@@ -199,28 +199,28 @@ nsXBLProtoImpl::InitTargetObjects(nsXBLP
   }
 
   // Because our prototype implementation has a class, we need to build up a corresponding
   // class for the concrete implementation in the bound document.
   AutoJSContext cx;
   JS::Rooted<JSObject*> global(cx, sgo->GetGlobalJSObject());
   JS::Rooted<JS::Value> v(cx);
 
-  JSAutoRealm ar(cx, global);
+  JSAutoRealmAllowCCW ar(cx, global);
   // Make sure the interface object is created before the prototype object
   // so that XULElement is hidden from content. See bug 909340.
   bool defineOnGlobal = dom::XULElement_Binding::ConstructorEnabled(cx, global);
   dom::XULElement_Binding::GetConstructorObjectHandle(cx, defineOnGlobal);
 
   rv = nsContentUtils::WrapNative(cx, aBoundElement, &v,
                                   /* aAllowWrapping = */ false);
   NS_ENSURE_SUCCESS(rv, rv);
 
   JS::Rooted<JSObject*> value(cx, &v.toObject());
-  JSAutoRealm ar2(cx, value);
+  JSAutoRealmAllowCCW ar2(cx, value);
 
   // We passed aAllowWrapping = false to nsContentUtils::WrapNative so we
   // should not have a wrapper.
   MOZ_ASSERT(!js::IsWrapper(value));
 
   // All of the above code was just obtaining the bound element's script object and its immediate
   // concrete base class.  We need to alter the object so that our concrete class is interposed
   // between the object and its base class.  We become the new base class of the object, and the
--- a/dom/xbl/nsXBLProtoImplField.cpp
+++ b/dom/xbl/nsXBLProtoImplField.cpp
@@ -179,32 +179,32 @@ InstallXBLField(JSContext* cx,
   // different realm 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 realm (see in
   // Field[GS]etter where we attempt a cross-realm call), we must enter
   // the callee's realm to access its reserved slots.
   nsXBLPrototypeBinding* protoBinding;
   nsAutoJSString fieldName;
   {
-    JSAutoRealm ar(cx, callee);
+    JSAutoRealmAllowCCW ar(cx, callee);
 
     JS::Rooted<JSObject*> xblProto(cx);
     xblProto = &js::GetFunctionNativeReserved(callee, XBLPROTO_SLOT).toObject();
 
     JS::Rooted<JS::Value> name(cx, js::GetFunctionNativeReserved(callee, FIELD_SLOT));
     if (!fieldName.init(cx, name.toString())) {
       return false;
     }
 
     MOZ_ALWAYS_TRUE(JS_ValueToId(cx, name, idp));
 
     // If a separate XBL scope is being used, the callee is not same-realm
     // with the xbl prototype, and the object is a cross-compartment wrapper.
     xblProto = js::UncheckedUnwrap(xblProto);
-    JSAutoRealm ar2(cx, xblProto);
+    JSAutoRealmAllowCCW ar2(cx, xblProto);
     JS::Value slotVal = ::JS_GetReservedSlot(xblProto, 0);
     protoBinding = static_cast<nsXBLPrototypeBinding*>(slotVal.toPrivate());
     MOZ_ASSERT(protoBinding);
   }
 
   nsXBLProtoImplField* field = protoBinding->FindField(fieldName);
   MOZ_ASSERT(field);
 
@@ -324,17 +324,17 @@ nsXBLProtoImplField::InstallAccessors(JS
     return NS_ERROR_FAILURE;
   if (found)
     return NS_OK;
 
   // FieldGetter and FieldSetter need to run in the XBL scope so that they can
   // see through any SOWs on their targets.
 
   // First, enter the XBL scope, and compile the functions there.
-  JSAutoRealm ar(aCx, scopeObject);
+  JSAutoRealmAllowCCW ar(aCx, scopeObject);
   JS::Rooted<JS::Value> wrappedClassObj(aCx, JS::ObjectValue(*aTargetClassObject));
   if (!JS_WrapValue(aCx, &wrappedClassObj))
     return NS_ERROR_OUT_OF_MEMORY;
 
   JS::Rooted<JSObject*> get(aCx,
     JS_GetFunctionObject(js::NewFunctionByIdWithReserved(aCx, FieldGetter,
                                                          0, 0, id)));
   if (!get) {
@@ -351,17 +351,17 @@ nsXBLProtoImplField::InstallAccessors(JS
     return NS_ERROR_OUT_OF_MEMORY;
   }
   js::SetFunctionNativeReserved(set, XBLPROTO_SLOT, wrappedClassObj);
   js::SetFunctionNativeReserved(set, FIELD_SLOT,
                                 JS::StringValue(JSID_TO_STRING(id)));
 
   // Now, re-enter the class object's scope, wrap the getters/setters, and define
   // them there.
-  JSAutoRealm ar2(aCx, aTargetClassObject);
+  JSAutoRealmAllowCCW ar2(aCx, aTargetClassObject);
   if (!JS_WrapObject(aCx, &get) || !JS_WrapObject(aCx, &set)) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   if (!::JS_DefinePropertyById(aCx, aTargetClassObject, id, get, set,
                                AccessorAttributes())) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
@@ -450,17 +450,17 @@ nsXBLProtoImplField::InstallField(JS::Ha
     // Report the exception now, before we try using the JSContext for
     // the JS_DefineUCProperty call.  Note that this reports in our current
     // realm, which is the XBL scope.
     aes.ReportException();
   }
 
   // Now, enter the node's realm, wrap the eval result, and define it on
   // the bound node.
-  JSAutoRealm ar2(cx, aBoundNode);
+  JSAutoRealmAllowCCW ar2(cx, aBoundNode);
   nsDependentString name(mName);
   if (!JS_WrapValue(cx, &result) ||
       !::JS_DefineUCProperty(cx, aBoundNode,
                              reinterpret_cast<const char16_t*>(mName),
                              name.Length(), result, mJSAttributes)) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
--- a/dom/xbl/nsXBLProtoImplMethod.cpp
+++ b/dom/xbl/nsXBLProtoImplMethod.cpp
@@ -183,17 +183,17 @@ nsXBLProtoImplMethod::CompileMember(Auto
   NS_ConvertUTF16toUTF8 cname(mName);
   NS_ConvertUTF16toUTF8 functionUri(aClassStr);
   int32_t hash = functionUri.RFindChar('#');
   if (hash != kNotFound) {
     functionUri.Truncate(hash);
   }
 
   JSContext *cx = jsapi.cx();
-  JSAutoRealm ar(cx, aClassObject);
+  JSAutoRealmAllowCCW ar(cx, aClassObject);
   JS::CompileOptions options(cx);
   options.setFileAndLine(functionUri.get(),
                          uncompiledMethod->mBodyText.GetLineNumber());
   JS::Rooted<JSObject*> methodObject(cx);
   JS::AutoObjectVector emptyVector(cx);
   nsresult rv = nsJSUtils::CompileFunction(jsapi, emptyVector, options, cname,
                                            paramCount,
                                            const_cast<const char**>(args),
--- a/dom/xbl/nsXBLProtoImplProperty.cpp
+++ b/dom/xbl/nsXBLProtoImplProperty.cpp
@@ -183,17 +183,17 @@ nsXBLProtoImplProperty::CompileMember(Au
     }
   }
 
   bool deletedGetter = false;
   nsXBLTextWithLineNumber *getterText = mGetter.GetUncompiled();
   if (getterText && getterText->GetText()) {
     nsDependentString getter(getterText->GetText());
     if (!getter.IsEmpty()) {
-      JSAutoRealm ar(cx, aClassObject);
+      JSAutoRealmAllowCCW ar(cx, aClassObject);
       JS::CompileOptions options(cx);
       options.setFileAndLine(functionUri.get(), getterText->GetLineNumber());
       nsCString name = NS_LITERAL_CSTRING("get_") + NS_ConvertUTF16toUTF8(mName);
       JS::Rooted<JSObject*> getterObject(cx);
       JS::AutoObjectVector emptyVector(cx);
       rv = nsJSUtils::CompileFunction(jsapi, emptyVector, options, name, 0,
                                       nullptr, getter, getterObject.address());
 
@@ -228,17 +228,17 @@ nsXBLProtoImplProperty::CompileMember(Au
     return rv;
   }
 
   bool deletedSetter = false;
   nsXBLTextWithLineNumber *setterText = mSetter.GetUncompiled();
   if (setterText && setterText->GetText()) {
     nsDependentString setter(setterText->GetText());
     if (!setter.IsEmpty()) {
-      JSAutoRealm ar(cx, aClassObject);
+      JSAutoRealmAllowCCW ar(cx, aClassObject);
       JS::CompileOptions options(cx);
       options.setFileAndLine(functionUri.get(), setterText->GetLineNumber());
       nsCString name = NS_LITERAL_CSTRING("set_") + NS_ConvertUTF16toUTF8(mName);
       JS::Rooted<JSObject*> setterObject(cx);
       JS::AutoObjectVector emptyVector(cx);
       rv = nsJSUtils::CompileFunction(jsapi, emptyVector, options, name, 1,
                                       gPropertyArgs, setter,
                                       setterObject.address());
--- a/dom/xbl/nsXBLPrototypeHandler.cpp
+++ b/dom/xbl/nsXBLPrototypeHandler.cpp
@@ -354,17 +354,17 @@ nsXBLPrototypeHandler::ExecuteHandler(Ev
   NS_ENSURE_TRUE(scopeObject, NS_ERROR_OUT_OF_MEMORY);
 
   // Bind it to the bound element. Note that if we're using a separate XBL scope,
   // we'll actually be binding the event handler to a cross-compartment wrapper
   // to the bound element's reflector.
 
   // First, enter our XBL scope. This is where the generic handler should have
   // been compiled, above.
-  JSAutoRealm ar(cx, scopeObject);
+  JSAutoRealmAllowCCW ar(cx, scopeObject);
   JS::Rooted<JSObject*> genericHandler(cx, handler.get());
   bool ok = JS_WrapObject(cx, &genericHandler);
   NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY);
   MOZ_ASSERT(!js::IsCrossCompartmentWrapper(genericHandler));
 
   // Build a scope chain in the XBL scope.
   RefPtr<Element> targetElement = do_QueryObject(scriptTarget);
   JS::AutoObjectVector scopeChain(cx);
@@ -425,32 +425,32 @@ nsXBLPrototypeHandler::EnsureEventHandle
   NS_ENSURE_SUCCESS(rv, rv);
 
   uint32_t argCount;
   const char **argNames;
   nsContentUtils::GetEventArgNames(kNameSpaceID_XBL, aName, false, &argCount,
                                    &argNames);
 
   // Compile the event handler in the xbl scope.
-  JSAutoRealm ar(cx, scopeObject);
+  JSAutoRealmAllowCCW ar(cx, scopeObject);
   JS::CompileOptions options(cx);
   options.setFileAndLine(bindingURI.get(), mLineNumber);
 
   JS::Rooted<JSObject*> handlerFun(cx);
   JS::AutoObjectVector emptyVector(cx);
   rv = nsJSUtils::CompileFunction(jsapi, emptyVector, options,
                                   nsAtomCString(aName), argCount,
                                   argNames, handlerText,
                                   handlerFun.address());
   NS_ENSURE_SUCCESS(rv, rv);
   NS_ENSURE_TRUE(handlerFun, NS_ERROR_FAILURE);
 
   // Wrap the handler into the content scope, since we're about to stash it
   // on the DOM window and such.
-  JSAutoRealm ar2(cx, globalObject);
+  JSAutoRealmAllowCCW ar2(cx, globalObject);
   bool ok = JS_WrapObject(cx, &handlerFun);
   NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY);
   aHandler.set(handlerFun);
   NS_ENSURE_TRUE(aHandler, NS_ERROR_FAILURE);
 
   if (pWindow) {
     pWindow->CacheXBLPrototypeHandler(this, aHandler);
   }
--- a/dom/xul/XULDocument.cpp
+++ b/dom/xul/XULDocument.cpp
@@ -2386,17 +2386,17 @@ XULDocument::ExecuteScript(nsXULPrototyp
 
     JS::Rooted<JSScript*> scriptObject(cx, aScript->GetScriptObject());
     NS_ENSURE_TRUE(scriptObject, NS_ERROR_UNEXPECTED);
 
     JS::Rooted<JSObject*> global(cx, JS::CurrentGlobalOrNull(cx));
     NS_ENSURE_TRUE(xpc::Scriptability::Get(global).Allowed(), NS_OK);
 
     JS::ExposeObjectToActiveJS(global);
-    JSAutoRealm ar(cx, global);
+    JSAutoRealmAllowCCW ar(cx, global);
 
     // The script is in the compilation scope. Clone it into the target scope
     // and execute it. On failure, ~AutoScriptEntry will handle exceptions, so
     // there is no need to manually check the return value.
     JS::RootedValue rval(cx);
     JS::CloneAndExecuteScript(cx, scriptObject, &rval);
 
     return NS_OK;
--- a/extensions/pref/autoconfig/src/nsJSConfigTriggers.cpp
+++ b/extensions/pref/autoconfig/src/nsJSConfigTriggers.cpp
@@ -70,17 +70,17 @@ nsresult CentralizedAdminPrefManagerInit
     principal = NullPrincipal::CreateWithoutOriginAttributes();
     rv = xpc->CreateSandbox(cx, principal, sandbox.address());
     NS_ENSURE_SUCCESS(rv, rv);
 
     autoconfigSb.init(cx, js::UncheckedUnwrap(sandbox));
 
 
     // Define gSandbox on system sandbox.
-    JSAutoRealm ac(cx, autoconfigSystemSb);
+    JSAutoRealmAllowCCW ac(cx, autoconfigSystemSb);
 
     JS::Rooted<JS::Value> value(cx, JS::ObjectValue(*sandbox));
 
     if (!JS_WrapValue(cx, &value) ||
         !JS_DefineProperty(cx, autoconfigSystemSb, "gSandbox", value, JSPROP_ENUMERATE)) {
       return NS_ERROR_FAILURE;
     }
 
@@ -165,17 +165,17 @@ nsresult EvaluateAdminConfigScript(JS::H
             NS_LITERAL_STRING("Your AutoConfig file is ASCII. Please convert it to UTF-8."),
             nsIScriptError::warningFlag,
             NS_LITERAL_CSTRING("autoconfig"),
             nullptr);
         /* If the length is 0, the conversion failed. Fallback to ASCII */
         convertedScript = NS_ConvertASCIItoUTF16(script);
     }
     {
-        JSAutoRealm ac(cx, autoconfigSystemSb);
+        JSAutoRealmAllowCCW ac(cx, autoconfigSystemSb);
         JS::Rooted<JS::Value> value(cx, JS::BooleanValue(isUTF8));
         if (!JS_DefineProperty(cx, autoconfigSystemSb, "gIsUTF8", value, JSPROP_ENUMERATE)) {
             return NS_ERROR_UNEXPECTED;
         }
     }
     rv = xpc->EvalInSandboxObject(convertedScript, filename, cx,
                                   sandbox, &v);
     NS_ENSURE_SUCCESS(rv, rv);
--- a/ipc/testshell/XPCShellEnvironment.cpp
+++ b/ipc/testshell/XPCShellEnvironment.cpp
@@ -382,17 +382,17 @@ XPCShellEnvironment::~XPCShellEnvironmen
         AutoJSAPI jsapi;
         if (!jsapi.Init(GetGlobalObject())) {
             return;
         }
         JSContext* cx = jsapi.cx();
         Rooted<JSObject*> global(cx, GetGlobalObject());
 
         {
-            JSAutoRealm ar(cx, global);
+            JSAutoRealmAllowCCW ar(cx, global);
             JS_SetAllNonReservedSlotsToUndefined(cx, global);
         }
         mGlobalHolder.reset();
 
         JS_GC(cx);
     }
 }
 
@@ -443,17 +443,17 @@ XPCShellEnvironment::Init()
         NS_ERROR("InitClassesWithNewWrappedGlobal failed!");
         return false;
     }
 
     if (!globalObj) {
         NS_ERROR("Failed to get global JSObject!");
         return false;
     }
-    JSAutoRealm ar(cx, globalObj);
+    JSAutoRealmAllowCCW ar(cx, globalObj);
 
     backstagePass->SetGlobalObject(globalObj);
 
     JS::Rooted<Value> privateVal(cx, PrivateValue(this));
     if (!JS_DefineProperty(cx, globalObj, "__XPCShellEnvironment",
                            privateVal,
                            JSPROP_READONLY | JSPROP_PERMANENT) ||
         !JS_DefineFunctions(cx, globalObj, gGlobalFunctions) ||
--- a/js/ductwork/debugger/JSDebugger.cpp
+++ b/js/ductwork/debugger/JSDebugger.cpp
@@ -49,17 +49,17 @@ JSDebugger::AddClass(JS::Handle<JS::Valu
   if (!obj) {
     return NS_ERROR_FAILURE;
   }
 
   if (!JS_IsGlobalObject(obj)) {
     return NS_ERROR_INVALID_ARG;
   }
 
-  JSAutoRealm ar(cx, obj);
+  JSAutoRealmAllowCCW ar(cx, obj);
   if (!JS_DefineDebuggerObject(cx, obj)) {
     return NS_ERROR_FAILURE;
   }
 
   if (recordreplay::IsRecordingOrReplaying() || recordreplay::IsMiddleman()) {
     if (!recordreplay::DefineRecordReplayControlObject(cx, obj)) {
       return NS_ERROR_FAILURE;
     }
--- a/js/ipc/JavaScriptLogging.h
+++ b/js/ipc/JavaScriptLogging.h
@@ -101,17 +101,17 @@ class Logging
         const char* side;
         const char* objDesc;
         void* ptr;
 
         if (local == incoming) {
             JS::RootedObject obj(cx);
             obj = shared->objects_.find(id);
             if (obj) {
-                JSAutoRealm ar(cx, obj);
+                JSAutoRealmAllowCCW ar(cx, obj);
                 objDesc = js::ObjectClassName(cx, obj);
             } else {
                 objDesc = "<dead object>";
             }
 
             side = shared->isParent() ? "parent" : "child";
             ptr = js::UncheckedUnwrap(obj, true);
         } else {
--- a/js/ipc/JavaScriptParent.cpp
+++ b/js/ipc/JavaScriptParent.cpp
@@ -80,17 +80,17 @@ JavaScriptParent::allowMessage(JSContext
     bool isSafe = channel->IsInTransaction();
 
     if (isSafe)
         return true;
 
     nsIGlobalObject* global = dom::GetIncumbentGlobal();
     JS::Rooted<JSObject*> jsGlobal(cx, global ? global->GetGlobalJSObject() : nullptr);
     if (jsGlobal) {
-        JSAutoRealm ar(cx, jsGlobal);
+        JSAutoRealmAllowCCW ar(cx, jsGlobal);
 
         if (!xpc::CompartmentPrivate::Get(jsGlobal)->allowCPOWs &&
             ForbidUnsafeBrowserCPOWs())
         {
             Telemetry::Accumulate(Telemetry::BROWSER_SHIM_USAGE_BLOCKED, 1);
             JS_ReportErrorASCII(cx, "unsafe CPOW usage forbidden");
             return false;
         }
--- a/js/ipc/JavaScriptShared.cpp
+++ b/js/ipc/JavaScriptShared.cpp
@@ -531,20 +531,20 @@ JavaScriptShared::findObjectById(JSConte
         JS_ReportErrorASCII(cx, "operation not possible on dead CPOW");
         return nullptr;
     }
 
     // Each process has a dedicated compartment for CPOW targets. All CPOWs
     // from the other process point to objects in this scope. From there, they
     // can access objects in other compartments using cross-compartment
     // wrappers.
-    JSAutoRealm ar(cx, scopeForTargetObjects());
+    JSAutoRealmAllowCCW ar(cx, scopeForTargetObjects());
     if (objId.hasXrayWaiver()) {
         {
-            JSAutoRealm ar2(cx, obj);
+            JSAutoRealmAllowCCW ar2(cx, obj);
             obj = js::ToWindowProxyIfWindow(obj);
             MOZ_ASSERT(obj);
         }
         if (!xpc::WrapperFactory::WaiveXrayAndWrap(cx, &obj))
             return nullptr;
     } else {
         if (!JS_WrapObject(cx, &obj))
             return nullptr;
--- a/js/ipc/WrapperOwner.cpp
+++ b/js/ipc/WrapperOwner.cpp
@@ -1187,17 +1187,17 @@ WrapperOwner::fromRemoteObjectVariant(JS
     }
 
     ObjectId objId = maybeObjId.value();
     RootedObject obj(cx, findCPOWById(objId));
     if (!obj) {
 
         // All CPOWs live in the privileged junk scope.
         RootedObject junkScope(cx, xpc::PrivilegedJunkScope());
-        JSAutoRealm ar(cx, junkScope);
+        JSAutoRealmAllowCCW ar(cx, junkScope);
         RootedValue v(cx, UndefinedValue());
         // We need to setLazyProto for the getPrototype/getPrototypeIfOrdinary
         // hooks.
         ProxyOptions options;
         options.setLazyProto(true);
         obj = NewProxyObject(cx,
                              &CPOWProxyHandler::singleton,
                              v,
--- a/js/rust/build.rs
+++ b/js/rust/build.rs
@@ -165,17 +165,17 @@ const WHITELIST_TYPES: &'static [&'stati
     "JS::Handle",
     "JS::HandleFunction",
     "JS::HandleId",
     "JS::HandleObject",
     "JS::HandleString",
     "JS::HandleValue",
     "JS::HandleValueArray",
     "JS::IsAcceptableThis",
-    "JSAutoRealm",
+    "JSAutoRealmAllowCCW",
     "JSAutoStructuredCloneBuffer",
     "JSClass",
     "JSClassOps",
     "JSContext",
     "JSErrNum",
     "JSErrorCallback",
     "JSErrorFormatString",
     "JSErrorReport",
--- a/js/rust/src/ac.rs
+++ b/js/rust/src/ac.rs
@@ -1,56 +1,56 @@
 use jsapi::root::*;
 #[cfg(feature = "debugmozjs")]
 use std::ptr;
 
 #[derive(Debug)]
-pub struct AutoCompartment(JSAutoRealm);
+pub struct AutoCompartment(JSAutoRealmAllowCCW);
 
 impl AutoCompartment {
     #[cfg(feature = "debugmozjs")]
     pub unsafe fn with_obj(cx: *mut JSContext,
                            target: *mut JSObject)
                            -> AutoCompartment
     {
         let mut notifier = mozilla::detail::GuardObjectNotifier {
             mStatementDone: ptr::null_mut(),
         };
 
         AutoCompartment(
-            JSAutoRealm::new(
+            JSAutoRealmAllowCCW::new(
                 cx,
                 target,
                 &mut notifier as *mut _))
     }
 
     #[cfg(not(feature = "debugmozjs"))]
     pub unsafe fn with_obj(cx: *mut JSContext,
                            target: *mut JSObject)
                            -> AutoCompartment
     {
-        AutoCompartment(JSAutoRealm::new(cx, target))
+        AutoCompartment(JSAutoRealmAllowCCW::new(cx, target))
     }
 
     #[cfg(feature = "debugmozjs")]
     pub unsafe fn with_script(cx: *mut JSContext,
                               target: *mut JSScript)
                               -> AutoCompartment
     {
         let mut notifier = mozilla::detail::GuardObjectNotifier {
             mStatementDone: ptr::null_mut(),
         };
 
         AutoCompartment(
-            JSAutoRealm::new1(
+            JSAutoRealmAllowCCW::new1(
                 cx,
                 target,
                 &mut notifier as *mut _))
     }
 
     #[cfg(not(feature = "debugmozjs"))]
     pub unsafe fn with_script(cx: *mut JSContext,
                               target: *mut JSScript)
                               -> AutoCompartment
     {
-        AutoCompartment(JSAutoRealm::new1(cx, target))
+        AutoCompartment(JSAutoRealmAllowCCW::new1(cx, target))
     }
 }
--- a/js/rust/src/rust.rs
+++ b/js/rust/src/rust.rs
@@ -610,17 +610,17 @@ impl GCMethods for JS::Value {
     unsafe fn post_barrier(v: *mut JS::Value, prev: JS::Value, next: JS::Value) {
         JS::HeapValuePostBarrier(v, &prev, &next);
     }
 }
 
 // ___________________________________________________________________________
 // Implementations for various things in jsapi.rs
 
-impl Drop for JSAutoRealm {
+impl Drop for JSAutoRealmAllowCCW {
     fn drop(&mut self) {
         unsafe { JS::LeaveRealm(self.cx_, self.oldRealm_); }
     }
 }
 
 impl JSJitMethodCallArgs {
     #[inline]
     pub fn get(&self, i: u32) -> JS::HandleValue {
--- a/js/src/builtin/DataViewObject.cpp
+++ b/js/src/builtin/DataViewObject.cpp
@@ -229,17 +229,17 @@ DataViewObject::constructWrapped(JSConte
     if (!proto) {
         proto = GlobalObject::getOrCreateDataViewPrototype(cx, global);
         if (!proto)
             return false;
     }
 
     RootedObject dv(cx);
     {
-        JSAutoRealm ar(cx, unwrapped);
+        JSAutoRealmAllowCCW ar(cx, unwrapped);
 
         Rooted<ArrayBufferObjectMaybeShared*> buffer(cx);
         buffer = &unwrapped->as<ArrayBufferObjectMaybeShared>();
 
         RootedObject wrappedProto(cx, proto);
         if (!cx->compartment()->wrap(cx, &wrappedProto))
             return false;
 
--- a/js/src/builtin/MapObject.cpp
+++ b/js/src/builtin/MapObject.cpp
@@ -1714,32 +1714,32 @@ CallObjFunc(RetT(*ObjFunc)(JSContext*, H
     assertSameCompartment(cx, obj);
 
     // Always unwrap, in case this is an xray or cross-compartment wrapper.
     RootedObject unwrappedObj(cx);
     unwrappedObj = UncheckedUnwrap(obj);
 
     // Enter the realm of the backing object before calling functions on
     // it.
-    JSAutoRealm ar(cx, unwrappedObj);
+    JSAutoRealmAllowCCW ar(cx, unwrappedObj);
     return ObjFunc(cx, unwrappedObj);
 }
 
 // Handles Has/Delete for public jsapi map/set access
 bool
 CallObjFunc(bool(*ObjFunc)(JSContext *cx, HandleObject obj, HandleValue key, bool *rval),
             JSContext *cx, HandleObject obj, HandleValue key, bool *rval)
 {
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, key);
 
     // Always unwrap, in case this is an xray or cross-compartment wrapper.
     RootedObject unwrappedObj(cx);
     unwrappedObj = UncheckedUnwrap(obj);
-    JSAutoRealm ar(cx, unwrappedObj);
+    JSAutoRealmAllowCCW ar(cx, unwrappedObj);
 
     // If we're working with a wrapped map/set, rewrap the key into the
     // compartment of the unwrapped map/set.
     RootedValue wrappedKey(cx, key);
     if (obj != unwrappedObj) {
         if (!JS_WrapValue(cx, &wrappedKey))
             return false;
     }
@@ -1757,17 +1757,17 @@ CallObjFunc(bool(*ObjFunc)(JSContext* cx
     assertSameCompartment(cx, obj);
 
     // Always unwrap, in case this is an xray or cross-compartment wrapper.
     RootedObject unwrappedObj(cx);
     unwrappedObj = UncheckedUnwrap(obj);
     {
         // Retrieve the iterator while in the unwrapped map/set's compartment,
         // otherwise we'll crash on a compartment assert.
-        JSAutoRealm ar(cx, unwrappedObj);
+        JSAutoRealmAllowCCW ar(cx, unwrappedObj);
         if (!ObjFunc(cx, iterType, unwrappedObj, rval))
             return false;
     }
 
     // If the caller is in a different compartment than the map/set, rewrap the
     // iterator object into the caller's compartment.
     if (obj != unwrappedObj) {
         if (!JS_WrapValue(cx, rval))
@@ -1796,17 +1796,17 @@ JS::MapGet(JSContext* cx, HandleObject o
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, key, rval);
 
     // Unwrap the object, and enter its realm. If object isn't wrapped,
     // this is essentially a noop.
     RootedObject unwrappedObj(cx);
     unwrappedObj = UncheckedUnwrap(obj);
     {
-        JSAutoRealm ar(cx, unwrappedObj);
+        JSAutoRealmAllowCCW ar(cx, unwrappedObj);
         RootedValue wrappedKey(cx, key);
 
         // If we passed in a wrapper, wrap our key into its compartment now.
         if (obj != unwrappedObj) {
             if (!JS_WrapValue(cx, &wrappedKey))
                 return false;
         }
         if (!MapObject::get(cx, unwrappedObj, wrappedKey, rval))
@@ -1827,17 +1827,17 @@ JS::MapSet(JSContext *cx, HandleObject o
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, key, val);
 
     // Unwrap the object, and enter its compartment. If object isn't wrapped,
     // this is essentially a noop.
     RootedObject unwrappedObj(cx);
     unwrappedObj = UncheckedUnwrap(obj);
     {
-        JSAutoRealm ar(cx, unwrappedObj);
+        JSAutoRealmAllowCCW ar(cx, unwrappedObj);
 
         // If we passed in a wrapper, wrap both key and value before adding to
         // the map
         RootedValue wrappedKey(cx, key);
         RootedValue wrappedValue(cx, val);
         if (obj != unwrappedObj) {
             if (!JS_WrapValue(cx, &wrappedKey) ||
                 !JS_WrapValue(cx, &wrappedValue)) {
@@ -1908,17 +1908,17 @@ JS::SetAdd(JSContext *cx, HandleObject o
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, key);
 
     // Unwrap the object, and enter its compartment. If object isn't wrapped,
     // this is essentially a noop.
     RootedObject unwrappedObj(cx);
     unwrappedObj = UncheckedUnwrap(obj);
     {
-        JSAutoRealm ar(cx, unwrappedObj);
+        JSAutoRealmAllowCCW ar(cx, unwrappedObj);
 
         // If we passed in a wrapper, wrap key before adding to the set
         RootedValue wrappedKey(cx, key);
         if (obj != unwrappedObj) {
             if (!JS_WrapValue(cx, &wrappedKey))
                 return false;
         }
         return SetObject::add(cx, unwrappedObj, wrappedKey);
--- a/js/src/devtools/rootAnalysis/annotations.js
+++ b/js/src/devtools/rootAnalysis/annotations.js
@@ -196,17 +196,17 @@ var ignoreFunctions = {
     "NS_LogCOMPtrRelease": true,
 
     // FIXME!
     "NS_DebugBreak": true,
 
     // These are a little overzealous -- these destructors *can* GC if they end
     // up wrapping a pending exception. See bug 898815 for the heavyweight fix.
     "void js::AutoRealm::~AutoRealm(int32)" : true,
-    "void JSAutoRealm::~JSAutoRealm(int32)" : true,
+    "void JSAutoRealmAllowCCW::~JSAutoRealmAllowCCW(int32)" : true,
 
     // Similar to heap snapshot mock classes, and GTests below. This posts a
     // synchronous runnable when a GTest fails, and we are pretty sure that the
     // particular runnable it posts can't even GC, but the analysis isn't
     // currently smart enough to determine that. In either case, this is (a)
     // only in GTests, and (b) only when the Gtest has already failed. We have
     // static and dynamic checks for no GC in the non-test code, and in the test
     // code we fall back to only the dynamic checks.
--- a/js/src/fuzz-tests/tests.cpp
+++ b/js/src/fuzz-tests/tests.cpp
@@ -47,17 +47,17 @@ jsfuzz_createGlobal(JSContext* cx, JSPri
 #ifdef ENABLE_STREAMS
     options.creationOptions().setStreamsEnabled(true);
 #endif
     newGlobal = JS_NewGlobalObject(cx, getGlobalClass(), principals, JS::FireOnNewGlobalHook,
                                    options);
     if (!newGlobal)
         return nullptr;
 
-    JSAutoRealm ar(cx, newGlobal);
+    JSAutoRealmAllowCCW ar(cx, newGlobal);
 
     // Populate the global object with the standard globals like Object and
     // Array.
     if (!JS::InitRealmStandardClasses(cx))
         return nullptr;
 
     return newGlobal;
 }
--- a/js/src/gdb/gdb-tests.cpp
+++ b/js/src/gdb/gdb-tests.cpp
@@ -83,17 +83,17 @@ main(int argc, const char** argv)
     JS::SetWarningReporter(cx, reportWarning);
 
     JSAutoRequest areq(cx);
 
     /* Create the global object. */
     JS::RealmOptions options;
     RootedObject global(cx, checkPtr(JS_NewGlobalObject(cx, &global_class,
                         nullptr, JS::FireOnNewGlobalHook, options)));
-    JSAutoRealm ar(cx, global);
+    JSAutoRealmAllowCCW ar(cx, global);
 
     /* Populate the global object with the standard globals,
        like Object and Array. */
     checkBool(JS::InitRealmStandardClasses(cx));
 
     argv++;
     while (*argv) {
         const char* name = *argv++;
--- a/js/src/jsapi-tests/testDebugger.cpp
+++ b/js/src/jsapi-tests/testDebugger.cpp
@@ -14,17 +14,17 @@ BEGIN_TEST(testDebugger_newScriptHook)
 {
     // Test that top-level indirect eval fires the newScript hook.
     CHECK(JS_DefineDebuggerObject(cx, global));
     JS::RealmOptions options;
     JS::RootedObject g(cx, JS_NewGlobalObject(cx, getGlobalClass(), nullptr,
                                               JS::FireOnNewGlobalHook, options));
     CHECK(g);
     {
-        JSAutoRealm ae(cx, g);
+        JSAutoRealm ar(cx, g);
         CHECK(JS::InitRealmStandardClasses(cx));
     }
 
     JS::RootedObject gWrapper(cx, g);
     CHECK(JS_WrapObject(cx, &gWrapper));
     JS::RootedValue v(cx, JS::ObjectValue(*gWrapper));
     CHECK(JS_SetProperty(cx, global, "g", v));
 
@@ -38,27 +38,27 @@ BEGIN_TEST(testDebugger_newScriptHook)
     // what scope object we use to enter the compartment.
     //
     // Scripts are associated with the global where they're compiled, so we
     // deliver them only to debuggers that are watching that particular global.
     //
     return testIndirectEval(g, "Math.abs(0)");
 }
 
-bool testIndirectEval(JS::HandleObject scope, const char* code)
+bool testIndirectEval(JS::HandleObject global, const char* code)
 {
     EXEC("hits = 0;");
 
     {
-        JSAutoRealm ae(cx, scope);
+        JSAutoRealm ar(cx, global);
         JSString* codestr = JS_NewStringCopyZ(cx, code);
         CHECK(codestr);
         JS::RootedValue arg(cx, JS::StringValue(codestr));
         JS::RootedValue v(cx);
-        CHECK(JS_CallFunctionName(cx, scope, "eval", HandleValueArray(arg), &v));
+        CHECK(JS_CallFunctionName(cx, global, "eval", HandleValueArray(arg), &v));
     }
 
     JS::RootedValue hitsv(cx);
     EVAL("hits", &hitsv);
     CHECK(hitsv.isInt32(1));
     return true;
 }
 END_TEST(testDebugger_newScriptHook)
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -681,39 +681,54 @@ JS::EnterRealm(JSContext* cx, JSObject* 
 JS_PUBLIC_API(void)
 JS::LeaveRealm(JSContext* cx, JS::Realm* oldRealm)
 {
     AssertHeapIsIdle();
     CHECK_REQUEST(cx);
     cx->leaveRealm(oldRealm);
 }
 
-JSAutoRealm::JSAutoRealm(JSContext* cx, JSObject* target
-                         MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
+JSAutoRealmAllowCCW::JSAutoRealmAllowCCW(JSContext* cx, JSObject* target
+                                         MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
+  : cx_(cx),
+    oldRealm_(cx->realm())
+{
+    AssertHeapIsIdleOrIterating();
+    MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+    cx_->enterRealmOf(target);
+}
+
+JSAutoRealmAllowCCW::JSAutoRealmAllowCCW(JSContext* cx, JSScript* target
+                                         MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
   : cx_(cx),
     oldRealm_(cx->realm())
 {
     AssertHeapIsIdleOrIterating();
     MOZ_GUARD_OBJECT_NOTIFIER_INIT;
     cx_->enterRealmOf(target);
 }
 
+JSAutoRealmAllowCCW::~JSAutoRealmAllowCCW()
+{
+    cx_->leaveRealm(oldRealm_);
+}
+
+JSAutoRealm::JSAutoRealm(JSContext* cx, JSObject* target
+                         MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
+  : JSAutoRealmAllowCCW(cx, target)
+{
+    MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+    MOZ_DIAGNOSTIC_ASSERT(!js::IsCrossCompartmentWrapper(target));
+}
+
 JSAutoRealm::JSAutoRealm(JSContext* cx, JSScript* target
                          MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
-  : cx_(cx),
-    oldRealm_(cx->realm())
-{
-    AssertHeapIsIdleOrIterating();
+  : JSAutoRealmAllowCCW(cx, target)
+{
     MOZ_GUARD_OBJECT_NOTIFIER_INIT;
-    cx_->enterRealmOf(target);
-}
-
-JSAutoRealm::~JSAutoRealm()
-{
-    cx_->leaveRealm(oldRealm_);
 }
 
 JSAutoNullableRealm::JSAutoNullableRealm(JSContext* cx,
                                          JSObject* targetOrNull
                                          MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
   : cx_(cx),
     oldRealm_(cx->realm())
 {
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -1032,24 +1032,37 @@ JS_RefreshCrossCompartmentWrappers(JSCon
  * enter/leave calls on the context. Furthermore, only the return value of a
  * JS::EnterRealm call may be passed as the 'oldRealm' argument of
  * the corresponding JS::LeaveRealm call.
  *
  * Entering a realm roots the realm and its global object for the lifetime of
  * the JSAutoRealm.
  */
 
-class MOZ_RAII JS_PUBLIC_API(JSAutoRealm)
+// JSAutoRealmAllowCCW is deprecated and will be removed soon, because entering
+// the realm of a CCW doesn't make sense when CCWs are shared by all realms in
+// the compartment. New code should prefer JSAutoRealm below instead (it asserts
+// the object is not a CCW).
+class MOZ_RAII JS_PUBLIC_API(JSAutoRealmAllowCCW)
 {
     JSContext* cx_;
     JS::Realm* oldRealm_;
   public:
+    JSAutoRealmAllowCCW(JSContext* cx, JSObject* target MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
+    JSAutoRealmAllowCCW(JSContext* cx, JSScript* target MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
+    ~JSAutoRealmAllowCCW();
+
+    MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
+};
+
+class MOZ_RAII JS_PUBLIC_API(JSAutoRealm) : public JSAutoRealmAllowCCW
+{
+  public:
     JSAutoRealm(JSContext* cx, JSObject* target MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
     JSAutoRealm(JSContext* cx, JSScript* target MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
-    ~JSAutoRealm();
 
     MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
 };
 
 class MOZ_RAII JS_PUBLIC_API(JSAutoNullableRealm)
 {
     JSContext* cx_;
     JS::Realm* oldRealm_;
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -875,17 +875,17 @@ static JS::UniqueChars
 FormatFrame(JSContext* cx, const FrameIter& iter, JS::UniqueChars&& inBuf, int num,
             bool showArgs, bool showLocals, bool showThisProps)
 {
     MOZ_ASSERT(!cx->isExceptionPending());
     RootedScript script(cx, iter.script());
     jsbytecode* pc = iter.pc();
 
     RootedObject envChain(cx, iter.environmentChain(cx));
-    JSAutoRealm ar(cx, envChain);
+    JSAutoRealmAllowCCW ar(cx, envChain);
 
     const char* filename = script->filename();
     unsigned lineno = PCToLineNumber(script, pc);
     RootedFunction fun(cx, iter.maybeCallee(cx));
     RootedString funname(cx);
     if (fun)
         funname = fun->displayAtom();
 
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -731,17 +731,17 @@ ShellInterruptCallback(JSContext* cx)
     // Do this first to prevent other interrupts that may occur while the
     // user-supplied callback is executing from re-entering the handler.
     sc->serviceInterrupt = false;
 
     bool result;
     if (sc->haveInterruptFunc) {
         bool wasAlreadyThrowing = cx->isExceptionPending();
         JS::AutoSaveExceptionState savedExc(cx);
-        JSAutoRealm ar(cx, &sc->interruptFunc.toObject());
+        JSAutoRealmAllowCCW ar(cx, &sc->interruptFunc.toObject());
         RootedValue rval(cx);
 
         // Report any exceptions thrown by the JS interrupt callback, but do
         // *not* keep it on the cx. The interrupt handler is invoked at points
         // that are not expected to throw catchable exceptions, like at
         // JSOP_RETRVAL.
         //
         // If the interrupted JS code was already throwing, any exceptions
@@ -1959,17 +1959,17 @@ Evaluate(JSContext* cx, unsigned argc, V
             return false;
         if (!loadBuffer.append(loadData, loadLength)) {
             JS_ReportOutOfMemory(cx);
             return false;
         }
     }
 
     {
-        JSAutoRealm ar(cx, global);
+        JSAutoRealmAllowCCW ar(cx, global);
         RootedScript script(cx);
 
         {
             if (saveBytecode) {
                 if (!JS::RealmCreationOptionsRef(cx).cloneSingletons()) {
                     JS_ReportErrorNumberASCII(cx, my_GetErrorMessage, nullptr,
                                               JSSMSG_CACHE_SINGLETON_FAILED);
                     return false;
@@ -2028,17 +2028,17 @@ Evaluate(JSContext* cx, unsigned argc, V
         // delazified should be encoded at the end of the delazification.
         if (saveIncrementalBytecode) {
             if (!StartIncrementalEncoding(cx, script))
                 return false;
         }
 
         if (!JS_ExecuteScript(cx, envChain, script, args.rval())) {
             if (catchTermination && !JS_IsExceptionPending(cx)) {
-                JSAutoRealm ar1(cx, callerGlobal);
+                JSAutoRealmAllowCCW ar1(cx, callerGlobal);
                 JSString* str = JS_NewStringCopyZ(cx, "terminated");
                 if (!str)
                     return false;
                 args.rval().setString(str);
                 return true;
             }
             return false;
         }
@@ -3046,17 +3046,17 @@ DisassembleToSprinter(JSContext* cx, uns
     DisassembleOptionParser p(args.length(), args.array());
     if (!p.parse(cx))
         return false;
 
     if (p.argc == 0) {
         /* Without arguments, disassemble the current script. */
         RootedScript script(cx, GetTopScript(cx));
         if (script) {
-            JSAutoRealm ar(cx, script);
+            JSAutoRealmAllowCCW ar(cx, script);
             if (!Disassemble(cx, script, p.lines, sprinter))
                 return false;
             if (!SrcNotes(cx, script, sprinter))
                 return false;
             if (!TryNotes(cx, script, sprinter))
                 return false;
             if (!ScopeNotes(cx, script, sprinter))
                 return false;
@@ -3309,17 +3309,17 @@ Clone(JSContext* cx, unsigned argc, Valu
 
     if (args.length() == 0) {
         JS_ReportErrorASCII(cx, "Invalid arguments to clone");
         return false;
     }
 
     RootedObject funobj(cx);
     {
-        Maybe<JSAutoRealm> ar;
+        Maybe<JSAutoRealmAllowCCW> ar;
         RootedObject obj(cx, args[0].isPrimitive() ? nullptr : &args[0].toObject());
 
         if (obj && obj->is<CrossCompartmentWrapperObject>()) {
             obj = UncheckedUnwrap(obj);
             ar.emplace(cx, obj);
             args[0].setObject(*obj);
         }
         if (obj && obj->is<JSFunction>()) {
@@ -3462,17 +3462,17 @@ NewSandbox(JSContext* cx, bool lazy)
     JS::RealmOptions options;
     SetStandardRealmOptions(options);
     RootedObject obj(cx, JS_NewGlobalObject(cx, &sandbox_class, nullptr,
                                             JS::DontFireOnNewGlobalHook, options));
     if (!obj)
         return nullptr;
 
     {
-        JSAutoRealm ar(cx, obj);
+        JSAutoRealmAllowCCW ar(cx, obj);
         if (!lazy && !JS::InitRealmStandardClasses(cx))
             return nullptr;
 
         RootedValue value(cx, BooleanValue(lazy));
         if (!JS_DefineProperty(cx, obj, "lazy", value, JSPROP_PERMANENT | JSPROP_READONLY))
             return nullptr;
 
         JS_FireOnNewGlobalObject(cx, obj);
@@ -3528,17 +3528,17 @@ EvalInContext(JSContext* cx, unsigned ar
         return true;
     }
 
     JS::AutoFilename filename;
     unsigned lineno;
 
     DescribeScriptedCaller(cx, &filename, &lineno);
     {
-        Maybe<JSAutoRealm> ar;
+        Maybe<JSAutoRealmAllowCCW> ar;
         unsigned flags;
         JSObject* unwrapped = UncheckedUnwrap(sobj, true, &flags);
         if (flags & Wrapper::CROSS_COMPARTMENT) {
             sobj = unwrapped;
             ar.emplace(cx, sobj);
         }
 
         sobj = ToWindowIfWindowProxy(sobj);
@@ -3639,17 +3639,17 @@ WorkerMain(WorkerInput* input)
 
         JS::RealmOptions compartmentOptions;
         SetStandardRealmOptions(compartmentOptions);
 
         RootedObject global(cx, NewGlobalObject(cx, compartmentOptions, nullptr));
         if (!global)
             break;
 
-        JSAutoRealm ar(cx, global);
+        JSAutoRealmAllowCCW ar(cx, global);
 
         JS::CompileOptions options(cx);
         options.setFileAndLine("<string>", 1)
                .setIsRunOnce(true);
 
         AutoReportException are(cx);
         RootedScript script(cx);
         if (!JS::Compile(cx, options, input->chars.get(), input->length, &script))
@@ -5184,17 +5184,17 @@ DecompileThisScript(JSContext* cx, unsig
 
     NonBuiltinScriptFrameIter iter(cx);
     if (iter.done()) {
         args.rval().setString(cx->runtime()->emptyString);
         return true;
     }
 
     {
-        JSAutoRealm ar(cx, iter.script());
+        JSAutoRealmAllowCCW ar(cx, iter.script());
 
         RootedScript script(cx, iter.script());
         JSString* result = JS_DecompileScript(cx, script);
         if (!result)
             return false;
 
         args.rval().setString(result);
     }
@@ -7682,17 +7682,17 @@ ErrorFilePointer()
 }
 
 static bool
 PrintStackTrace(JSContext* cx, HandleValue exn)
 {
     if (!exn.isObject())
         return false;
 
-    Maybe<JSAutoRealm> ar;
+    Maybe<JSAutoRealmAllowCCW> ar;
     RootedObject exnObj(cx, &exn.toObject());
     if (IsCrossCompartmentWrapper(exnObj)) {
         exnObj = UncheckedUnwrap(exnObj);
         ar.emplace(cx, exnObj);
     }
 
     // Ignore non-ErrorObject thrown by |throw| statement.
     if (!exnObj->is<ErrorObject>())
@@ -8387,17 +8387,17 @@ NewGlobalObject(JSContext* cx, JS::Realm
                 JSPrincipals* principals)
 {
     RootedObject glob(cx, JS_NewGlobalObject(cx, &global_class, principals,
                                              JS::DontFireOnNewGlobalHook, options));
     if (!glob)
         return nullptr;
 
     {
-        JSAutoRealm ar(cx, glob);
+        JSAutoRealmAllowCCW ar(cx, glob);
 
 #ifndef LAZY_STANDARD_CLASSES
         if (!JS::InitRealmStandardClasses(cx))
             return nullptr;
 #endif
 
         bool succeeded;
         if (!JS_SetImmutablePrototype(cx, glob, &succeeded))
@@ -8992,17 +8992,17 @@ Shell(JSContext* cx, OptionParser* op, c
         disableOOMFunctions = true;
 
     JS::RealmOptions options;
     SetStandardRealmOptions(options);
     RootedObject glob(cx, NewGlobalObject(cx, options, nullptr));
     if (!glob)
         return 1;
 
-    JSAutoRealm ar(cx, glob);
+    JSAutoRealmAllowCCW ar(cx, glob);
 
     ShellContext* sc = GetShellContext(cx);
     int result = EXIT_SUCCESS;
     {
         AutoReportException are(cx);
         if (!ProcessArgs(cx, op) && !sc->quitting)
             result = EXITCODE_RUNTIME_ERROR;
     }
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -9476,17 +9476,17 @@ DebuggerObject::promiseIDGetter(JSContex
 
 /* static */ bool
 DebuggerObject::promiseDependentPromisesGetter(JSContext* cx, unsigned argc, Value* vp)
 {
     THIS_DEBUGOBJECT_OWNER_PROMISE(cx, argc, vp, "get promiseDependentPromises", args, dbg, refobj);
 
     Rooted<GCVector<Value>> values(cx, GCVector<Value>(cx));
     {
-        JSAutoRealm ar(cx, promise);
+        JSAutoRealmAllowCCW ar(cx, promise);
         if (!promise->dependentPromises(cx, &values))
             return false;
     }
     for (size_t i = 0; i < values.length(); i++) {
         if (!dbg->wrapDebuggeeValue(cx, values[i]))
             return false;
     }
     RootedArrayObject promises(cx);
--- a/js/src/vm/JSObject.cpp
+++ b/js/src/vm/JSObject.cpp
@@ -1151,29 +1151,29 @@ JS_CopyPropertyFrom(JSContext* cx, Handl
     if (desc.setter() && !desc.hasSetterObject())
         return true;
 
     if (copyBehavior == MakeNonConfigurableIntoConfigurable) {
         // Mask off the JSPROP_PERMANENT bit.
         desc.attributesRef() &= ~JSPROP_PERMANENT;
     }
 
-    JSAutoRealm ar(cx, target);
+    JSAutoRealmAllowCCW ar(cx, target);
     cx->markId(id);
     RootedId wrappedId(cx, id);
     if (!cx->compartment()->wrap(cx, &desc))
         return false;
 
     return DefineProperty(cx, target, wrappedId, desc);
 }
 
 JS_FRIEND_API(bool)
 JS_CopyPropertiesFrom(JSContext* cx, HandleObject target, HandleObject obj)
 {
-    JSAutoRealm ar(cx, obj);
+    JSAutoRealmAllowCCW ar(cx, obj);
 
     AutoIdVector props(cx);
     if (!GetPropertyKeys(cx, obj, JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS, &props))
         return false;
 
     for (size_t i = 0; i < props.length(); ++i) {
         if (!JS_CopyPropertyFrom(cx, props[i], target, obj))
             return false;
--- a/js/src/vm/JSScript.cpp
+++ b/js/src/vm/JSScript.cpp
@@ -4493,17 +4493,17 @@ JSScript::AutoDelazify::holdScript(JS::H
     if (fun) {
         if (fun->realm()->isSelfHostingRealm()) {
             // The self-hosting realm is shared across runtimes, so we can't use
             // JSAutoRealm: it could cause races. Functions in the self-hosting
             // realm will never be lazy, so we can safely assume we don't have
             // to delazify.
             script_ = fun->nonLazyScript();
         } else {
-            JSAutoRealm ar(cx_, fun);
+            JSAutoRealmAllowCCW ar(cx_, fun);
             script_ = JSFunction::getOrCreateScript(cx_, fun);
             if (script_) {
                 oldDoNotRelazify_ = script_->bitFields_.doNotRelazify_;
                 script_->setDoNotRelazify(true);
             }
         }
     }
 }
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -2915,17 +2915,17 @@ JSRuntime::initSelfHosting(JSContext* cx
      * parented to this one, so cannot include state in the nursery.
      */
     JS::AutoDisableGenerationalGC disable(cx);
 
     Rooted<GlobalObject*> shg(cx, JSRuntime::createSelfHostingGlobal(cx));
     if (!shg)
         return false;
 
-    JSAutoRealm ar(cx, shg);
+    JSAutoRealmAllowCCW ar(cx, shg);
 
     /*
      * Set a temporary error reporter printing to stderr because it is too
      * early in the startup process for any other reporter to be registered
      * and we don't want errors in self-hosted code to be silently swallowed.
      *
      * This class also overrides the warning reporter to print warnings to
      * stderr. See selfHosting_WarningReporter.
--- a/js/src/vm/StructuredClone.cpp
+++ b/js/src/vm/StructuredClone.cpp
@@ -1142,17 +1142,17 @@ JSStructuredCloneWriter::parseTransferab
             if (unwrappedObj->as<ArrayBufferObject>().isExternal())
                 return reportDataCloneError(JS_SCERR_TRANSFERABLE);
         }
 
         else  {
             if (!out.buf.callbacks_ || !out.buf.callbacks_->canTransfer)
                 return reportDataCloneError(JS_SCERR_TRANSFERABLE);
 
-            JSAutoRealm ar(cx, unwrappedObj);
+            JSAutoRealmAllowCCW ar(cx, unwrappedObj);
             if (!out.buf.callbacks_->canTransfer(cx, unwrappedObj, out.buf.closure_))
                 return false;
         }
 
         // No duplicates allowed
         auto p = transferableObjects.lookupForAdd(tObj);
         if (p)
             return reportDataCloneError(JS_SCERR_DUP_TRANSFERABLE);
@@ -1248,17 +1248,17 @@ JSStructuredCloneWriter::checkStack()
  * Int16Array views of the same ArrayBuffer, should the data bytes be
  * byte-swapped when writing or not? The Int8Array requires them to not be
  * swapped; the Int16Array requires that they are.
  */
 bool
 JSStructuredCloneWriter::writeTypedArray(HandleObject obj)
 {
     Rooted<TypedArrayObject*> tarr(context(), &CheckedUnwrap(obj)->as<TypedArrayObject>());
-    JSAutoRealm ar(context(), tarr);
+    JSAutoRealmAllowCCW ar(context(), tarr);
 
     if (!TypedArrayObject::ensureHasBuffer(context(), tarr))
         return false;
 
     if (!out.writePair(SCTAG_TYPED_ARRAY_OBJECT, tarr->length()))
         return false;
     uint64_t type = tarr->type();
     if (!out.write(type))
@@ -1271,34 +1271,34 @@ JSStructuredCloneWriter::writeTypedArray
 
     return out.write(tarr->byteOffset());
 }
 
 bool
 JSStructuredCloneWriter::writeDataView(HandleObject obj)
 {
     Rooted<DataViewObject*> view(context(), &CheckedUnwrap(obj)->as<DataViewObject>());
-    JSAutoRealm ar(context(), view);
+    JSAutoRealmAllowCCW ar(context(), view);
 
     if (!out.writePair(SCTAG_DATA_VIEW_OBJECT, view->byteLength()))
         return false;
 
     // Write out the ArrayBuffer tag and contents
     RootedValue val(context(), DataViewObject::bufferValue(view));
     if (!startWrite(val))
         return false;
 
     return out.write(view->byteOffset());
 }
 
 bool
 JSStructuredCloneWriter::writeArrayBuffer(HandleObject obj)
 {
     Rooted<ArrayBufferObject*> buffer(context(), &CheckedUnwrap(obj)->as<ArrayBufferObject>());
-    JSAutoRealm ar(context(), buffer);
+    JSAutoRealmAllowCCW ar(context(), buffer);
 
     return out.writePair(SCTAG_ARRAY_BUFFER_OBJECT, buffer->byteLength()) &&
            out.writeBytes(buffer->dataPointer(), buffer->byteLength());
 }
 
 bool
 JSStructuredCloneWriter::writeSharedArrayBuffer(HandleObject obj)
 {
@@ -1420,17 +1420,17 @@ JSStructuredCloneWriter::traverseObject(
 bool
 JSStructuredCloneWriter::traverseMap(HandleObject obj)
 {
     Rooted<GCVector<Value>> newEntries(context(), GCVector<Value>(context()));
     {
         // If there is no wrapper, the compartment munging is a no-op.
         RootedObject unwrapped(context(), CheckedUnwrap(obj));
         MOZ_ASSERT(unwrapped);
-        JSAutoRealm ar(context(), unwrapped);
+        JSAutoRealmAllowCCW ar(context(), unwrapped);
         if (!MapObject::getKeysAndValuesInterleaved(unwrapped, &newEntries))
             return false;
     }
     if (!context()->compartment()->wrap(context(), &newEntries))
         return false;
 
     for (size_t i = newEntries.length(); i > 0; --i) {
         if (!entries.append(newEntries[i - 1]))
@@ -1450,17 +1450,17 @@ JSStructuredCloneWriter::traverseMap(Han
 bool
 JSStructuredCloneWriter::traverseSet(HandleObject obj)
 {
     Rooted<GCVector<Value>> keys(context(), GCVector<Value>(context()));
     {
         // If there is no wrapper, the compartment munging is a no-op.
         RootedObject unwrapped(context(), CheckedUnwrap(obj));
         MOZ_ASSERT(unwrapped);
-        JSAutoRealm ar(context(), unwrapped);
+        JSAutoRealmAllowCCW ar(context(), unwrapped);
         if (!SetObject::keys(context(), unwrapped, &keys))
             return false;
     }
     if (!context()->compartment()->wrap(context(), &keys))
         return false;
 
     for (size_t i = keys.length(); i > 0; --i) {
         if (!entries.append(keys[i - 1]))
@@ -1761,17 +1761,17 @@ JSStructuredCloneWriter::transferOwnersh
             return false;
 
         if (cls == ESClass::ArrayBuffer) {
             tag = SCTAG_TRANSFER_MAP_ARRAY_BUFFER;
 
             // The current setup of the array buffer inheritance hierarchy doesn't
             // lend itself well to generic manipulation via proxies.
             Rooted<ArrayBufferObject*> arrayBuffer(cx, &CheckedUnwrap(obj)->as<ArrayBufferObject>());
-            JSAutoRealm ar(cx, arrayBuffer);
+            JSAutoRealmAllowCCW ar(cx, arrayBuffer);
 
             if (arrayBuffer->isDetached()) {
                 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
                 return false;
             }
 
             size_t nbytes = arrayBuffer->byteLength();
 
--- a/js/src/vm/TypedArrayObject.cpp
+++ b/js/src/vm/TypedArrayObject.cpp
@@ -888,17 +888,17 @@ class TypedArrayObjectTemplate : public 
             protoRoot =
                 GlobalObject::getOrCreatePrototype(cx, JSCLASS_CACHED_PROTO_KEY(instanceClass()));
             if (!protoRoot)
                 return nullptr;
         }
 
         RootedObject typedArray(cx);
         {
-            JSAutoRealm ar(cx, unwrappedBuffer);
+            JSAutoRealmAllowCCW ar(cx, unwrappedBuffer);
 
             RootedObject wrappedProto(cx, protoRoot);
             if (!cx->compartment()->wrap(cx, &wrappedProto))
                 return nullptr;
 
             typedArray =
                 makeInstance(cx, unwrappedBuffer, CreateSingleton::No, uint32_t(byteOffset),
                              length, wrappedProto);
@@ -1168,17 +1168,17 @@ TypedArrayObjectTemplate<T>::fromTypedAr
         srcArray = &other->as<TypedArrayObject>();
     } else {
         RootedObject unwrapped(cx, CheckedUnwrap(other));
         if (!unwrapped) {
             ReportAccessDenied(cx);
             return nullptr;
         }
 
-        JSAutoRealm ar(cx, unwrapped);
+        JSAutoRealmAllowCCW ar(cx, unwrapped);
 
         srcArray = &unwrapped->as<TypedArrayObject>();
 
         // To keep things simpler, we always reify the array buffer for
         // wrapped typed arrays.
         if (!TypedArrayObject::ensureHasBuffer(cx, srcArray))
             return nullptr;
     }
--- a/js/xpconnect/loader/ChromeScriptLoader.cpp
+++ b/js/xpconnect/loader/ChromeScriptLoader.cpp
@@ -306,17 +306,17 @@ PrecompiledScript::~PrecompiledScript()
 
 void
 PrecompiledScript::ExecuteInGlobal(JSContext* aCx, HandleObject aGlobal,
                                    MutableHandleValue aRval,
                                    ErrorResult& aRv)
 {
     {
         RootedObject targetObj(aCx, JS_FindCompilationScope(aCx, aGlobal));
-        JSAutoRealm ar(aCx, targetObj);
+        JSAutoRealmAllowCCW ar(aCx, targetObj);
 
         Rooted<JSScript*> script(aCx, mScript);
         if (!JS::CloneAndExecuteScript(aCx, script, aRval)) {
             aRv.NoteJSContextException(aCx);
             return;
         }
     }
 
--- a/js/xpconnect/loader/ScriptPreloader.cpp
+++ b/js/xpconnect/loader/ScriptPreloader.cpp
@@ -1047,17 +1047,17 @@ ScriptPreloader::MaybeFinishOffThreadDec
         mParsingScripts.clear();
 
         DecodeNextBatch(OFF_THREAD_CHUNK_SIZE);
     });
 
     AutoSafeJSAPI jsapi;
     JSContext* cx = jsapi.cx();
 
-    JSAutoRealm ar(cx, xpc::CompilationScope());
+    JSAutoRealmAllowCCW ar(cx, xpc::CompilationScope());
     JS::Rooted<JS::ScriptVector> jsScripts(cx, JS::ScriptVector(cx));
 
     // If this fails, we still need to mark the scripts as finished. Any that
     // weren't successfully compiled in this operation (which should never
     // happen under ordinary circumstances) will be re-decoded on the main
     // thread, and raise the appropriate errors when they're executed.
     //
     // The exception from the off-thread decode operation will be reported when
@@ -1117,17 +1117,17 @@ ScriptPreloader::DecodeNextBatch(size_t 
     }
 
     if (size == 0 && mPendingScripts.isEmpty()) {
         return;
     }
 
     AutoSafeJSAPI jsapi;
     JSContext* cx = jsapi.cx();
-    JSAutoRealm ar(cx, scope ? scope : xpc::CompilationScope());
+    JSAutoRealmAllowCCW ar(cx, scope ? scope : xpc::CompilationScope());
 
     JS::CompileOptions options(cx);
     options.setNoScriptRval(true)
            .setSourceIsLazy(true);
 
     if (!JS::CanCompileOffThread(cx, options, size) ||
         !JS::DecodeMultiOffThreadScripts(cx, options, mParsingSources,
                                          OffThreadDecodeCallback,
@@ -1167,17 +1167,17 @@ ScriptPreloader::CachedScript::CachedScr
 
 bool
 ScriptPreloader::CachedScript::XDREncode(JSContext* cx)
 {
     auto cleanup = MakeScopeExit([&] () {
         MaybeDropScript();
     });
 
-    JSAutoRealm ar(cx, mScript);
+    JSAutoRealmAllowCCW ar(cx, mScript);
     JS::RootedScript jsscript(cx, mScript);
 
     mXDRData.construct<JS::TranscodeBuffer>();
 
     JS::TranscodeResult code = JS::EncodeScript(cx, Buffer(), jsscript);
     if (code == JS::TranscodeResult_Ok) {
         mXDRRange.emplace(Buffer().begin(), Buffer().length());
         mSize = Range().length();
--- a/js/xpconnect/loader/mozJSComponentLoader.cpp
+++ b/js/xpconnect/loader/mozJSComponentLoader.cpp
@@ -441,17 +441,17 @@ mozJSComponentLoader::LoadModule(FileLoc
     RootedValue exn(cx);
     rv = ObjectForLocation(info, file, &entry->obj, &entry->thisObjectKey,
                            &entry->location, isCriticalModule, &exn);
     if (NS_FAILED(rv)) {
         // Temporary debugging assertion for bug 1403348:
         if (isCriticalModule && !exn.isUndefined()) {
             AnnotateCrashReport();
 
-            JSAutoRealm ar(cx, xpc::PrivilegedJunkScope());
+            JSAutoRealmAllowCCW ar(cx, xpc::PrivilegedJunkScope());
             JS_WrapValue(cx, &exn);
 
             nsAutoCString file;
             uint32_t line;
             uint32_t column;
             nsAutoString msg;
             nsContentUtils::ExtractErrorValues(cx, exn, file, &line, &column, msg);
 
@@ -463,17 +463,17 @@ mozJSComponentLoader::LoadModule(FileLoc
         return nullptr;
     }
 
     nsCOMPtr<nsIComponentManager> cm;
     rv = NS_GetComponentManager(getter_AddRefs(cm));
     if (NS_FAILED(rv))
         return nullptr;
 
-    JSAutoRealm ar(cx, entry->obj);
+    JSAutoRealmAllowCCW ar(cx, entry->obj);
     RootedObject entryObj(cx, entry->obj);
 
     RootedObject NSGetFactoryHolder(cx, ResolveModuleObjectProperty(cx, entryObj, "NSGetFactory"));
     RootedValue NSGetFactory_val(cx);
     if (!NSGetFactoryHolder ||
         !JS_GetProperty(cx, NSGetFactoryHolder, "NSGetFactory", &NSGetFactory_val) ||
         NSGetFactory_val.isUndefined())
     {
@@ -592,17 +592,17 @@ mozJSComponentLoader::CreateLoaderGlobal
                                               options,
                                               &global);
     NS_ENSURE_SUCCESS_VOID(rv);
 
     NS_ENSURE_TRUE_VOID(global);
 
     backstagePass->SetGlobalObject(global);
 
-    JSAutoRealm ar(aCx, global);
+    JSAutoRealmAllowCCW ar(aCx, global);
     if (!JS_DefineFunctions(aCx, global, gGlobalFun) ||
         !JS_DefineProfilingFunctions(aCx, global)) {
         return;
     }
 
     // Set the location information for the new global, so that tools like
     // about:memory may use that information
     xpc::SetLocationForGlobal(global, aLocation);
@@ -687,17 +687,17 @@ mozJSComponentLoader::PrepareObjectForLo
         CreateLoaderGlobal(aCx, nativePath, &globalObj);
         createdNewGlobal = true;
     }
 
     // |thisObj| is the object we set properties on for a particular .jsm.
     RootedObject thisObj(aCx, globalObj);
     NS_ENSURE_TRUE(thisObj, nullptr);
 
-    JSAutoRealm ar(aCx, thisObj);
+    JSAutoRealmAllowCCW ar(aCx, thisObj);
 
     if (reuseGlobal) {
         thisObj = js::NewJSMEnvironment(aCx);
         NS_ENSURE_TRUE(thisObj, nullptr);
     }
 
     *aRealFile = false;
 
@@ -796,17 +796,17 @@ mozJSComponentLoader::ObjectForLocation(
     nsresult rv = aInfo.EnsureURI();
     NS_ENSURE_SUCCESS(rv, rv);
     bool reuseGlobal = false;
     RootedObject obj(cx, PrepareObjectForLocation(cx, aComponentFile, aInfo.URI(),
                                                   &reuseGlobal, &realFile));
     NS_ENSURE_TRUE(obj, NS_ERROR_FAILURE);
     MOZ_ASSERT(JS_IsGlobalObject(obj) == !reuseGlobal);
 
-    JSAutoRealm ar(cx, obj);
+    JSAutoRealmAllowCCW ar(cx, obj);
 
     RootedScript script(cx);
 
     nsAutoCString nativePath;
     rv = aInfo.URI()->GetSpec(nativePath);
     NS_ENSURE_SUCCESS(rv, rv);
 
     // Before compiling the script, first check to see if we have it in
@@ -960,17 +960,17 @@ mozJSComponentLoader::UnloadModules()
 {
     mInitialized = false;
 
     if (mLoaderGlobal) {
         dom::AutoJSAPI jsapi;
         jsapi.Init();
         JSContext* cx = jsapi.cx();
         RootedObject global(cx, mLoaderGlobal);
-        JSAutoRealm ar(cx, global);
+        JSAutoRealmAllowCCW ar(cx, global);
         MOZ_ASSERT(JS_HasExtensibleLexicalEnvironment(global));
         JS_SetAllNonReservedSlotsToUndefined(cx, JS_ExtensibleLexicalEnvironment(global));
         JS_SetAllNonReservedSlotsToUndefined(cx, global);
         mLoaderGlobal = nullptr;
     }
 
     mInProgressImports.Clear();
     mImports.Clear();
@@ -1013,17 +1013,17 @@ mozJSComponentLoader::ImportInto(const n
             // Not doing so breaks |make package|.
             return ReportOnCallerUTF8(cx, ERROR_SCOPE_OBJ,
                                       PromiseFlatCString(registryLocation).get());
         }
     } else {
         FindTargetObject(cx, &targetObject);
     }
 
-    Maybe<JSAutoRealm> ar;
+    Maybe<JSAutoRealmAllowCCW> ar;
     if (targetObject) {
         ar.emplace(cx, targetObject);
     }
 
     RootedObject global(cx);
     nsresult rv = ImportInto(registryLocation, targetObject, cx, &global);
 
     if (global) {
@@ -1190,17 +1190,17 @@ mozJSComponentLoader::ExtractExports(JSC
     JSCLContextHelper cxhelper(aCx);
 
     // Even though we are calling JS_SetPropertyById on targetObj, we want
     // to ensure that we never run script here, so we use an AutoJSAPI and
     // not an AutoEntryScript.
     dom::AutoJSAPI jsapi;
     jsapi.Init();
     JSContext* cx = jsapi.cx();
-    JSAutoRealm ar(cx, aMod->obj);
+    JSAutoRealmAllowCCW ar(cx, aMod->obj);
 
     RootedValue symbols(cx);
     {
         RootedObject obj(cx, ResolveModuleObjectProperty(cx, aMod->obj,
                                                          "EXPORTED_SYMBOLS"));
         if (!obj || !JS_GetProperty(cx, obj, "EXPORTED_SYMBOLS", &symbols)) {
             return ReportOnCallerUTF8(cxhelper, ERROR_NOT_PRESENT, aInfo);
         }
--- a/js/xpconnect/loader/mozJSComponentLoader.h
+++ b/js/xpconnect/loader/mozJSComponentLoader.h
@@ -155,17 +155,17 @@ class mozJSComponentLoader final : publi
             Clear();
         }
 
         void Clear() {
             getfactoryobj = nullptr;
 
             if (obj) {
                 mozilla::AutoJSContext cx;
-                JSAutoRealm ar(cx, obj);
+                JSAutoRealmAllowCCW ar(cx, obj);
 
                 if (JS_HasExtensibleLexicalEnvironment(obj)) {
                     JS_SetAllNonReservedSlotsToUndefined(cx, JS_ExtensibleLexicalEnvironment(obj));
                 }
                 JS_SetAllNonReservedSlotsToUndefined(cx, obj);
                 obj = nullptr;
                 thisObjectKey = nullptr;
             }
--- a/js/xpconnect/loader/mozJSSubScriptLoader.cpp
+++ b/js/xpconnect/loader/mozJSSubScriptLoader.cpp
@@ -228,17 +228,17 @@ EvalScript(JSContext* cx,
             MOZ_ASSERT(js::IsJSMEnvironment(loadScope));
             if (!js::ExecuteInJSMEnvironment(cx, script, loadScope, envChain)) {
                 return false;
             }
             retval.setUndefined();
         }
     }
 
-    JSAutoRealm rar(cx, targetObj);
+    JSAutoRealmAllowCCW rar(cx, targetObj);
     if (!JS_WrapValue(cx, retval)) {
         return false;
     }
 
     if (script && (startupCache || preloadCache)) {
         nsAutoCString cachePath;
         SubscriptCachePath(cx, uri, targetObj, cachePath);
 
@@ -265,17 +265,17 @@ EvalScript(JSContext* cx,
             // disable and reenable an add-on without uninstalling it, leading
             // to cached scripts being held alive, and tied to nuked Sandbox
             // globals. Given the unusual circumstances required to trigger
             // this, it's not a major concern. But it should be kept in mind.
             ScriptPreloader::GetSingleton().NoteScript(uriStr, cachePath, script);
         }
 
         if (startupCache) {
-            JSAutoRealm ar(cx, script);
+            JSAutoRealmAllowCCW ar(cx, script);
             WriteCachedScript(StartupCache::GetSingleton(), cachePath, cx, script);
         }
     }
 
     return true;
 }
 
 class AsyncScriptLoader : public nsIIncrementalStreamLoaderObserver
@@ -553,17 +553,17 @@ mozJSSubScriptLoader::ReadScript(nsIURI*
         ReportError(cx, LOAD_ERROR_CONTENTTOOBIG, uri);
         return false;
     }
 
     nsCString buf;
     rv = NS_ReadInputStreamToString(instream, buf, len);
     NS_ENSURE_SUCCESS(rv, false);
 
-    Maybe<JSAutoRealm> ar;
+    Maybe<JSAutoRealmAllowCCW> ar;
 
     // Note that when using the ScriptPreloader cache with loadSubScript, there
     // will be a side-effect of keeping the global that the script was compiled
     // for alive. See note above in EvalScript().
     //
     // This will compile the script in XPConnect compilation scope. When the
     // script is evaluated, it will be cloned into the target scope to be
     // executed, avoiding leaks on the first session when we don't have a
@@ -651,17 +651,17 @@ mozJSSubScriptLoader::DoLoadSubScriptWit
 
     // Figure out who's calling us
     JS::AutoFilename filename;
     if (!JS::DescribeScriptedCaller(cx, &filename)) {
         // No scripted frame means we don't know who's calling, bail.
         return NS_ERROR_FAILURE;
     }
 
-    JSAutoRealm ar(cx, targetObj);
+    JSAutoRealmAllowCCW ar(cx, targetObj);
 
     nsCOMPtr<nsIIOService> serv = do_GetService(NS_IOSERVICE_CONTRACTID);
     if (!serv) {
         ReportError(cx, NS_LITERAL_CSTRING(LOAD_ERROR_NOSERVICE));
         return NS_OK;
     }
 
     NS_LossyConvertUTF16toASCII asciiUrl(url);
--- a/js/xpconnect/src/ExportHelpers.cpp
+++ b/js/xpconnect/src/ExportHelpers.cpp
@@ -208,17 +208,17 @@ public:
 bool
 StackScopedClone(JSContext* cx, StackScopedCloneOptions& options,
                  MutableHandleValue val)
 {
     StackScopedCloneData data(cx, &options);
     {
         // For parsing val we have to enter its realm.
         // (unless it's a primitive)
-        Maybe<JSAutoRealm> ar;
+        Maybe<JSAutoRealmAllowCCW> ar;
         if (val.isObject()) {
             ar.emplace(cx, &val.toObject());
         } else if (val.isString() && !JS_WrapValue(cx, val)) {
             return false;
         }
 
         if (!data.Write(cx, val))
             return false;
@@ -295,17 +295,17 @@ FunctionForwarder(JSContext* cx, unsigne
             return false;
         thisVal.setObject(*thisObject);
     }
 
     {
         // We manually implement the contents of CrossCompartmentWrapper::call
         // here, because certain function wrappers (notably content->nsEP) are
         // not callable.
-        JSAutoRealm ar(cx, unwrappedFun);
+        JSAutoRealmAllowCCW ar(cx, unwrappedFun);
         if (!CheckSameOriginArg(cx, options, thisVal) || !JS_WrapValue(cx, &thisVal))
             return false;
 
         for (size_t n = 0;  n < args.length(); ++n) {
             if (!CheckSameOriginArg(cx, options, args[n]) || !JS_WrapValue(cx, args[n]))
                 return false;
         }
 
@@ -395,17 +395,17 @@ ExportFunction(JSContext* cx, HandleValu
     if (js::IsScriptedProxy(targetScope)) {
         JS_ReportErrorASCII(cx, "Defining property on proxy object is not allowed");
         return false;
     }
 
     {
         // We need to operate in the target scope from here on, let's enter
         // its realm.
-        JSAutoRealm ar(cx, targetScope);
+        JSAutoRealmAllowCCW ar(cx, targetScope);
 
         // Unwrapping to see if we have a callable.
         funObj = UncheckedUnwrap(funObj);
         if (!JS::IsCallable(funObj)) {
             JS_ReportErrorASCII(cx, "First argument must be a function");
             return false;
         }
 
@@ -478,17 +478,17 @@ CreateObjectIn(JSContext* cx, HandleValu
 
     if (define && js::IsScriptedProxy(scope)) {
         JS_ReportErrorASCII(cx, "Defining property on proxy object is not allowed");
         return false;
     }
 
     RootedObject obj(cx);
     {
-        JSAutoRealm ar(cx, scope);
+        JSAutoRealmAllowCCW ar(cx, scope);
         JS_MarkCrossZoneId(cx, options.defineAs);
 
         obj = JS_NewPlainObject(cx);
         if (!obj)
             return false;
 
         if (define) {
             if (!JS_DefinePropertyById(cx, scope, options.defineAs, obj,
--- a/js/xpconnect/src/Sandbox.cpp
+++ b/js/xpconnect/src/Sandbox.cpp
@@ -190,17 +190,17 @@ SandboxImport(JSContext* cx, unsigned ar
             return false;
     } else {
         // NB: funobj must only be used to get the JSFunction out.
         RootedObject funobj(cx, &args[0].toObject());
         if (js::IsProxy(funobj)) {
             funobj = XPCWrapper::UnsafeUnwrapSecurityWrapper(funobj);
         }
 
-        JSAutoRealm ar(cx, funobj);
+        JSAutoRealmAllowCCW ar(cx, funobj);
 
         RootedValue funval(cx, ObjectValue(*funobj));
         JSFunction* fun = JS_ValueToFunction(cx, funval);
         if (!fun) {
             XPCThrower::Throw(NS_ERROR_INVALID_ARG, cx);
             return false;
         }
 
@@ -1122,17 +1122,17 @@ xpc::CreateSandboxObject(JSContext* cx, 
     // same-origin Xrays for chrome->chrome access seems a bit superfluous.
     // Arguably we should just flip the default for chrome and still honor the
     // flag, but such a change would break code in subtle ways for minimal
     // benefit. So we just switch it off here.
     priv->wantXrays =
       AccessCheck::isChrome(sandbox) ? false : options.wantXrays;
 
     {
-        JSAutoRealm ar(cx, sandbox);
+        JSAutoRealmAllowCCW ar(cx, sandbox);
 
         // This creates a SandboxPrivate and passes ownership of it to |sandbox|.
         SandboxPrivate::Create(principal, sandbox);
 
         // Ensure |Object.prototype| is instantiated before prototype-
         // splicing below.
         if (!JS::GetRealmObjectPrototype(cx))
             return NS_ERROR_XPC_UNEXPECTED;
@@ -1204,17 +1204,17 @@ xpc::CreateSandboxObject(JSContext* cx, 
         return NS_ERROR_UNEXPECTED;
 
     // Set the location information for the new global, so that tools like
     // about:memory may use that information
     xpc::SetLocationForGlobal(sandbox, options.sandboxName);
 
     xpc::SetSandboxMetadata(cx, sandbox, options.metadata);
 
-    JSAutoRealm ar(cx, sandbox);
+    JSAutoRealmAllowCCW ar(cx, sandbox);
     JS_FireOnNewGlobalObject(cx, sandbox);
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsXPCComponents_utils_Sandbox::Call(nsIXPConnectWrappedNative* wrapper, JSContext* cx,
                                     JSObject* objArg, const CallArgs& args, bool* _retval)
@@ -1839,17 +1839,17 @@ xpc::EvalInSandbox(JSContext* cx, Handle
     RootedValue v(cx, UndefinedValue());
     RootedValue exn(cx, UndefinedValue());
     bool ok = true;
     {
         // We're about to evaluate script, so make an AutoEntryScript.
         // This is clearly Gecko-specific and not in any spec.
         mozilla::dom::AutoEntryScript aes(priv, "XPConnect sandbox evaluation");
         JSContext* sandcx = aes.cx();
-        JSAutoRealm ar(sandcx, sandbox);
+        JSAutoRealmAllowCCW ar(sandcx, sandbox);
 
         JS::CompileOptions options(sandcx);
         options.setFileAndLine(filenameBuf.get(), lineNo);
         MOZ_ASSERT(JS_IsGlobalObject(sandbox));
         ok = JS::Evaluate(sandcx, options,
                           PromiseFlatString(source).get(), source.Length(), &v);
 
         // If the sandbox threw an exception, grab it off the context.
@@ -1892,17 +1892,17 @@ xpc::EvalInSandbox(JSContext* cx, Handle
 nsresult
 xpc::GetSandboxMetadata(JSContext* cx, HandleObject sandbox, MutableHandleValue rval)
 {
     MOZ_ASSERT(NS_IsMainThread());
     MOZ_ASSERT(IsSandbox(sandbox));
 
     RootedValue metadata(cx);
     {
-      JSAutoRealm ar(cx, sandbox);
+      JSAutoRealmAllowCCW ar(cx, sandbox);
       metadata = JS_GetReservedSlot(sandbox, XPCONNECT_SANDBOX_CLASS_METADATA_SLOT);
     }
 
     if (!JS_WrapValue(cx, &metadata))
         return NS_ERROR_UNEXPECTED;
 
     rval.set(metadata);
     return NS_OK;
@@ -1911,16 +1911,16 @@ xpc::GetSandboxMetadata(JSContext* cx, H
 nsresult
 xpc::SetSandboxMetadata(JSContext* cx, HandleObject sandbox, HandleValue metadataArg)
 {
     MOZ_ASSERT(NS_IsMainThread());
     MOZ_ASSERT(IsSandbox(sandbox));
 
     RootedValue metadata(cx);
 
-    JSAutoRealm ar(cx, sandbox);
+    JSAutoRealmAllowCCW ar(cx, sandbox);
     if (!JS_StructuredClone(cx, metadataArg, &metadata, nullptr, nullptr))
         return NS_ERROR_UNEXPECTED;
 
     JS_SetReservedSlot(sandbox, XPCONNECT_SANDBOX_CLASS_METADATA_SLOT, metadata);
 
     return NS_OK;
 }
--- a/js/xpconnect/src/XPCComponents.cpp
+++ b/js/xpconnect/src/XPCComponents.cpp
@@ -2523,17 +2523,17 @@ nsXPCComponents_Utils::MakeObjectPropsNo
     if (!cx)
         return NS_ERROR_FAILURE;
 
     // first argument must be an object
     if (vobj.isPrimitive())
         return NS_ERROR_XPC_BAD_CONVERT_JS;
 
     RootedObject obj(cx, js::UncheckedUnwrap(&vobj.toObject()));
-    JSAutoRealm ar(cx, obj);
+    JSAutoRealmAllowCCW ar(cx, obj);
     Rooted<IdVector> ida(cx, IdVector(cx));
     if (!JS_Enumerate(cx, obj, &ida))
         return NS_ERROR_FAILURE;
 
     RootedId id(cx);
     RootedValue v(cx);
     for (size_t i = 0; i < ida.length(); ++i) {
         id = ida[i];
@@ -2654,17 +2654,17 @@ nsXPCComponents_Utils::ForcePermissiveCO
 }
 
 NS_IMETHODIMP
 nsXPCComponents_Utils::Dispatch(HandleValue runnableArg, HandleValue scope,
                                 JSContext* cx)
 {
     RootedValue runnable(cx, runnableArg);
     // Enter the given realm, if any, and rewrap runnable.
-    Maybe<JSAutoRealm> ar;
+    Maybe<JSAutoRealmAllowCCW> ar;
     if (scope.isObject()) {
         JSObject* scopeObj = js::UncheckedUnwrap(&scope.toObject());
         if (!scopeObj)
             return NS_ERROR_FAILURE;
         ar.emplace(cx, scopeObj);
         if (!JS_WrapValue(cx, &runnable))
             return NS_ERROR_FAILURE;
     }
@@ -2895,17 +2895,17 @@ NS_IMETHODIMP
 nsXPCComponents_Utils::GenerateXPCWrappedJS(HandleValue aObj, HandleValue aScope,
                                             JSContext* aCx, nsISupports** aOut)
 {
     if (!aObj.isObject())
         return NS_ERROR_INVALID_ARG;
     RootedObject obj(aCx, &aObj.toObject());
     RootedObject scope(aCx, aScope.isObject() ? js::UncheckedUnwrap(&aScope.toObject())
                                               : CurrentGlobalOrNull(aCx));
-    JSAutoRealm ar(aCx, scope);
+    JSAutoRealmAllowCCW ar(aCx, scope);
     if (!JS_WrapObject(aCx, &obj))
         return NS_ERROR_FAILURE;
 
     RefPtr<WrappedJSHolder> holder = new WrappedJSHolder();
     nsresult rv = nsXPCWrappedJS::GetNewOrUsed(obj, NS_GET_IID(nsISupports),
                                                getter_AddRefs(holder->mWrappedJS));
     holder.forget(aOut);
     return rv;
@@ -2963,17 +2963,17 @@ xpc::CloneInto(JSContext* aCx, HandleVal
 
     RootedObject optionsObject(aCx, aOptions.isObject() ? &aOptions.toObject()
                                                         : nullptr);
     StackScopedCloneOptions options(aCx, optionsObject);
     if (aOptions.isObject() && !options.Parse())
         return false;
 
     {
-        JSAutoRealm ar(aCx, scope);
+        JSAutoRealmAllowCCW ar(aCx, scope);
         aCloned.set(aValue);
         if (!StackScopedClone(aCx, options, aCloned))
             return false;
     }
 
     return JS_WrapValue(aCx, aCloned);
 }
 
--- a/js/xpconnect/src/XPCConvert.cpp
+++ b/js/xpconnect/src/XPCConvert.cpp
@@ -971,17 +971,17 @@ XPCConvert::JSObject2NativeInterface(voi
                                      nsISupports* aOuter,
                                      nsresult* pErr)
 {
     MOZ_ASSERT(dest, "bad param");
     MOZ_ASSERT(src, "bad param");
     MOZ_ASSERT(iid, "bad param");
 
     AutoJSContext cx;
-    JSAutoRealm ar(cx, src);
+    JSAutoRealmAllowCCW ar(cx, src);
 
     *dest = nullptr;
      if (pErr)
         *pErr = NS_ERROR_XPC_BAD_CONVERT_JS;
 
     nsISupports* iface;
 
     if (!aOuter) {
--- a/js/xpconnect/src/XPCShellImpl.cpp
+++ b/js/xpconnect/src/XPCShellImpl.cpp
@@ -537,17 +537,17 @@ XPCShellInterruptCallback(JSContext* cx)
 {
     MOZ_ASSERT(sScriptedInterruptCallback->initialized());
     RootedValue callback(cx, *sScriptedInterruptCallback);
 
     // If no interrupt callback was set by script, no-op.
     if (callback.isUndefined())
         return true;
 
-    JSAutoRealm ar(cx, &callback.toObject());
+    JSAutoRealmAllowCCW ar(cx, &callback.toObject());
     RootedValue rv(cx);
     if (!JS_CallFunctionValue(cx, nullptr, callback, JS::HandleValueArray::empty(), &rv) ||
         !rv.isBoolean())
     {
         NS_WARNING("Scripted interrupt callback failed! Terminating script.");
         JS_ClearPendingException(cx);
         return false;
     }
@@ -1333,17 +1333,17 @@ XRE_XPCShellMain(int argc, char** argv, 
 
         {
             if (!glob) {
                 return 1;
             }
 
             backstagePass->SetGlobalObject(glob);
 
-            JSAutoRealm ar(cx, glob);
+            JSAutoRealmAllowCCW ar(cx, glob);
 
             // Even if we're building in a configuration where source is
             // discarded, there's no reason to do that on XPCShell, and doing so
             // might break various automation scripts.
             JS::RealmBehaviorsRef(cx).setDiscardSource(false);
 
             if (!JS_InitReflectParse(cx, glob)) {
                 return 1;
--- a/js/xpconnect/src/XPCWrappedJSClass.cpp
+++ b/js/xpconnect/src/XPCWrappedJSClass.cpp
@@ -443,17 +443,17 @@ public:
 };
 
 NS_IMPL_ISUPPORTS(WrappedJSNamed, nsINamed)
 
 nsCString
 GetFunctionName(JSContext* cx, HandleObject obj)
 {
     RootedObject inner(cx, js::UncheckedUnwrap(obj));
-    JSAutoRealm ar(cx, inner);
+    JSAutoRealmAllowCCW ar(cx, inner);
 
     RootedFunction fun(cx, JS_GetObjectFunction(inner));
     if (!fun) {
         // If the object isn't a function, it's likely that it has a single
         // function property (for things like nsITimerCallback). In this case,
         // return the name of that function property.
 
         Rooted<IdVector> idArray(cx, IdVector(cx));
@@ -560,17 +560,17 @@ nsXPCWrappedJSClass::DelegatedQueryInter
         *aInstancePtr = nullptr;
         return NS_NOINTERFACE;
     }
 
     // We passed the unwrapped object's global to AutoEntryScript so we now need
     // to enter the (maybe wrapper) object's realm. We will have to revisit this
     // later because CCWs are not associated with a single realm so this
     // doesn't make much sense. See bug 1478359.
-    JSAutoRealm ar(aes.cx(), obj);
+    JSAutoRealmAllowCCW ar(aes.cx(), obj);
 
     // We support nsISupportsWeakReference iff the root wrapped JSObject
     // claims to support it in its QueryInterface implementation.
     if (aIID.Equals(NS_GET_IID(nsISupportsWeakReference))) {
         // We only want to expose one implementation from our aggregate.
         nsXPCWrappedJS* root = self->GetRootWrapper();
 
         // Fail if JSObject doesn't claim support for nsISupportsWeakReference
@@ -957,17 +957,17 @@ nsXPCWrappedJSClass::CallMethod(nsXPCWra
 
     if (!cx || !IsReflectable(methodIndex))
         return NS_ERROR_FAILURE;
 
     // We passed the unwrapped object's global to AutoEntryScript so we now need
     // to enter the (maybe wrapper) object's realm. We will have to revisit this
     // later because CCWs are not associated with a single realm so this
     // doesn't make much sense. See bug 1478359.
-    JSAutoRealm ar(cx, obj);
+    JSAutoRealmAllowCCW ar(cx, obj);
 
     // [optional_argc] has a different calling convention, which we don't
     // support for JS-implemented components.
     if (info->WantsOptArgc()) {
         const char* str = "IDL methods marked with [optional_argc] may not "
                           "be implemented in JS";
         // Throw and warn for good measure.
         JS_ReportErrorASCII(cx, "%s", str);
--- a/js/xpconnect/src/XPCWrappedNative.cpp
+++ b/js/xpconnect/src/XPCWrappedNative.cpp
@@ -183,17 +183,17 @@ XPCWrappedNative::WrapNewGlobal(xpcObjec
         aOptions.creationOptions().setSharedMemoryAndAtomicsEnabled(true);
     RootedObject global(cx, xpc::CreateGlobalObject(cx, clasp, principal, aOptions));
     if (!global)
         return NS_ERROR_FAILURE;
     XPCWrappedNativeScope* scope = RealmPrivate::Get(global)->scope;
 
     // Immediately enter the global's realm, so that everything else we
     // create ends up there.
-    JSAutoRealm ar(cx, global);
+    JSAutoRealmAllowCCW ar(cx, global);
 
     // If requested, initialize the standard classes on the global.
     if (initStandardClasses && !JS::InitRealmStandardClasses(cx))
         return NS_ERROR_FAILURE;
 
     // Make a proto.
     XPCWrappedNativeProto* proto =
         XPCWrappedNativeProto::GetNewOrUsed(scope,
@@ -337,17 +337,17 @@ XPCWrappedNative::GetNewOrUsed(xpcObject
     // described by the nsIClassInfo, not for the class info object
     // itself.
     if (!isClassInfoSingleton)
         GatherScriptable(identity, info, getter_AddRefs(scrProto),
                          getter_AddRefs(scrWrapper));
 
     RootedObject parent(cx, Scope->GetGlobalJSObject());
 
-    mozilla::Maybe<JSAutoRealm> ar;
+    mozilla::Maybe<JSAutoRealmAllowCCW> ar;
 
     if (scrWrapper && scrWrapper->WantPreCreate()) {
         RootedObject plannedParent(cx, parent);
         nsresult rv =
             scrWrapper->PreCreate(identity, cx, parent, parent.address());
         if (NS_FAILED(rv))
             return rv;
         rv = NS_OK;
--- a/js/xpconnect/src/XPCWrappedNativeJSOps.cpp
+++ b/js/xpconnect/src/XPCWrappedNativeJSOps.cpp
@@ -152,17 +152,17 @@ GetDoubleWrappedJSObject(XPCCallContext&
     nsCOMPtr<nsIXPConnectWrappedJS>
         underware = do_QueryInterface(wrapper->GetIdentityObject());
     if (underware) {
         RootedObject mainObj(ccx, underware->GetJSObject());
         if (mainObj) {
             RootedId id(ccx, ccx.GetContext()->
                             GetStringID(XPCJSContext::IDX_WRAPPED_JSOBJECT));
 
-            JSAutoRealm ar(ccx, mainObj);
+            JSAutoRealmAllowCCW ar(ccx, mainObj);
 
             RootedValue val(ccx);
             if (JS_GetPropertyById(ccx, mainObj, id, &val) &&
                 !val.isPrimitive()) {
                 obj = val.toObjectOrNull();
             }
         }
     }
--- a/js/xpconnect/src/XPCWrappedNativeScope.cpp
+++ b/js/xpconnect/src/XPCWrappedNativeScope.cpp
@@ -286,17 +286,17 @@ XPCWrappedNativeScope::AllowContentXBLSc
     return mAllowContentXBLScope;
 }
 
 namespace xpc {
 JSObject*
 GetXBLScope(JSContext* cx, JSObject* contentScopeArg)
 {
     JS::RootedObject contentScope(cx, contentScopeArg);
-    JSAutoRealm ar(cx, contentScope);
+    JSAutoRealmAllowCCW ar(cx, contentScope);
     XPCWrappedNativeScope* nativeScope = RealmPrivate::Get(contentScope)->scope;
 
     RootedObject scope(cx, nativeScope->EnsureContentXBLScope(cx));
     NS_ENSURE_TRUE(scope, nullptr); // See bug 858642.
 
     scope = js::UncheckedUnwrap(scope);
     JS::ExposeObjectToActiveJS(scope);
     return scope;
--- a/js/xpconnect/src/XPCWrapper.cpp
+++ b/js/xpconnect/src/XPCWrapper.cpp
@@ -62,17 +62,17 @@ XrayWrapperConstructor(JSContext* cx, un
   return JS_WrapValue(cx, args.rval());
 }
 // static
 bool
 AttachNewConstructorObject(JSContext* aCx, JS::HandleObject aGlobalObject)
 {
   // Pushing a JSContext calls ActivateDebugger which calls this function, so
   // we can't use an AutoJSContext here until JSD is gone.
-  JSAutoRealm ar(aCx, aGlobalObject);
+  JSAutoRealmAllowCCW ar(aCx, aGlobalObject);
   JSFunction* xpcnativewrapper =
     JS_DefineFunction(aCx, aGlobalObject, "XPCNativeWrapper",
                       XrayWrapperConstructor, 1,
                       JSPROP_READONLY | JSPROP_PERMANENT | JSFUN_CONSTRUCTOR);
   if (!xpcnativewrapper) {
     return false;
   }
   JS::RootedObject obj(aCx, JS_GetFunctionObject(xpcnativewrapper));
--- a/js/xpconnect/src/nsXPConnect.cpp
+++ b/js/xpconnect/src/nsXPConnect.cpp
@@ -461,17 +461,17 @@ CreateGlobalObject(JSContext* cx, const 
     MOZ_RELEASE_ASSERT(principal != nsContentUtils::GetNullSubjectPrincipal(),
                        "The null subject principal is getting inherited - fix that!");
 
     RootedObject global(cx,
                         JS_NewGlobalObject(cx, clasp, nsJSPrincipals::get(principal),
                                            JS::DontFireOnNewGlobalHook, aOptions));
     if (!global)
         return nullptr;
-    JSAutoRealm ar(cx, global);
+    JSAutoRealmAllowCCW ar(cx, global);
 
     // The constructor automatically attaches the scope to the compartment private
     // of |global|.
     (void) new XPCWrappedNativeScope(cx, global);
 
     if (clasp->flags & JSCLASS_DOM_GLOBAL) {
 #ifdef DEBUG
         // Verify that the right trace hook is called. Note that this doesn't
@@ -526,17 +526,17 @@ InitGlobalObjectOptions(JS::RealmOptions
     }
 }
 
 bool
 InitGlobalObject(JSContext* aJSContext, JS::Handle<JSObject*> aGlobal, uint32_t aFlags)
 {
     // Immediately enter the global's realm so that everything we create
     // ends up there.
-    JSAutoRealm ar(aJSContext, aGlobal);
+    JSAutoRealmAllowCCW ar(aJSContext, aGlobal);
 
     // Stuff coming through this path always ends up as a DOM global.
     MOZ_ASSERT(js::GetObjectClass(aGlobal)->flags & JSCLASS_DOM_GLOBAL);
 
     if (!(aFlags & xpc::OMIT_COMPONENTS_OBJECT)) {
         // XPCCallContext gives us an active request needed to save/restore.
         if (!RealmPrivate::Get(aGlobal)->scope->AttachComponentsObject(aJSContext) ||
             !XPCNativeWrapper::AttachNewConstructorObject(aJSContext, aGlobal)) {
@@ -599,17 +599,17 @@ static nsresult
 NativeInterface2JSObject(HandleObject aScope,
                          nsISupports* aCOMObj,
                          nsWrapperCache* aCache,
                          const nsIID * aIID,
                          bool aAllowWrapping,
                          MutableHandleValue aVal)
 {
     AutoJSContext cx;
-    JSAutoRealm ar(cx, aScope);
+    JSAutoRealmAllowCCW ar(cx, aScope);
 
     nsresult rv;
     xpcObjectHelper helper(aCOMObj, aCache);
     if (!XPCConvert::NativeInterface2JSObject(aVal, helper, aIID, aAllowWrapping, &rv))
         return rv;
 
     MOZ_ASSERT(aAllowWrapping || !xpc::WrapperFactory::IsXrayWrapper(&aVal.toObject()),
                "Shouldn't be returning a xray wrapper here");
@@ -668,17 +668,17 @@ nsXPConnect::WrapJS(JSContext * aJSConte
 {
     MOZ_ASSERT(aJSContext, "bad param");
     MOZ_ASSERT(aJSObjArg, "bad param");
     MOZ_ASSERT(result, "bad param");
 
     *result = nullptr;
 
     RootedObject aJSObj(aJSContext, aJSObjArg);
-    JSAutoRealm ar(aJSContext, aJSObj);
+    JSAutoRealmAllowCCW ar(aJSContext, aJSObj);
 
     nsresult rv = NS_ERROR_UNEXPECTED;
     if (!XPCConvert::JSObject2NativeInterface(result, aJSObj,
                                               &aIID, nullptr, &rv))
         return rv;
     return NS_OK;
 }
 
@@ -803,17 +803,17 @@ nsXPConnect::EvalInSandboxObject(const n
 
 NS_IMETHODIMP
 nsXPConnect::GetWrappedNativePrototype(JSContext* aJSContext,
                                        JSObject* aScopeArg,
                                        nsIClassInfo* aClassInfo,
                                        JSObject** aRetVal)
 {
     RootedObject aScope(aJSContext, aScopeArg);
-    JSAutoRealm ar(aJSContext, aScope);
+    JSAutoRealmAllowCCW ar(aJSContext, aScope);
 
     XPCWrappedNativeScope* scope = ObjectScope(aScope);
     if (!scope)
         return UnexpectedFailure(NS_ERROR_FAILURE);
 
     nsCOMPtr<nsIXPCScriptable> scrProto =
         XPCWrappedNative::GatherProtoScriptable(aClassInfo);
 
--- a/js/xpconnect/src/xpcprivate.h
+++ b/js/xpconnect/src/xpcprivate.h
@@ -2238,17 +2238,17 @@ public:
     /**
      * Does the post script evaluation.
      */
     ~AutoScriptEvaluate();
 private:
     JSContext* mJSContext;
     mozilla::Maybe<JS::AutoSaveExceptionState> mState;
     bool mEvaluated;
-    mozilla::Maybe<JSAutoRealm> mAutoRealm;
+    mozilla::Maybe<JSAutoRealmAllowCCW> mAutoRealm;
     MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
 
     // No copying or assignment allowed
     AutoScriptEvaluate(const AutoScriptEvaluate&) = delete;
     AutoScriptEvaluate & operator =(const AutoScriptEvaluate&) = delete;
 };
 
 /***************************************************************************/
--- a/js/xpconnect/wrappers/WrapperFactory.cpp
+++ b/js/xpconnect/wrappers/WrapperFactory.cpp
@@ -68,17 +68,17 @@ WrapperFactory::GetXrayWaiver(HandleObje
 JSObject*
 WrapperFactory::CreateXrayWaiver(JSContext* cx, HandleObject obj)
 {
     // The caller is required to have already done a lookup.
     // NB: This implictly performs the assertions of GetXrayWaiver.
     MOZ_ASSERT(!GetXrayWaiver(obj));
     XPCWrappedNativeScope* scope = ObjectScope(obj);
 
-    JSAutoRealm ar(cx, obj);
+    JSAutoRealmAllowCCW ar(cx, obj);
     JSObject* waiver = Wrapper::New(cx, obj, &XrayWaiver);
     if (!waiver)
         return nullptr;
 
     // Add the new waiver to the map. It's important that we only ever have
     // one waiver for the lifetime of the target object.
     if (!scope->mWaiverWrapperMap) {
         scope->mWaiverWrapperMap =
@@ -223,17 +223,17 @@ WrapperFactory::PrepareForWrapping(JSCon
     // between scopes so for those we also want to return the wrapper. So...
     if (!IS_WN_REFLECTOR(obj) || JS_IsGlobalObject(obj)) {
         retObj.set(waive ? WaiveXray(cx, obj) : obj);
         return;
     }
 
     XPCWrappedNative* wn = XPCWrappedNative::Get(obj);
 
-    JSAutoRealm ar(cx, obj);
+    JSAutoRealmAllowCCW ar(cx, obj);
     XPCCallContext ccx(cx, obj);
     RootedObject wrapScope(cx, scope);
 
     {
         if (ccx.GetScriptable() && ccx.GetScriptable()->WantPreCreate()) {
             // We have a precreate hook. This object might enforce that we only
             // ever create JS object for it.
 
--- a/js/xpconnect/wrappers/XrayWrapper.cpp
+++ b/js/xpconnect/wrappers/XrayWrapper.cpp
@@ -273,17 +273,17 @@ ReportWrapperDenial(JSContext* cx, Handl
 bool JSXrayTraits::getOwnPropertyFromWrapperIfSafe(JSContext* cx,
                                                    HandleObject wrapper,
                                                    HandleId id,
                                                    MutableHandle<PropertyDescriptor> outDesc)
 {
     MOZ_ASSERT(js::IsObjectInContextCompartment(wrapper, cx));
     RootedObject target(cx, getTargetObject(wrapper));
     {
-        JSAutoRealm ar(cx, target);
+        JSAutoRealmAllowCCW ar(cx, target);
         JS_MarkCrossZoneId(cx, id);
         if (!getOwnPropertyFromTargetIfSafe(cx, target, wrapper, id, outDesc))
             return false;
     }
     return JS_WrapPropertyDescriptor(cx, outDesc);
 }
 
 bool JSXrayTraits::getOwnPropertyFromTargetIfSafe(JSContext* cx,
@@ -304,52 +304,52 @@ bool JSXrayTraits::getOwnPropertyFromTar
         return false;
 
     // If the property doesn't exist at all, we're done.
     if (!desc.object())
         return true;
 
     // Disallow accessor properties.
     if (desc.hasGetterOrSetter()) {
-        JSAutoRealm ar(cx, wrapper);
+        JSAutoRealmAllowCCW ar(cx, wrapper);
         JS_MarkCrossZoneId(cx, id);
         return ReportWrapperDenial(cx, id, WrapperDenialForXray, "property has accessor");
     }
 
     // Apply extra scrutiny to objects.
     if (desc.value().isObject()) {
         RootedObject propObj(cx, js::UncheckedUnwrap(&desc.value().toObject()));
-        JSAutoRealm ar(cx, propObj);
+        JSAutoRealmAllowCCW ar(cx, propObj);
 
         // Disallow non-subsumed objects.
         if (!AccessCheck::subsumes(target, propObj)) {
-            JSAutoRealm ar(cx, wrapper);
+            JSAutoRealmAllowCCW ar(cx, wrapper);
             JS_MarkCrossZoneId(cx, id);
             return ReportWrapperDenial(cx, id, WrapperDenialForXray, "value not same-origin with target");
         }
 
         // Disallow non-Xrayable objects.
         XrayType xrayType = GetXrayType(propObj);
         if (xrayType == NotXray || xrayType == XrayForOpaqueObject) {
-            JSAutoRealm ar(cx, wrapper);
+            JSAutoRealmAllowCCW ar(cx, wrapper);
             JS_MarkCrossZoneId(cx, id);
             return ReportWrapperDenial(cx, id, WrapperDenialForXray, "value not Xrayable");
         }
 
         // Disallow callables.
         if (JS::IsCallable(propObj)) {
-            JSAutoRealm ar(cx, wrapper);
+            JSAutoRealmAllowCCW ar(cx, wrapper);
             JS_MarkCrossZoneId(cx, id);
             return ReportWrapperDenial(cx, id, WrapperDenialForXray, "value is callable");
         }
     }
 
     // Disallow any property that shadows something on its (Xrayed)
     // prototype chain.
-    JSAutoRealm ar2(cx, wrapper);
+    JSAutoRealmAllowCCW ar2(cx, wrapper);
     JS_MarkCrossZoneId(cx, id);
     RootedObject proto(cx);
     bool foundOnProto = false;
     if (!JS_GetPrototype(cx, wrapper, &proto) ||
         (proto && !JS_HasPropertyById(cx, proto, id, &foundOnProto)))
     {
         return false;
     }
@@ -509,17 +509,17 @@ JSXrayTraits::resolveOwnProperty(JSConte
         }
         if (IsTypedArrayKey(key)) {
             if (IsArrayIndex(GetArrayIndexFromId(cx, id))) {
                 // WebExtensions can't use cloneInto(), so we just let them do
                 // the slow thing to maximize compatibility.
                 if (CompartmentPrivate::Get(CurrentGlobalOrNull(cx))->isWebExtensionContentScript) {
                     Rooted<PropertyDescriptor> innerDesc(cx);
                     {
-                        JSAutoRealm ar(cx, target);
+                        JSAutoRealmAllowCCW ar(cx, target);
                         JS_MarkCrossZoneId(cx, id);
                         if (!JS_GetOwnPropertyDescriptorById(cx, target, id, &innerDesc))
                             return false;
                     }
                     if (innerDesc.isDataDescriptor() && innerDesc.value().isNumber()) {
                         desc.setValue(innerDesc.value());
                         desc.object().set(wrapper);
                     }
@@ -547,17 +547,17 @@ JSXrayTraits::resolveOwnProperty(JSConte
                 // 'prototype' property.
                 JSProtoKey standardConstructor = constructorFor(holder);
                 if (standardConstructor != JSProto_Null) {
                     // Handle the 'prototype' property to make
                     // xrayedGlobal.StandardClass.prototype work.
                     if (id == GetJSIDByIndex(cx, XPCJSContext::IDX_PROTOTYPE)) {
                         RootedObject standardProto(cx);
                         {
-                            JSAutoRealm ar(cx, target);
+                            JSAutoRealmAllowCCW ar(cx, target);
                             if (!JS_GetClassPrototype(cx, standardConstructor, &standardProto))
                                 return false;
                             MOZ_ASSERT(standardProto);
                         }
 
                         if (!JS_WrapObject(cx, &standardProto))
                             return false;
                         FillPropertyDescriptor(desc, wrapper, JSPROP_PERMANENT | JSPROP_READONLY,
@@ -617,17 +617,17 @@ JSXrayTraits::resolveOwnProperty(JSConte
         // The rest of this function applies only to prototypes.
         return true;
     }
 
     // Handle the 'constructor' property.
     if (id == GetJSIDByIndex(cx, XPCJSContext::IDX_CONSTRUCTOR)) {
         RootedObject constructor(cx);
         {
-            JSAutoRealm ar(cx, target);
+            JSAutoRealmAllowCCW ar(cx, target);
             if (!JS_GetClassObject(cx, key, &constructor))
                 return false;
         }
         if (!JS_WrapObject(cx, &constructor))
             return false;
         desc.object().set(wrapper);
         desc.setAttributes(0);
         desc.setGetter(nullptr);
@@ -666,17 +666,17 @@ JSXrayTraits::delete_(JSContext* cx, Han
     // If we're using Object Xrays, we allow callers to attempt to delete any
     // property from the underlying object that they are able to resolve. Note
     // that this deleting may fail if the property is non-configurable.
     JSProtoKey key = getProtoKey(holder);
     bool isObjectOrArrayInstance = (key == JSProto_Object || key == JSProto_Array) &&
                                    !isPrototype(holder);
     if (isObjectOrArrayInstance) {
         RootedObject target(cx, getTargetObject(wrapper));
-        JSAutoRealm ar(cx, target);
+        JSAutoRealmAllowCCW ar(cx, target);
         JS_MarkCrossZoneId(cx, id);
         Rooted<PropertyDescriptor> desc(cx);
         if (!getOwnPropertyFromTargetIfSafe(cx, target, wrapper, id, &desc))
             return false;
         if (desc.object())
             return JS_DeletePropertyById(cx, target, id, result);
     }
     return result.succeed();
@@ -724,17 +724,17 @@ JSXrayTraits::defineProperty(JSContext* 
             return false;
         }
         if (existingDesc.object() && existingDesc.object() != wrapper) {
             JS_ReportErrorASCII(cx, "Not allowed to shadow non-own Xray-resolved property on [Object] or [Array] XrayWrapper");
             return false;
         }
 
         Rooted<PropertyDescriptor> wrappedDesc(cx, desc);
-        JSAutoRealm ar(cx, target);
+        JSAutoRealmAllowCCW ar(cx, target);
         JS_MarkCrossZoneId(cx, id);
         if (!JS_WrapPropertyDescriptor(cx, &wrappedDesc) ||
             !JS_DefinePropertyById(cx, target, id, wrappedDesc, result))
         {
             return false;
         }
         *defined = true;
         return true;
@@ -743,17 +743,17 @@ JSXrayTraits::defineProperty(JSContext* 
     // For WebExtensions content scripts, we forward the definition of indexed properties. By
     // validating that the key and value are both numbers, we can avoid doing any wrapping.
     if (isInstance && IsTypedArrayKey(key) &&
         CompartmentPrivate::Get(JS::CurrentGlobalOrNull(cx))->isWebExtensionContentScript &&
         desc.isDataDescriptor() && (desc.value().isNumber() || desc.value().isUndefined()) &&
         IsArrayIndex(GetArrayIndexFromId(cx, id)))
     {
         RootedObject target(cx, getTargetObject(wrapper));
-        JSAutoRealm ar(cx, target);
+        JSAutoRealmAllowCCW ar(cx, target);
         JS_MarkCrossZoneId(cx, id);
         if (!JS_DefinePropertyById(cx, target, id, desc, result))
             return false;
         *defined = true;
         return true;
     }
 
     return true;
@@ -806,17 +806,17 @@ JSXrayTraits::enumerateNames(JSContext* 
 
     JSProtoKey key = getProtoKey(holder);
     if (!isPrototype(holder)) {
         // For Object and Array instances, we expose some properties from the underlying
         // object, but only after filtering them carefully.
         if (key == JSProto_Object || key == JSProto_Array) {
             MOZ_ASSERT(props.empty());
             {
-                JSAutoRealm ar(cx, target);
+                JSAutoRealmAllowCCW ar(cx, target);
                 AutoIdVector targetProps(cx);
                 if (!js::GetPropertyKeys(cx, target, flags | JSITER_OWNONLY, &targetProps))
                     return false;
                 // Loop over the properties, and only pass along the ones that
                 // we determine to be safe.
                 if (!props.reserve(targetProps.length()))
                     return false;
                 for (size_t i = 0; i < targetProps.length(); ++i) {
@@ -1104,17 +1104,17 @@ XrayTraits::getExpandoObjectInternal(JSC
         }
 #endif
         return true;
     }
 
     // The expando object lives in the compartment of the target, so all our
     // work needs to happen there.
     RootedObject head(cx, expandoChain);
-    JSAutoRealm ar(cx, head);
+    JSAutoRealmAllowCCW ar(cx, head);
 
     // Iterate through the chain, looking for a same-origin object.
     while (head) {
         if (expandoObjectMatchesConsumer(cx, head, origin)) {
             expandoObject.set(head);
             return true;
         }
         head = JS_GetReservedSlot(head, JSSLOT_EXPANDO_NEXT).toObjectOrNull();
@@ -1188,31 +1188,31 @@ XrayTraits::attachExpandoObject(JSContex
 
     // AddRef and store the principal.
     NS_ADDREF(origin);
     JS_SetReservedSlot(expandoObject, JSSLOT_EXPANDO_ORIGIN, JS::PrivateValue(origin));
 
     // Note the exclusive wrapper, if there is one.
     RootedObject wrapperHolder(cx);
     if (exclusiveWrapper) {
-        JSAutoRealm ar(cx, exclusiveWrapper);
+        JSAutoRealmAllowCCW ar(cx, exclusiveWrapper);
         wrapperHolder = JS_NewObjectWithGivenProto(cx, &gWrapperHolderClass, nullptr);
         if (!wrapperHolder)
             return nullptr;
         JS_SetReservedSlot(wrapperHolder, JSSLOT_WRAPPER_HOLDER_CONTENTS, ObjectValue(*exclusiveWrapper));
     }
     if (!JS_WrapObject(cx, &wrapperHolder))
         return nullptr;
     JS_SetReservedSlot(expandoObject, JSSLOT_EXPANDO_EXCLUSIVE_WRAPPER_HOLDER,
                        ObjectOrNullValue(wrapperHolder));
 
     // Store it on the exclusive wrapper, if there is one.
     if (exclusiveWrapper) {
         RootedObject cachedExpandoObject(cx, expandoObject);
-        JSAutoRealm ar(cx, exclusiveWrapper);
+        JSAutoRealmAllowCCW ar(cx, exclusiveWrapper);
         if (!JS_WrapObject(cx, &cachedExpandoObject))
             return nullptr;
         JSObject* holder = ensureHolder(cx, exclusiveWrapper);
         if (!holder)
             return nullptr;
         SetCachedXrayExpando(holder, cachedExpandoObject);
     }
 
@@ -1230,17 +1230,17 @@ XrayTraits::attachExpandoObject(JSContex
     return expandoObject;
 }
 
 JSObject*
 XrayTraits::ensureExpandoObject(JSContext* cx, HandleObject wrapper,
                                 HandleObject target)
 {
     // Expando objects live in the target compartment.
-    JSAutoRealm ar(cx, target);
+    JSAutoRealmAllowCCW ar(cx, target);
     RootedObject expandoObject(cx);
     if (!getExpandoObject(cx, target, wrapper, &expandoObject))
         return nullptr;
     if (!expandoObject) {
         bool isExclusive = CompartmentHasExclusiveExpandos(wrapper);
         expandoObject = attachExpandoObject(cx, target, isExclusive ? wrapper : nullptr,
                                             ObjectPrincipal(wrapper));
     }
@@ -1272,23 +1272,23 @@ XrayTraits::cloneExpandoChain(JSContext*
             // compartment of dst).
             movingIntoXrayCompartment =
                 js::IsObjectInContextCompartment(unwrappedHolder, cx);
 
             if (!movingIntoXrayCompartment) {
                 // The global containing this wrapper holder has an xray for |src|
                 // with expandos. Create an xray in the global for |dst| which
                 // will be associated with a clone of |src|'s expando object.
-                JSAutoRealm ar(cx, unwrappedHolder);
+                JSAutoRealmAllowCCW ar(cx, unwrappedHolder);
                 exclusiveWrapper = dst;
                 if (!JS_WrapObject(cx, &exclusiveWrapper))
                     return false;
             }
         } else {
-            JSAutoRealm ar(cx, oldHead);
+            JSAutoRealmAllowCCW ar(cx, oldHead);
             movingIntoXrayCompartment =
                 expandoObjectMatchesConsumer(cx, oldHead, ObjectPrincipal(dst));
         }
 
         if (movingIntoXrayCompartment) {
             // Just copy properties directly onto dst.
             if (!JS_CopyPropertiesFrom(cx, dst, oldHead))
                 return false;
@@ -1428,27 +1428,27 @@ XrayTraits::resolveOwnProperty(JSContext
     RootedObject expando(cx);
     if (!getExpandoObject(cx, target, wrapper, &expando))
         return false;
 
     // Check for expando properties first. Note that the expando object lives
     // in the target compartment.
     bool found = false;
     if (expando) {
-        JSAutoRealm ar(cx, expando);
+        JSAutoRealmAllowCCW ar(cx, expando);
         JS_MarkCrossZoneId(cx, id);
         if (!JS_GetOwnPropertyDescriptorById(cx, expando, id, desc))
             return false;
         found = !!desc.object();
     }
 
     // Next, check for ES builtins.
     if (!found && JS_IsGlobalObject(target)) {
         JSProtoKey key = JS_IdToProtoKey(cx, id);
-        JSAutoRealm ar(cx, target);
+        JSAutoRealmAllowCCW ar(cx, target);
         if (key != JSProto_Null) {
             MOZ_ASSERT(key < JSProto_LIMIT);
             RootedObject constructor(cx);
             if (!JS_GetClassObject(cx, key, &constructor))
                 return false;
             MOZ_ASSERT(constructor);
             desc.value().set(ObjectValue(*constructor));
             found = true;
@@ -1924,17 +1924,17 @@ XrayWrapper<Base, Traits>::definePropert
     if (!Traits::singleton.defineProperty(cx, wrapper, id, desc, existing_desc, result, &defined))
         return false;
     if (defined)
         return true;
 
     // We're placing an expando. The expando objects live in the target
     // compartment, so we need to enter it.
     RootedObject target(cx, Traits::getTargetObject(wrapper));
-    JSAutoRealm ar(cx, target);
+    JSAutoRealmAllowCCW ar(cx, target);
     JS_MarkCrossZoneId(cx, id);
 
     // Grab the relevant expando object.
     RootedObject expandoObject(cx, Traits::singleton.ensureExpandoObject(cx, wrapper,
                                                                          target));
     if (!expandoObject)
         return false;
 
@@ -1968,17 +1968,17 @@ XrayWrapper<Base, Traits>::delete_(JSCon
 
     // Check the expando object.
     RootedObject target(cx, Traits::getTargetObject(wrapper));
     RootedObject expando(cx);
     if (!Traits::singleton.getExpandoObject(cx, target, wrapper, &expando))
         return false;
 
     if (expando) {
-        JSAutoRealm ar(cx, expando);
+        JSAutoRealmAllowCCW ar(cx, expando);
         JS_MarkCrossZoneId(cx, id);
         bool hasProp;
         if (!JS_HasPropertyById(cx, expando, id, &hasProp)) {
             return false;
         }
         if (hasProp) {
             return JS_DeletePropertyById(cx, expando, id, result);
         }
@@ -2125,18 +2125,18 @@ XrayWrapper<Base, Traits>::getPrototype(
         return false;
 
     // We want to keep the Xray's prototype distinct from that of content, but
     // only if there's been a set. If there's not an expando, or the expando
     // slot is |undefined|, hand back the default proto, appropriately wrapped.
 
     if (expando) {
         RootedValue v(cx);
-        { // Scope for JSAutoRealm
-            JSAutoRealm ar(cx, expando);
+        { // Scope for JSAutoRealmAllowCCW
+            JSAutoRealmAllowCCW ar(cx, expando);
             v = JS_GetReservedSlot(expando, JSSLOT_EXPANDO_PROTOTYPE);
         }
         if (!v.isUndefined()) {
             protop.set(v.toObjectOrNull());
             return JS_WrapObject(cx, protop);
         }
     }
 
@@ -2170,17 +2170,17 @@ XrayWrapper<Base, Traits>::setPrototype(
         return Base::setPrototype(cx, wrapper, proto, result);
 
     RootedObject target(cx, Traits::getTargetObject(wrapper));
     RootedObject expando(cx, Traits::singleton.ensureExpandoObject(cx, wrapper, target));
     if (!expando)
         return false;
 
     // The expando lives in the target's realm, so do our installation there.
-    JSAutoRealm ar(cx, target);
+    JSAutoRealmAllowCCW ar(cx, target);
 
     RootedValue v(cx, ObjectOrNullValue(proto));
     if (!JS_WrapValue(cx, &v))
         return false;
     JS_SetReservedSlot(expando, JSSLOT_EXPANDO_PROTOTYPE, v);
     return result.succeed();
 }
 
@@ -2223,17 +2223,17 @@ XrayWrapper<Base, Traits>::getPropertyKe
     // Enumerate expando properties first. Note that the expando object lives
     // in the target compartment.
     RootedObject target(cx, Traits::getTargetObject(wrapper));
     RootedObject expando(cx);
     if (!Traits::singleton.getExpandoObject(cx, target, wrapper, &expando))
         return false;
 
     if (expando) {
-        JSAutoRealm ar(cx, expando);
+        JSAutoRealmAllowCCW ar(cx, expando);
         if (!js::GetPropertyKeys(cx, expando, flags, &props))
             return false;
     }
     for (size_t i = 0; i < props.length(); ++i)
         JS_MarkCrossZoneId(cx, props[i]);
 
     return Traits::singleton.enumerateNames(cx, wrapper, flags, props);
 }
--- a/js/xpconnect/wrappers/XrayWrapper.h
+++ b/js/xpconnect/wrappers/XrayWrapper.h
@@ -220,17 +220,17 @@ public:
             if (protoKey == JSProto_Null) {
                 protop.set(nullptr);
                 return true;
             }
             key = protoKey;
         }
 
         {
-            JSAutoRealm ar(cx, target);
+            JSAutoRealmAllowCCW ar(cx, target);
             if (!JS_GetClassPrototype(cx, key, protop))
                 return false;
         }
         return JS_WrapObject(cx, protop);
     }
 
     virtual void preserveWrapper(JSObject* target) override {
         // In the case of pure JS objects, there is no underlying object, and
@@ -324,17 +324,17 @@ public:
     bool getPrototype(JSContext* cx, JS::HandleObject wrapper,
                       JS::HandleObject target,
                       JS::MutableHandleObject protop)
     {
         // Opaque wrappers just get targetGlobal.Object.prototype as their
         // prototype. This is preferable to using a null prototype because it
         // lets things like |toString| and |__proto__| work.
         {
-            JSAutoRealm ar(cx, target);
+            JSAutoRealmAllowCCW ar(cx, target);
             if (!JS_GetClassPrototype(cx, JSProto_Object, protop))
                 return false;
         }
         return JS_WrapObject(cx, protop);
     }
 
     static bool getBuiltinClass(JSContext* cx, JS::HandleObject wrapper, const js::Wrapper& baseInstance,
                                 js::ESClass* cls) {
--- a/layout/generic/nsTextFrame.cpp
+++ b/layout/generic/nsTextFrame.cpp
@@ -3635,20 +3635,23 @@ PropertyProvider::GetHyphenationBreaks(R
            run.GetSkippedOffset() > mStart.GetSkippedOffset())
           ? HyphenType::Soft
           : HyphenType::None;
       allowHyphenBreakBeforeNextChar = false;
     }
   }
 
   if (mTextStyle->mHyphens == StyleHyphens::Auto) {
-    uint32_t currentFragOffset = mStart.GetOriginalOffset();
+    gfxSkipCharsIterator skipIter(mStart);
     for (uint32_t i = 0; i < aRange.Length(); ++i) {
-      if (IS_HYPHEN(mFrag->CharAt(currentFragOffset + i))) {
-        aBreakBefore[i] = HyphenType::Explicit;
+      if (IS_HYPHEN(mFrag->
+          CharAt(skipIter.ConvertSkippedToOriginal(aRange.start + i)))) {
+        if (i < aRange.Length() - 1) {
+          aBreakBefore[i + 1] = HyphenType::Explicit;
+        }
         continue;
       }
 
       if (mTextRun->CanHyphenateBefore(aRange.start + i) &&
           aBreakBefore[i] == HyphenType::None) {
         aBreakBefore[i] = HyphenType::AutoWithoutManualInSameWord;
       }
     }
new file mode 100644
--- /dev/null
+++ b/layout/reftests/text/hyphenation-control-5-ref.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html lang="en">
+<meta charset="utf-8">
+<style>
+body { columns: 3; }
+p { margin: 0 0 1em 0; }
+</style>
+<body>
+<p>hard-<br>hit
+<p>hard-<br>hit-<br>ting
+<p>hard-<br>est-<br>hit
+<p>hard-<br>est-<br>hit-<br>ting
+
+<p><b>hard</b>-<br>hit
+<p><b>hard</b>-<br>hit-<br>ting
+<p><b>hard-<br>est</b>-<br>hit
+<p><b>hard-<br>est</b>-<br>hit-<br>ting
+
+<p>hard-<br><b>hit</b>
+<p>hard-<br><b>hit-<br>ting</b>
+<p>hard-<br>est-<br><b>hit</b>
+<p>hard-<br>est-<br><b>hit-<br>ting</b>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/text/hyphenation-control-5.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html lang="en">
+<meta charset="utf-8">
+<style>
+body { columns: 3; }
+p { margin: 0 0 1em 0; width:0; hyphens:auto; }
+</style>
+<body>
+<p>hard-hit
+<p>hard-hitting
+<p>hardest-hit
+<p>hardest-hitting
+
+<p><b>hard</b>-hit
+<p><b>hard</b>-hitting
+<p><b>hardest</b>-hit
+<p><b>hardest</b>-hitting
+
+<p>hard-<b>hit</b>
+<p>hard-<b>hitting</b>
+<p>hardest-<b>hit</b>
+<p>hardest-<b>hitting</b>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/text/hyphenation-control-6-ref.html
@@ -0,0 +1,73 @@
+<!DOCTYPE html>
+<html lang="en">
+<meta charset="utf-8">
+<style>
+.test { hyphens:auto; font:10px monospace; border: 1px solid silver; }
+</style>
+<body>
+<p>All the columns should appear identical:</p>
+<div id="outer" style="columns:6">
+<script>
+let outer = document.getElementById("outer");
+for (i = 1; i <= 6; ++i) {
+  div = document.createElement("div");
+  div.className = "test";
+  div.style.width = "0ch";
+  div.innerHTML = "the<br>flow-<br>rel-<br>a-<br>tive";
+  outer.appendChild(div);
+
+  div = document.createElement("div");
+  div.className = "test";
+  div.style.width = "2ch";
+  div.innerHTML = "the<br>flow-<br>rel-<br>a-<br>tive";
+  outer.appendChild(div);
+
+  div = document.createElement("div");
+  div.className = "test";
+  div.style.width = "4ch";
+  div.innerHTML = "the<br>flow-<br>rel-<br>a-<br>tive";
+  outer.appendChild(div);
+
+  div = document.createElement("div");
+  div.className = "test";
+  div.style.width = "6ch";
+  div.innerHTML = "the<br>flow-<br>rela-<br>tive";
+  outer.appendChild(div);
+
+  div = document.createElement("div");
+  div.className = "test";
+  div.style.width = "8ch";
+  div.innerHTML = "the<br>flow-<br>relative";
+  outer.appendChild(div);
+
+  div = document.createElement("div");
+  div.className = "test";
+  div.style.width = "10ch";
+  div.innerHTML = "the flow-<br>relative";
+  outer.appendChild(div);
+
+  div = document.createElement("div");
+  div.className = "test";
+  div.style.width = "12ch";
+  div.innerHTML = "the flow-<br>relative";
+  outer.appendChild(div);
+
+  div = document.createElement("div");
+  div.className = "test";
+  div.style.width = "14ch";
+  div.innerHTML = "the flow-<br>relative";
+  outer.appendChild(div);
+
+  div = document.createElement("div");
+  div.className = "test";
+  div.style.width = "16ch";
+  div.innerHTML = "the flow-<br>relative";
+  outer.appendChild(div);
+
+  div = document.createElement("div");
+  div.className = "test";
+  div.style.width = "18ch";
+  div.innerHTML = "the flow-relative";
+  outer.appendChild(div);
+}
+</script>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/text/hyphenation-control-6.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html lang="en">
+<meta charset="utf-8">
+<style>
+.test { hyphens:auto; font:10px monospace; border: 1px solid silver; }
+</style>
+<body>
+<p>All the columns should appear identical:</p>
+<div id="outer" style="columns:6">
+<script>
+let outer = document.getElementById("outer");
+for (i = 1; i <= 6; ++i) {
+  for (j = 0; j <= 18; j += 2) {
+    div = document.createElement("div");
+    div.className = "test";
+    div.style.width = j + "ch";
+    div.textContent = "the" + " ".repeat(i) + "flow-relative";
+    outer.appendChild(div);
+  }
+}
+</script>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/text/hyphenation-control-7-ref.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+  <meta "charset=utf-8">
+  <style>
+  p {
+    background: yellow;
+    margin: 0 0 1em 0;
+    font-family: monospace;
+  }
+  </style>
+<body>
+<h3>The columns should appear identical; "relative" should never be hyphenated</h3>
+<div style="columns:2">
+<p style="width: 16ch">the flow-<br>relative flow-<br>relative flow-<br>relative flow-<br>relative flow-<br>relative</p>
+<p style="width: 20ch">the flow-relative<br>flow-relative flow-<br>relative flow-<br>relative flow-<br>relative</p>
+<p style="width: 24ch">the flow-relative flow-<br>relative flow-relative<br>flow-relative flow-<br>relative</p>
+<p style="width: 41ch">the flow-relative flow-relative flow-<br>relative flow-relative flow-relative</p>
+<p style="width: 50ch">the flow-relative flow-relative flow-relative<br>flow-relative flow-relative</p>
+
+<p style="width: 16ch">the flow-<br>relative flow-<br>relative flow-<br>relative flow-<br>relative flow-<br>relative</p>
+<p style="width: 20ch">the flow-relative<br>flow-relative flow-<br>relative flow-<br>relative flow-<br>relative</p>
+<p style="width: 24ch">the flow-relative flow-<br>relative flow-relative<br>flow-relative flow-<br>relative</p>
+<p style="width: 41ch">the flow-relative flow-relative flow-<br>relative flow-relative flow-relative</p>
+<p style="width: 50ch">the flow-relative flow-relative flow-relative<br>flow-relative flow-relative</p>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/text/hyphenation-control-7.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+  <meta "charset=utf-8">
+  <style>
+  p {
+    background: yellow;
+    margin: 0 0 1em 0;
+    font-family: monospace;
+    hyphens: auto;
+  }
+  </style>
+<body>
+<h3>The columns should appear identical; "relative" should never be hyphenated</h3>
+<div style="columns:2">
+<p style="width: 16ch">the   flow-relative        flow-relative    flow-relative     flow-relative    flow-relative</p>
+<p style="width: 20ch">the   flow-relative        flow-relative    flow-relative     flow-relative    flow-relative</p>
+<p style="width: 24ch">the   flow-relative        flow-relative    flow-relative     flow-relative    flow-relative</p>
+<p style="width: 41ch">the   flow-relative        flow-relative    flow-relative     flow-relative    flow-relative</p>
+<p style="width: 50ch">the   flow-relative        flow-relative    flow-relative     flow-relative    flow-relative</p>
+
+<p style="width: 16ch">the flow-relative flow-relative flow-relative flow-relative flow-relative</p>
+<p style="width: 20ch">the flow-relative flow-relative flow-relative flow-relative flow-relative</p>
+<p style="width: 24ch">the flow-relative flow-relative flow-relative flow-relative flow-relative</p>
+<p style="width: 41ch">the flow-relative flow-relative flow-relative flow-relative flow-relative</p>
+<p style="width: 50ch">the flow-relative flow-relative flow-relative flow-relative flow-relative</p>
--- a/layout/reftests/text/reftest.list
+++ b/layout/reftests/text/reftest.list
@@ -316,16 +316,19 @@ pref(gfx.font_rendering.graphite.enabled
 == auto-hyphenation-uk-1.html auto-hyphenation-uk-1-ref.html
 
 == auto-hyphenation-transformed-1.html auto-hyphenation-transformed-1-ref.html
 
 == hyphenation-control-1.html hyphenation-control-1-ref.html
 == hyphenation-control-2.html hyphenation-control-2-ref.html
 == hyphenation-control-3.html hyphenation-control-3-ref.html
 == hyphenation-control-4.html hyphenation-control-4-ref.html
+fuzzy-if(winWidget,47,6) == hyphenation-control-5.html hyphenation-control-5-ref.html
+== hyphenation-control-6.html hyphenation-control-6-ref.html
+== hyphenation-control-7.html hyphenation-control-7-ref.html
 
 # osx-font-smoothing - with and without subpixel AA, only under OSX
 fails-if(!cocoaWidget) != osx-font-smoothing.html osx-font-smoothing-ref.html
 fails-if(!cocoaWidget) != osx-font-smoothing-2.html osx-font-smoothing-2-notref.html
 == osx-font-smoothing-2.html osx-font-smoothing-2-ref.html
 
 pref(layout.css.text-align-unsafe-value.enabled,true) fails == text-align-unsafe.html text-align-unsafe-ref.html # bug 1388949
 
--- a/netwerk/base/ProxyAutoConfig.cpp
+++ b/netwerk/base/ProxyAutoConfig.cpp
@@ -658,17 +658,17 @@ private:
     mGlobal = JS_NewGlobalObject(mContext, &sGlobalClass, nullptr,
                                  JS::DontFireOnNewGlobalHook, options);
     if (!mGlobal) {
       JS_ClearPendingException(mContext);
       return NS_ERROR_OUT_OF_MEMORY;
     }
     JS::Rooted<JSObject*> global(mContext, mGlobal);
 
-    JSAutoRealm ar(mContext, global);
+    JSAutoRealmAllowCCW ar(mContext, global);
     AutoPACErrorReporter aper(mContext);
     if (!JS::InitRealmStandardClasses(mContext)) {
       return NS_ERROR_FAILURE;
     }
     if (!JS_DefineFunctions(mContext, global, PACGlobalFunctions)) {
       return NS_ERROR_FAILURE;
     }
 
@@ -735,17 +735,17 @@ ProxyAutoConfig::SetupJS()
   NS_GetCurrentThread()->SetCanInvokeJS(true);
 
   mJSContext = JSContextWrapper::Create(mExtraHeapSize);
   if (!mJSContext)
     return NS_ERROR_FAILURE;
 
   JSContext* cx = mJSContext->Context();
   JSAutoRequest areq(cx);
-  JSAutoRealm ar(cx, mJSContext->Global());
+  JSAutoRealmAllowCCW ar(cx, mJSContext->Global());
   AutoPACErrorReporter aper(cx);
 
   // check if this is a data: uri so that we don't spam the js console with
   // huge meaningless strings. this is not on the main thread, so it can't
   // use nsIURI scheme methods
   bool isDataURI = nsDependentCSubstring(mPACURI, 0, 5).LowerCaseEqualsASCII("data:", 5);
 
   SetRunning(this);
@@ -795,17 +795,17 @@ ProxyAutoConfig::GetProxyForURI(const ns
   if (mJSNeedsSetup)
     SetupJS();
 
   if (!mJSContext || !mJSContext->IsOK())
     return NS_ERROR_NOT_AVAILABLE;
 
   JSContext *cx = mJSContext->Context();
   JSAutoRequest areq(cx);
-  JSAutoRealm ar(cx, mJSContext->Global());
+  JSAutoRealmAllowCCW ar(cx, mJSContext->Global());
   AutoPACErrorReporter aper(cx);
 
   // the sRunning flag keeps a new PAC file from being installed
   // while the event loop is spinning on a DNS function. Don't early return.
   SetRunning(this);
   mRunningHost = aTestHost;
 
   nsresult rv = NS_ERROR_FAILURE;
@@ -862,17 +862,17 @@ ProxyAutoConfig::GetProxyForURI(const ns
 }
 
 void
 ProxyAutoConfig::GC()
 {
   if (!mJSContext || !mJSContext->IsOK())
     return;
 
-  JSAutoRealm ar(mJSContext->Context(), mJSContext->Global());
+  JSAutoRealmAllowCCW ar(mJSContext->Context(), mJSContext->Global());
   JS_MaybeGC(mJSContext->Context());
 }
 
 ProxyAutoConfig::~ProxyAutoConfig()
 {
   MOZ_COUNT_DTOR(ProxyAutoConfig);
   MOZ_ASSERT(mShutdown, "Shutdown must be called before dtor.");
   NS_ASSERTION(!mJSContext,
--- a/testing/marionette/capabilities.js
+++ b/testing/marionette/capabilities.js
@@ -459,76 +459,65 @@ class Capabilities extends Map {
 
   // Matches capabilities as described by WebDriver.
   static match_(json = {}) {
     let matched = new Capabilities();
 
     for (let [k, v] of Object.entries(json)) {
       switch (k) {
         case "acceptInsecureCerts":
-          assert.boolean(v,
-              pprint`Expected ${k} to be a boolean, got ${v}`);
+          assert.boolean(v, pprint`Expected ${k} to be a boolean, got ${v}`);
           matched.set("acceptInsecureCerts", v);
           break;
 
         case "pageLoadStrategy":
-          if (v === null) {
-            matched.set("pageLoadStrategy", PageLoadStrategy.Normal);
-          } else {
-            assert.string(v,
-                pprint`Expected ${k} to be a string, got ${v}`);
+          assert.string(v, pprint`Expected ${k} to be a string, got ${v}`);
 
-            if (Object.values(PageLoadStrategy).includes(v)) {
-              matched.set("pageLoadStrategy", v);
-            } else {
-              throw new InvalidArgumentError(
-                  "Unknown page load strategy: " + v);
-            }
+          if (Object.values(PageLoadStrategy).includes(v)) {
+            matched.set("pageLoadStrategy", v);
+          } else {
+            throw new InvalidArgumentError("Unknown page load strategy: " + v);
           }
 
           break;
 
         case "proxy":
           let proxy = Proxy.fromJSON(v);
           matched.set("proxy", proxy);
           break;
 
         case "timeouts":
           let timeouts = Timeouts.fromJSON(v);
           matched.set("timeouts", timeouts);
           break;
 
         case "unhandledPromptBehavior":
-          assert.string(v,
-              pprint`Expected ${k} to be a string, got ${v}`);
+          assert.string(v, pprint`Expected ${k} to be a string, got ${v}`);
 
           if (Object.values(UnhandledPromptBehavior).includes(v)) {
             matched.set("unhandledPromptBehavior", v);
           } else {
             throw new InvalidArgumentError(
                 `Unknown unhandled prompt behavior: ${v}`);
           }
 
           break;
 
         case "moz:accessibilityChecks":
-          assert.boolean(v,
-              pprint`Expected ${k} to be a boolean, got ${v}`);
+          assert.boolean(v, pprint`Expected ${k} to be a boolean, got ${v}`);
           matched.set("moz:accessibilityChecks", v);
           break;
 
         case "moz:useNonSpecCompliantPointerOrigin":
-          assert.boolean(v,
-              pprint`Expected ${k} to be a boolean, got ${v}`);
+          assert.boolean(v, pprint`Expected ${k} to be a boolean, got ${v}`);
           matched.set("moz:useNonSpecCompliantPointerOrigin", v);
           break;
 
         case "moz:webdriverClick":
-          assert.boolean(v,
-              pprint`Expected ${k} to be a boolean, got ${v}`);
+          assert.boolean(v, pprint`Expected ${k} to be a boolean, got ${v}`);
           matched.set("moz:webdriverClick", v);
           break;
       }
     }
 
     return matched;
   }
 }
--- a/testing/marionette/harness/marionette_harness/tests/unit/test_capabilities.py
+++ b/testing/marionette/harness/marionette_harness/tests/unit/test_capabilities.py
@@ -138,22 +138,17 @@ class TestCapabilityMatching(MarionetteT
 
     def test_page_load_strategy(self):
         for strategy in ["none", "eager", "normal"]:
             print("valid strategy {}".format(strategy))
             self.delete_session()
             self.marionette.start_session({"pageLoadStrategy": strategy})
             self.assertEqual(self.marionette.session_capabilities["pageLoadStrategy"], strategy)
 
-        # A null value should be treatend as "normal"
-        self.delete_session()
-        self.marionette.start_session({"pageLoadStrategy": None})
-        self.assertEqual(self.marionette.session_capabilities["pageLoadStrategy"], "normal")
-
-        for value in ["", "EAGER", True, 42, {}, []]:
+        for value in ["", "EAGER", True, 42, {}, [], None]:
             print("invalid strategy {}".format(value))
             with self.assertRaisesRegexp(SessionNotCreatedException, "InvalidArgumentError"):
                 self.marionette.start_session({"pageLoadStrategy": value})
 
     def test_timeouts(self):
         timeouts = {u"implicit": 123, u"pageLoad": 456, u"script": 789}
         caps = {"timeouts": timeouts}
         self.marionette.start_session(caps)
--- a/testing/marionette/test/unit/test_capabilities.js
+++ b/testing/marionette/test/unit/test_capabilities.js
@@ -451,16 +451,17 @@ add_test(function test_Capabilities_from
   equal(false, caps.get("acceptInsecureCerts"));
   Assert.throws(() => fromJSON({acceptInsecureCerts: "foo"}), InvalidArgumentError);
 
   for (let strategy of Object.values(PageLoadStrategy)) {
     caps = fromJSON({pageLoadStrategy: strategy});
     equal(strategy, caps.get("pageLoadStrategy"));
   }
   Assert.throws(() => fromJSON({pageLoadStrategy: "foo"}), InvalidArgumentError);
+  Assert.throws(() => fromJSON({pageLoadStrategy: null}), InvalidArgumentError);
 
   let proxyConfig = {proxyType: "manual"};
   caps = fromJSON({proxy: proxyConfig});
   equal("manual", caps.get("proxy").proxyType);
 
   let timeoutsConfig = {implicit: 123};
   caps = fromJSON({timeouts: timeoutsConfig});
   equal(123, caps.get("timeouts").implicit);
--- a/toolkit/components/extensions/MatchPattern.cpp
+++ b/toolkit/components/extensions/MatchPattern.cpp
@@ -735,17 +735,17 @@ MatchGlob::Init(JSContext* aCx, const ns
 bool
 MatchGlob::Matches(const nsAString& aString) const
 {
   if (mRegExp) {
     AutoJSAPI jsapi;
     jsapi.Init();
     JSContext* cx = jsapi.cx();
 
-    JSAutoRealm ar(cx, mRegExp);
+    JSAutoRealmAllowCCW ar(cx, mRegExp);
 
     JS::RootedObject regexp(cx, mRegExp);
     JS::RootedValue result(cx);
 
     nsString input(aString);
 
     size_t index = 0;
     if (!JS_ExecuteRegExpNoStatics(cx, regexp, input.BeginWriting(), aString.Length(),
--- a/toolkit/components/mozintl/MozIntlHelper.cpp
+++ b/toolkit/components/mozintl/MozIntlHelper.cpp
@@ -25,17 +25,17 @@ AddFunctions(JSContext* cx, JS::Handle<J
     return NS_ERROR_INVALID_ARG;
   }
 
   JS::Rooted<JSObject*> realIntlObj(cx, js::CheckedUnwrap(&val.toObject()));
   if (!realIntlObj) {
     return NS_ERROR_INVALID_ARG;
   }
 
-  JSAutoRealm ar(cx, realIntlObj);
+  JSAutoRealmAllowCCW ar(cx, realIntlObj);
 
   if (!JS_DefineFunctions(cx, realIntlObj, funcs)) {
     return NS_ERROR_FAILURE;
   }
 
   return NS_OK;
 }
 
@@ -68,17 +68,17 @@ MozIntlHelper::AddDateTimeFormatConstruc
     return NS_ERROR_INVALID_ARG;
   }
 
   JS::Rooted<JSObject*> realIntlObj(cx, js::CheckedUnwrap(&val.toObject()));
   if (!realIntlObj) {
     return NS_ERROR_INVALID_ARG;
   }
 
-  JSAutoRealm ar(cx, realIntlObj);
+  JSAutoRealmAllowCCW ar(cx, realIntlObj);
 
   if (!js::AddMozDateTimeFormatConstructor(cx, realIntlObj)) {
     return NS_ERROR_FAILURE;
   }
 
   return NS_OK;
 }
 
@@ -89,17 +89,17 @@ MozIntlHelper::AddRelativeTimeFormatCons
     return NS_ERROR_INVALID_ARG;
   }
 
   JS::Rooted<JSObject*> realIntlObj(cx, js::CheckedUnwrap(&val.toObject()));
   if (!realIntlObj) {
     return NS_ERROR_INVALID_ARG;
   }
 
-  JSAutoRealm ar(cx, realIntlObj);
+  JSAutoRealmAllowCCW ar(cx, realIntlObj);
 
   if (!js::AddRelativeTimeFormatConstructor(cx, realIntlObj)) {
     return NS_ERROR_FAILURE;
   }
 
   return NS_OK;
 }
 
--- a/toolkit/recordreplay/ipc/JSControl.cpp
+++ b/toolkit/recordreplay/ipc/JSControl.cpp
@@ -138,17 +138,17 @@ Middleman_RegisterReplayDebugger(JSConte
   return true;
 }
 
 static bool
 InvalidateReplayDebuggersAfterUnpause(JSContext* aCx)
 {
   RootedValue rval(aCx);
   for (auto root : gReplayDebuggers) {
-    JSAutoRealm ac(aCx, *root);
+    JSAutoRealmAllowCCW ac(aCx, *root);
     if (!JS_CallFunctionName(aCx, *root, "invalidateAfterUnpause",
                              HandleValueArray::empty(), &rval))
     {
       return false;
     }
   }
   return true;
 }
@@ -254,17 +254,17 @@ Middleman_SetBreakpoint(JSContext* aCx, 
 }
 
 bool
 HitBreakpoint(JSContext* aCx, size_t aId)
 {
   InstalledBreakpoint* breakpoint = gBreakpoints[aId];
   MOZ_RELEASE_ASSERT(breakpoint);
 
-  JSAutoRealm ac(aCx, breakpoint->mHandler);
+  JSAutoRealmAllowCCW ac(aCx, breakpoint->mHandler);
 
   RootedValue handlerValue(aCx, ObjectValue(*breakpoint->mHandler));
   RootedValue rval(aCx);
   return JS_CallFunctionValue(aCx, nullptr, handlerValue,
                               HandleValueArray::empty(), &rval)
       // The replaying process will resume after this hook returns, if it
       // hasn't already been explicitly resumed.
       && InvalidateReplayDebuggersAfterUnpause(aCx);
@@ -320,17 +320,17 @@ SetupDevtoolsSandbox()
   options.invisibleToDebugger = true;
   RootedValue v(cx);
   nsresult rv = CreateSandboxObject(cx, &v, nsXPConnect::SystemPrincipal(), options);
   MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
 
   gDevtoolsSandbox = new PersistentRootedObject(cx);
   *gDevtoolsSandbox = ::js::UncheckedUnwrap(&v.toObject());
 
-  JSAutoRealm ac(cx, *gDevtoolsSandbox);
+  JSAutoRealmAllowCCW ac(cx, *gDevtoolsSandbox);
 
   ErrorResult er;
   dom::GlobalObject global(cx, *gDevtoolsSandbox);
   RootedObject obj(cx);
   dom::ChromeUtils::Import(global, NS_LITERAL_STRING(ReplayScriptURL),
                            dom::Optional<HandleObject>(), &obj, er);
   MOZ_RELEASE_ASSERT(!er.Failed());
 }
@@ -347,17 +347,17 @@ RecordReplayInterface_IsInternalScript(c
 
 #undef ReplayScriptURL
 
 void
 ProcessRequest(const char16_t* aRequest, size_t aRequestLength, CharBuffer* aResponse)
 {
   AutoDisallowThreadEvents disallow;
   AutoSafeJSContext cx;
-  JSAutoRealm ac(cx, *gDevtoolsSandbox);
+  JSAutoRealmAllowCCW ac(cx, *gDevtoolsSandbox);
 
   RootedValue requestValue(cx);
   if (!JS_ParseJSON(cx, aRequest, aRequestLength, &requestValue)) {
     MOZ_CRASH("ProcessRequest: ParseJSON failed");
   }
 
   RootedValue responseValue(cx);
   if (!JS_CallFunctionName(cx, *gDevtoolsSandbox, "ProcessRequest",
@@ -380,17 +380,17 @@ ProcessRequest(const char16_t* aRequest,
   }
 }
 
 void
 EnsurePositionHandler(const BreakpointPosition& aPosition)
 {
   AutoDisallowThreadEvents disallow;
   AutoSafeJSContext cx;
-  JSAutoRealm ac(cx, *gDevtoolsSandbox);
+  JSAutoRealmAllowCCW ac(cx, *gDevtoolsSandbox);
 
   RootedObject obj(cx, aPosition.Encode(cx));
   if (!obj) {
     MOZ_CRASH("EnsurePositionHandler");
   }
 
   RootedValue objValue(cx, ObjectValue(*obj));
   RootedValue rval(cx);
@@ -400,45 +400,45 @@ EnsurePositionHandler(const BreakpointPo
   }
 }
 
 void
 ClearPositionHandlers()
 {
   AutoDisallowThreadEvents disallow;
   AutoSafeJSContext cx;
-  JSAutoRealm ac(cx, *gDevtoolsSandbox);
+  JSAutoRealmAllowCCW ac(cx, *gDevtoolsSandbox);
 
   RootedValue rval(cx);
   if (!JS_CallFunctionName(cx, *gDevtoolsSandbox, "ClearPositionHandlers",
                            HandleValueArray::empty(), &rval)) {
     MOZ_CRASH("ClearPositionHandlers");
   }
 }
 
 void
 ClearPausedState()
 {
   AutoDisallowThreadEvents disallow;
   AutoSafeJSContext cx;
-  JSAutoRealm ac(cx, *gDevtoolsSandbox);
+  JSAutoRealmAllowCCW ac(cx, *gDevtoolsSandbox);
 
   RootedValue rval(cx);
   if (!JS_CallFunctionName(cx, *gDevtoolsSandbox, "ClearPausedState",
                            HandleValueArray::empty(), &rval)) {
     MOZ_CRASH("ClearPausedState");
   }
 }
 
 Maybe<BreakpointPosition>
 GetEntryPosition(const BreakpointPosition& aPosition)
 {
   AutoDisallowThreadEvents disallow;
   AutoSafeJSContext cx;
-  JSAutoRealm ac(cx, *gDevtoolsSandbox);
+  JSAutoRealmAllowCCW ac(cx, *gDevtoolsSandbox);
 
   RootedObject positionObject(cx, aPosition.Encode(cx));
   if (!positionObject) {
     MOZ_CRASH("GetEntryPosition");
   }
 
   RootedValue rval(cx);
   RootedValue positionValue(cx, ObjectValue(*positionObject));
--- a/toolkit/recordreplay/ipc/ParentGraphics.cpp
+++ b/toolkit/recordreplay/ipc/ParentGraphics.cpp
@@ -91,17 +91,17 @@ InitGraphicsSandbox()
   options.invisibleToDebugger = true;
   RootedValue v(cx);
   nsresult rv = CreateSandboxObject(cx, &v, nsXPConnect::SystemPrincipal(), options);
   MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
 
   gGraphicsSandbox = new JS::PersistentRootedObject(cx);
   *gGraphicsSandbox = ::js::UncheckedUnwrap(&v.toObject());
 
-  JSAutoRealm ac(cx, *gGraphicsSandbox);
+  JSAutoRealmAllowCCW ac(cx, *gGraphicsSandbox);
 
   ErrorResult er;
   dom::GlobalObject global(cx, *gGraphicsSandbox);
   RootedObject obj(cx);
   dom::ChromeUtils::Import(global, NS_LITERAL_STRING("resource://devtools/server/actors/replay/graphics.js"),
                            dom::Optional<HandleObject>(), &obj, er);
   MOZ_RELEASE_ASSERT(!er.Failed());
 }
@@ -121,17 +121,17 @@ UpdateGraphicsInUIProcess(const PaintMes
   }
 
   // Make sure there is a sandbox which is running the graphics JS module.
   if (!gGraphicsSandbox) {
     InitGraphicsSandbox();
   }
 
   AutoSafeJSContext cx;
-  JSAutoRealm ac(cx, *gGraphicsSandbox);
+  JSAutoRealmAllowCCW ac(cx, *gGraphicsSandbox);
 
   size_t width = gLastPaint.ref().mWidth;
   size_t height = gLastPaint.ref().mHeight;
   size_t stride = layers::ImageDataSerializer::ComputeRGBStride(gSurfaceFormat, width);
 
   // Make sure the width and height are appropriately sized.
   CheckedInt<size_t> scaledWidth = CheckedInt<size_t>(width) * 4;
   CheckedInt<size_t> scaledHeight = CheckedInt<size_t>(height) * stride;