Bug 1478955 part 1 - Rename JSAutoRealm to JSAutoRealmAllowCCW. r=luke
authorJan de Mooij <jdemooij@mozilla.com>
Sat, 28 Jul 2018 12:12:26 +0200
changeset 428860 1494e906ad52413008a722bf5e9ab533d1821f57
parent 428859 2961b5e8758b629b814caf83ab3c4a8d82343873
child 428861 4185529cca83e2785603ac94897f46138da3d20c
push id34348
push userbtara@mozilla.com
push dateSat, 28 Jul 2018 21:49:02 +0000
treeherdermozilla-central@71922e0cd9e1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersluke
bugs1478955
milestone63.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1478955 part 1 - Rename JSAutoRealm to JSAutoRealmAllowCCW. r=luke
devtools/shared/heapsnapshot/tests/gtest/DevTools.h
devtools/shared/heapsnapshot/tests/gtest/DoesCrossCompartmentBoundaries.cpp
devtools/shared/heapsnapshot/tests/gtest/DoesntCrossCompartmentBoundaries.cpp
dom/base/ChromeUtils.cpp
dom/base/Element.cpp
dom/base/IntlUtils.cpp
dom/base/PostMessageEvent.cpp
dom/base/StructuredCloneBlob.cpp
dom/base/nsContentPermissionHelper.cpp
dom/base/nsContentUtils.cpp
dom/base/nsDocument.cpp
dom/base/nsFrameLoader.cpp
dom/base/nsFrameMessageManager.cpp
dom/base/nsGlobalWindowInner.cpp
dom/base/nsGlobalWindowOuter.cpp
dom/base/nsINode.cpp
dom/base/nsJSEnvironment.cpp
dom/base/nsJSUtils.h
dom/base/nsNodeUtils.cpp
dom/base/nsObjectLoadingContent.cpp
dom/bindings/BindingUtils.cpp
dom/bindings/BindingUtils.h
dom/bindings/CallbackObject.cpp
dom/bindings/CallbackObject.h
dom/bindings/Codegen.py
dom/bindings/SimpleGlobalObject.cpp
dom/bindings/StructuredClone.cpp
dom/bindings/TypedArray.h
dom/bindings/WebIDLGlobalNameHash.cpp
dom/browser-element/BrowserElementParent.cpp
dom/canvas/WebGLContextUtils.h
dom/clients/manager/ClientOpenWindowUtils.cpp
dom/console/Console.cpp
dom/console/ConsoleUtils.cpp
dom/encoding/TextEncoder.cpp
dom/events/EventListenerManager.cpp
dom/events/EventListenerService.cpp
dom/events/EventListenerService.h
dom/html/nsHTMLDocument.cpp
dom/indexedDB/IDBObjectStore.cpp
dom/indexedDB/IDBRequest.cpp
dom/ipc/ContentChild.cpp
dom/media/webaudio/AudioContext.cpp
dom/network/TCPSocket.cpp
dom/plugins/base/nsJSNPRuntime.cpp
dom/promise/Promise.cpp
dom/promise/PromiseDebugging.cpp
dom/script/ScriptSettings.cpp
dom/workers/WorkerDebugger.cpp
dom/workers/WorkerPrivate.cpp
dom/workers/WorkerRunnable.cpp
dom/workers/WorkerScope.cpp
dom/worklet/Worklet.cpp
dom/xbl/nsBindingManager.cpp
dom/xbl/nsXBLBinding.cpp
dom/xbl/nsXBLProtoImpl.cpp
dom/xbl/nsXBLProtoImplField.cpp
dom/xbl/nsXBLProtoImplMethod.cpp
dom/xbl/nsXBLProtoImplProperty.cpp
dom/xbl/nsXBLPrototypeHandler.cpp
dom/xul/XULDocument.cpp
extensions/pref/autoconfig/src/nsJSConfigTriggers.cpp
ipc/testshell/XPCShellEnvironment.cpp
js/ductwork/debugger/JSDebugger.cpp
js/ipc/JavaScriptLogging.h
js/ipc/JavaScriptParent.cpp
js/ipc/JavaScriptShared.cpp
js/ipc/WrapperOwner.cpp
js/rust/build.rs
js/rust/src/ac.rs
js/rust/src/rust.rs
js/src/builtin/DataViewObject.cpp
js/src/builtin/MapObject.cpp
js/src/devtools/rootAnalysis/annotations.js
js/src/fuzz-tests/tests.cpp
js/src/gdb/gdb-tests.cpp
js/src/jsapi-tests/testBug604087.cpp
js/src/jsapi-tests/testCallNonGenericMethodOnProxy.cpp
js/src/jsapi-tests/testChromeBuffer.cpp
js/src/jsapi-tests/testCloneScript.cpp
js/src/jsapi-tests/testDebugger.cpp
js/src/jsapi-tests/testErrorLineOfContext.cpp
js/src/jsapi-tests/testFreshGlobalEvalRedefinition.cpp
js/src/jsapi-tests/testGCGrayMarking.cpp
js/src/jsapi-tests/testGCMarking.cpp
js/src/jsapi-tests/testMutedErrors.cpp
js/src/jsapi-tests/testPreserveJitCode.cpp
js/src/jsapi-tests/testScriptObject.cpp
js/src/jsapi-tests/testStructuredClone.cpp
js/src/jsapi-tests/testUbiNode.cpp
js/src/jsapi-tests/testWeakMap.cpp
js/src/jsapi-tests/tests.cpp
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jsfriendapi.cpp
js/src/shell/js.cpp
js/src/vm/Debugger.cpp
js/src/vm/JSObject.cpp
js/src/vm/JSScript.cpp
js/src/vm/SelfHosting.cpp
js/src/vm/StructuredClone.cpp
js/src/vm/TypedArrayObject.cpp
js/xpconnect/loader/ChromeScriptLoader.cpp
js/xpconnect/loader/ScriptPreloader.cpp
js/xpconnect/loader/mozJSComponentLoader.cpp
js/xpconnect/loader/mozJSComponentLoader.h
js/xpconnect/loader/mozJSSubScriptLoader.cpp
js/xpconnect/src/ExportHelpers.cpp
js/xpconnect/src/Sandbox.cpp
js/xpconnect/src/XPCComponents.cpp
js/xpconnect/src/XPCConvert.cpp
js/xpconnect/src/XPCShellImpl.cpp
js/xpconnect/src/XPCWrappedJSClass.cpp
js/xpconnect/src/XPCWrappedNative.cpp
js/xpconnect/src/XPCWrappedNativeJSOps.cpp
js/xpconnect/src/XPCWrappedNativeScope.cpp
js/xpconnect/src/XPCWrapper.cpp
js/xpconnect/src/nsXPConnect.cpp
js/xpconnect/src/xpcprivate.h
js/xpconnect/wrappers/WrapperFactory.cpp
js/xpconnect/wrappers/XrayWrapper.cpp
js/xpconnect/wrappers/XrayWrapper.h
netwerk/base/ProxyAutoConfig.cpp
toolkit/components/extensions/MatchPattern.cpp
toolkit/components/mozintl/MozIntlHelper.cpp
toolkit/recordreplay/ipc/JSControl.cpp
toolkit/recordreplay/ipc/ParentGraphics.cpp
--- 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
@@ -3764,17 +3764,17 @@ class CGWrapWithCacheMethod(CGAbstractMe
             aReflector.set(aCache->GetWrapper());
             if (aReflector) {
             #ifdef DEBUG
               AssertReflectorHasGivenProto(aCx, aReflector, aGivenProto);
             #endif // DEBUG
               return true;
             }
 
-            JSAutoRealm ar(aCx, global);
+            JSAutoRealmAllowCCW ar(aCx, global);
             $*{declareProto}
 
             $*{createObject}
 
             aCache->SetWrapper(aReflector);
             $*{unforgeable}
             $*{slots}
             $*{setImmutablePrototype}
@@ -3928,17 +3928,17 @@ class CGWrapGlobalMethod(CGAbstractMetho
                                              aPrincipal,
                                              aInitStandardClasses,
                                              aReflector)) {
               $*{failureCode}
             }
 
             // aReflector is a new global, so has a new realm.  Enter it
             // before doing anything with it.
-            JSAutoRealm ar(aCx, aReflector);
+            JSAutoRealmAllowCCW ar(aCx, aReflector);
 
             if (!DefineProperties(aCx, aReflector, ${properties}, ${chromeProperties})) {
               $*{failureCode}
             }
             $*{unforgeable}
 
             $*{slots}
 
@@ -4013,17 +4013,17 @@ class CGClearCachedValueMethod(CGAbstrac
             noopRetval = " true"
             saveMember = (
                 "JS::Rooted<JS::Value> oldValue(aCx, js::GetReservedSlot(obj, %s));\n" %
                 slotIndex)
             regetMember = fill(
                 """
                 JS::Rooted<JS::Value> temp(aCx);
                 JSJitGetterCallArgs args(&temp);
-                JSAutoRealm ar(aCx, obj);
+                JSAutoRealmAllowCCW ar(aCx, obj);
                 if (!get_${name}(aCx, obj, aObject, args)) {
                   js::SetReservedSlot(obj, ${slotIndex}, oldValue);
                   return false;
                 }
                 return true;
                 """,
                 name=self.member.identifier.name,
                 slotIndex=slotIndex)
@@ -5413,17 +5413,17 @@ def getJSToNativeConversionInfo(type, de
 
         templateBody = fill(
             """
             { // Scope for our GlobalObject, FastErrorResult, JSAutoRealm,
               // etc.
 
               JS::Rooted<JSObject*> globalObj(cx);
               $*{getPromiseGlobal}
-              JSAutoRealm ar(cx, globalObj);
+              JSAutoRealmAllowCCW ar(cx, globalObj);
               GlobalObject promiseGlobal(cx, globalObj);
               if (promiseGlobal.Failed()) {
                 $*{exceptionCode}
               }
 
               JS::Rooted<JS::Value> valueToResolve(cx, $${val});
               if (!JS_WrapValue(cx, &valueToResolve)) {
                 $*{exceptionCode}
@@ -7656,17 +7656,17 @@ class CGPerSignatureCall(CGThing):
                 # object's compartment and then wrap up all of our arguments into
                 # that compartment as needed.  This is all happening after we've
                 # already done the conversions from JS values to WebIDL (C++)
                 # values, so we only need to worry about cases where there are 'any'
                 # or 'object' types, or other things that we represent as actual
                 # JSAPI types, present.  Effectively, we're emulating a
                 # CrossCompartmentWrapper, but working with the C++ types, not the
                 # original list of JS::Values.
-                cgThings.append(CGGeneric("Maybe<JSAutoRealm> ar;\n"))
+                cgThings.append(CGGeneric("Maybe<JSAutoRealmAllowCCW> ar;\n"))
                 xraySteps.append(CGGeneric("ar.emplace(cx, obj);\n"))
                 xraySteps.append(CGGeneric(dedent(
                     """
                     if (!JS_WrapObject(cx, &desiredProto)) {
                       return false;
                     }
                     """)))
                 xraySteps.extend(
@@ -7867,24 +7867,24 @@ 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);
+                  JSAutoRealmAllowCCW ar(cx, slotStorage);
                   $*{slotStorageSteps}
                 }
                 // And now make sure args.rval() is in the caller realm.
                 return ${maybeWrap}(cx, args.rval());
                 """,
                 conversionScope=conversionScope,
                 wrapCode=wrapCode,
                 postConversionSteps=postConversionSteps,
@@ -10861,17 +10861,17 @@ class CGResolveOwnPropertyViaResolve(CGA
         return CGGeneric(dedent("""
             {
               // Since we're dealing with an Xray, do the resolve on the
               // underlying object first.  That gives it a chance to
               // define properties on the actual object as needed, and
               // then use the fact that it created the objects as a flag
               // to avoid re-resolving the properties if someone deletes
               // them.
-              JSAutoRealm ar(cx, obj);
+              JSAutoRealmAllowCCW ar(cx, obj);
               JS_MarkCrossZoneId(cx, id);
               JS::Rooted<JS::PropertyDescriptor> objDesc(cx);
               if (!self->DoResolve(cx, obj, id, &objDesc)) {
                 return false;
               }
               // If desc.value() is undefined, then the DoResolve call
               // has already defined the property on the object.  Don't
               // try to also define it.
@@ -11556,17 +11556,17 @@ class CGDeleteNamedProperty(CGAbstractSt
                                         "bool", args)
 
     def definition_body(self):
         return fill(
             """
             MOZ_ASSERT(xpc::WrapperFactory::IsXrayWrapper(xray));
             MOZ_ASSERT(js::IsProxy(proxy));
             MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy));
-            JSAutoRealm ar(cx, proxy);
+            JSAutoRealmAllowCCW ar(cx, proxy);
             bool deleteSucceeded = false;
             bool found = false;
             $*{namedBody}
             if (!found || deleteSucceeded) {
               return opresult.succeed();
             }
             return opresult.failCantDelete();
             """,
@@ -12751,17 +12751,17 @@ class CGDictionary(CGThing):
                 AutoJSAPI jsapi;
                 jsapi.Init();
                 JSContext *cx = jsapi.cx();
                 // It's safe to use UnprivilegedJunkScopeOrWorkerGlobal here
                 // because we'll only be creating objects, in ways that have no
                 // side-effects, followed by a call to JS::ToJSONMaybeSafely,
                 // which likewise guarantees no side-effects for the sorts of
                 // things we will pass it.
-                JSAutoRealm ar(cx, UnprivilegedJunkScopeOrWorkerGlobal());
+                JSAutoRealmAllowCCW ar(cx, UnprivilegedJunkScopeOrWorkerGlobal());
                 JS::Rooted<JS::Value> val(cx);
                 if (!ToObjectInternal(cx, &val)) {
                   return false;
                 }
                 JS::Rooted<JSObject*> obj(cx, &val.toObject());
                 return StringifyToJSON(cx, obj, aJSON);
             """), const=True)
 
@@ -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;
             """,
@@ -16649,27 +16649,27 @@ class CGMaplikeOrSetlikeHelperFunctionGe
             """
             MOZ_ASSERT(self);
             AutoJSAPI jsapi;
             jsapi.Init();
             JSContext* cx = jsapi.cx();
             // It's safe to use UnprivilegedJunkScopeOrWorkerGlobal here because
             // all we want is to wrap into _some_ scope and then unwrap to find
             // the reflector, and wrapping has no side-effects.
-            JSAutoRealm tempRealm(cx, UnprivilegedJunkScopeOrWorkerGlobal());
+            JSAutoRealmAllowCCW tempRealm(cx, UnprivilegedJunkScopeOrWorkerGlobal());
             JS::Rooted<JS::Value> v(cx);
             if(!ToJSValue(cx, self, &v)) {
               aRv.Throw(NS_ERROR_UNEXPECTED);
               return%s;
             }
             // This is a reflector, but due to trying to name things
             // similarly across method generators, it's called obj here.
             JS::Rooted<JSObject*> obj(cx);
             obj = js::UncheckedUnwrap(&v.toObject(), /* stopAtWindowProxy = */ false);
-            JSAutoRealm reflectorRealm(cx, obj);
+            JSAutoRealmAllowCCW reflectorRealm(cx, obj);
             """ % self.getDefaultRetval())
 
     def getArgs(self, returnType, argList):
         # We don't need the context or the value. We'll generate those instead.
         args = CGNativeMember.getArgs(self, returnType, argList)
         # Prepend a pointer to the binding object onto the arguments
         return [Argument(self.descriptorProvider.nativeType + "*", "self")] + args
 
--- 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/testBug604087.cpp
+++ b/js/src/jsapi-tests/testBug604087.cpp
@@ -14,17 +14,17 @@
 
 const js::Class OuterWrapperClass = PROXY_CLASS_DEF(
     "Proxy",
     JSCLASS_HAS_RESERVED_SLOTS(1) /* additional class flags */);
 
 static JSObject*
 wrap(JSContext* cx, JS::HandleObject toWrap, JS::HandleObject target)
 {
-    JSAutoRealm ar(cx, target);
+    JSAutoRealmAllowCCW ar(cx, target);
     JS::RootedObject wrapper(cx, toWrap);
     if (!JS_WrapObject(cx, &wrapper))
         return nullptr;
     return wrapper;
 }
 
 static void
 PreWrap(JSContext* cx, JS::HandleObject scope, JS::HandleObject obj,
@@ -75,17 +75,17 @@ BEGIN_TEST(testBug604087)
 
     JS::RootedObject c4wrapper(cx, wrap(cx, outerObj, compartment4));
     CHECK(c4wrapper);
     c4wrapper->as<js::ProxyObject>().setReservedSlot(0, js::Int32Value(4));
     compartment4 = c4wrapper = nullptr;
 
     JS::RootedObject next(cx);
     {
-        JSAutoRealm ar(cx, compartment2);
+        JSAutoRealmAllowCCW ar(cx, compartment2);
         next = js::Wrapper::New(cx, compartment2, &js::Wrapper::singleton, options);
         CHECK(next);
     }
 
     JS_SetWrapObjectCallbacks(cx, &WrapObjectCallbacks);
     CHECK(JS_TransplantObject(cx, outerObj, next));
     return true;
 }
--- a/js/src/jsapi-tests/testCallNonGenericMethodOnProxy.cpp
+++ b/js/src/jsapi-tests/testCallNonGenericMethodOnProxy.cpp
@@ -58,17 +58,17 @@ BEGIN_TEST(test_CallNonGenericMethodOnPr
   // Now create the second global object and compartment...
   {
     JS::RealmOptions options;
     JS::RootedObject globalB(cx, JS_NewGlobalObject(cx, getGlobalClass(), nullptr,
 						    JS::FireOnNewGlobalHook, options));
     CHECK(globalB);
 
     // ...and enter it.
-    JSAutoRealm enter(cx, globalB);
+    JSAutoRealmAllowCCW enter(cx, globalB);
     JS::RootedObject customB(cx, JS_NewObject(cx, &CustomClass));
     CHECK(customB);
     JS_SetReservedSlot(customB, CUSTOM_SLOT, Int32Value(42));
 
     JS::RootedFunction customMethodB(cx, JS_NewFunction(cx, CustomMethod, 0, 0,
 							"customMethodB"));
     CHECK(customMethodB);
 
--- a/js/src/jsapi-tests/testChromeBuffer.cpp
+++ b/js/src/jsapi-tests/testChromeBuffer.cpp
@@ -33,17 +33,17 @@ static JS::PersistentRootedObject truste
 
 static bool
 CallTrusted(JSContext* cx, unsigned argc, JS::Value* vp)
 {
     JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
 
     bool ok = false;
     {
-        JSAutoRealm ar(cx, trusted_glob);
+        JSAutoRealmAllowCCW ar(cx, trusted_glob);
         JS::RootedValue funVal(cx, JS::ObjectValue(*trusted_fun));
         ok = JS_CallFunctionValue(cx, nullptr, funVal, JS::HandleValueArray::empty(), args.rval());
     }
     return ok;
 }
 
 BEGIN_TEST(testChromeBuffer)
 {
@@ -61,17 +61,17 @@ BEGIN_TEST(testChromeBuffer)
      * compiled with "trusted principals" can run using reserved trusted-only
      * buffer space.
      */
     {
         // Disable the JIT because if we don't this test fails.  See bug 1160414.
         JS::ContextOptions oldOptions = JS::ContextOptionsRef(cx);
         JS::ContextOptionsRef(cx).setIon(false).setBaseline(false);
         {
-            JSAutoRealm ar(cx, trusted_glob);
+            JSAutoRealmAllowCCW ar(cx, trusted_glob);
             const char* paramName = "x";
             const char* bytes = "return x ? 1 + trusted(x-1) : 0";
             JS::CompileOptions options(cx);
             options.setFileAndLine("", 0);
             JS::AutoObjectVector emptyScopeChain(cx);
             CHECK(JS::CompileFunction(cx, emptyScopeChain, options, "trusted",
                                       1, &paramName, bytes, strlen(bytes), &fun));
             CHECK(JS_DefineProperty(cx, trusted_glob, "trusted", fun, JSPROP_ENUMERATE));
@@ -105,17 +105,17 @@ BEGIN_TEST(testChromeBuffer)
     }
 
     /*
      * Check that content called from chrome in the reserved-buffer space
      * immediately ooms.
      */
     {
         {
-            JSAutoRealm ar(cx, trusted_glob);
+            JSAutoRealmAllowCCW ar(cx, trusted_glob);
             const char* paramName = "untrusted";
             const char* bytes = "try {                                  "
                                 "  untrusted();                         "
                                 "} catch (e) {                          "
                                 "  /*                                   "
                                 "   * Careful!  We must not reenter JS  "
                                 "   * that might try to push a frame.   "
                                 "   */                                  "
@@ -151,17 +151,17 @@ BEGIN_TEST(testChromeBuffer)
         CHECK(JS_CallFunction(cx, nullptr, fun, JS::HandleValueArray(v), &rval));
         bool match;
         CHECK(JS_StringEqualsAscii(cx, rval.toString(), "From trusted: InternalError: too much recursion", &match));
         CHECK(match);
     }
 
     {
         {
-            JSAutoRealm ar(cx, trusted_glob);
+            JSAutoRealmAllowCCW ar(cx, trusted_glob);
             const char* bytes = "return 42";
             JS::CompileOptions options(cx);
             options.setFileAndLine("", 0);
             JS::AutoObjectVector emptyScopeChain(cx);
             CHECK(JS::CompileFunction(cx, emptyScopeChain, options, "trusted",
                                       0, nullptr, bytes, strlen(bytes), &fun));
             CHECK(JS_DefineProperty(cx, trusted_glob, "trusted", fun, JSPROP_ENUMERATE));
             trusted_fun = JS_GetFunctionObject(fun);
--- a/js/src/jsapi-tests/testCloneScript.cpp
+++ b/js/src/jsapi-tests/testCloneScript.cpp
@@ -26,29 +26,29 @@ BEGIN_TEST(test_cloneScript)
         "    ++i;\n"
         "}\n"
         "(sum);\n";
 
     JS::RootedObject obj(cx);
 
     // compile for A
     {
-        JSAutoRealm a(cx, A);
+        JSAutoRealmAllowCCW a(cx, A);
         JS::RootedFunction fun(cx);
         JS::CompileOptions options(cx);
         options.setFileAndLine(__FILE__, 1);
         JS::AutoObjectVector emptyScopeChain(cx);
         CHECK(JS::CompileFunction(cx, emptyScopeChain, options, "f", 0, nullptr,
                                   source, strlen(source), &fun));
         CHECK(obj = JS_GetFunctionObject(fun));
     }
 
     // clone into B
     {
-        JSAutoRealm b(cx, B);
+        JSAutoRealmAllowCCW b(cx, B);
         CHECK(JS::CloneFunctionObject(cx, obj));
     }
 
     return true;
 }
 END_TEST(test_cloneScript)
 
 struct Principals final : public JSPrincipals
@@ -107,17 +107,17 @@ BEGIN_TEST(test_cloneScriptWithPrincipal
 
     const char* argnames[] = { "arg" };
     const char* source = "return function() { return arg; }";
 
     JS::RootedObject obj(cx);
 
     // Compile in A
     {
-        JSAutoRealm a(cx, A);
+        JSAutoRealmAllowCCW a(cx, A);
         JS::CompileOptions options(cx);
         options.setFileAndLine(__FILE__, 1);
         JS::RootedFunction fun(cx);
         JS::AutoObjectVector emptyScopeChain(cx);
         JS::CompileFunction(cx, emptyScopeChain, options, "f",
                            mozilla::ArrayLength(argnames), argnames, source,
                            strlen(source), &fun);
         CHECK(fun);
@@ -126,17 +126,17 @@ BEGIN_TEST(test_cloneScriptWithPrincipal
         CHECK(script = JS_GetFunctionScript(cx, fun));
 
         CHECK(JS_GetScriptPrincipals(script) == principalsA);
         CHECK(obj = JS_GetFunctionObject(fun));
     }
 
     // Clone into B
     {
-        JSAutoRealm b(cx, B);
+        JSAutoRealmAllowCCW b(cx, B);
         JS::RootedObject cloned(cx);
         CHECK(cloned = JS::CloneFunctionObject(cx, obj));
 
         JS::RootedFunction fun(cx);
         JS::RootedValue clonedValue(cx, JS::ObjectValue(*cloned));
         CHECK(fun = JS_ValueToFunction(cx, clonedValue));
 
         JSScript* script;
--- 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);
+        JSAutoRealmAllowCCW ae(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));
 
@@ -43,17 +43,17 @@ BEGIN_TEST(testDebugger_newScriptHook)
     return testIndirectEval(g, "Math.abs(0)");
 }
 
 bool testIndirectEval(JS::HandleObject scope, const char* code)
 {
     EXEC("hits = 0;");
 
     {
-        JSAutoRealm ae(cx, scope);
+        JSAutoRealmAllowCCW ae(cx, scope);
         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));
     }
 
     JS::RootedValue hitsv(cx);
--- a/js/src/jsapi-tests/testErrorLineOfContext.cpp
+++ b/js/src/jsapi-tests/testErrorLineOfContext.cpp
@@ -33,17 +33,17 @@ BEGIN_TEST(testErrorLineOfContext)
 bool
 eval(const char16_t* chars, size_t len, JS::MutableHandleValue rval)
 {
     JS::RealmOptions globalOptions;
     JS::RootedObject global(cx, JS_NewGlobalObject(cx, getGlobalClass(), nullptr,
 						   JS::FireOnNewGlobalHook, globalOptions));
     CHECK(global);
 
-    JSAutoRealm ar(cx, global);
+    JSAutoRealmAllowCCW ar(cx, global);
     JS::CompileOptions options(cx);
     return JS::Evaluate(cx, options, chars, len, rval);
 }
 
 template<size_t N>
 bool
 testLineOfContextHasNoLineTerminator(const char16_t (&chars)[N], char16_t expectedLast)
 {
--- a/js/src/jsapi-tests/testFreshGlobalEvalRedefinition.cpp
+++ b/js/src/jsapi-tests/testFreshGlobalEvalRedefinition.cpp
@@ -28,17 +28,17 @@ BEGIN_TEST(testRedefineGlobalEval)
     };
 
     /* Create the global object. */
     JS::RealmOptions options;
     JS::Rooted<JSObject*> g(cx, JS_NewGlobalObject(cx, &cls, nullptr, JS::FireOnNewGlobalHook, options));
     if (!g)
         return false;
 
-    JSAutoRealm ar(cx, g);
+    JSAutoRealmAllowCCW ar(cx, g);
     JS::Rooted<JS::Value> v(cx);
     CHECK(JS_GetProperty(cx, g, "Object", &v));
 
     static const char data[] = "Object.defineProperty(this, 'eval', { configurable: false });";
     JS::CompileOptions opts(cx);
     CHECK(JS::Evaluate(cx, opts.setFileAndLine(__FILE__, __LINE__),
                        data, mozilla::ArrayLength(data) - 1, &v));
 
--- a/js/src/jsapi-tests/testGCGrayMarking.cpp
+++ b/js/src/jsapi-tests/testGCGrayMarking.cpp
@@ -51,17 +51,17 @@ BEGIN_TEST(testGCGrayMarking)
 {
     AutoNoAnalysisForTest disableAnalysis;
     AutoDisableCompactingGC disableCompactingGC(cx);
 #ifdef JS_GC_ZEAL
     AutoLeaveZeal nozeal(cx);
 #endif /* JS_GC_ZEAL */
 
     CHECK(InitGlobals());
-    JSAutoRealm ar(cx, global1);
+    JSAutoRealmAllowCCW ar(cx, global1);
 
     InitGrayRootTracer();
 
     bool ok =
         TestMarking() &&
         TestWeakMaps() &&
         TestUnassociatedWeakMaps() &&
         TestCCWs() &&
@@ -663,17 +663,17 @@ AllocSameCompartmentSourceObject(JSObjec
     return source;
 }
 
 JSObject*
 GetCrossCompartmentWrapper(JSObject* target)
 {
     MOZ_ASSERT(target->compartment() == global1->compartment());
     JS::RootedObject obj(cx, target);
-    JSAutoRealm ar(cx, global2);
+    JSAutoRealmAllowCCW ar(cx, global2);
     if (!JS_WrapObject(cx, &obj))
         return nullptr;
 
     EvictNursery();
 
     MOZ_ASSERT(obj->compartment() == global2->compartment());
     return obj;
 }
--- a/js/src/jsapi-tests/testGCMarking.cpp
+++ b/js/src/jsapi-tests/testGCMarking.cpp
@@ -40,17 +40,17 @@ ConstructCCW(JSContext* cx, const JSClas
     // This checks that the API obeys the implicit zone request.
     if (global1->zone() == global2->zone()) {
         fprintf(stderr, "global2 is in global1's zone");
         return false;
     }
 
     // Define an object in compartment 2, that is wrapped by a CCW into compartment 1.
     {
-        JSAutoRealm ar(cx, global2);
+        JSAutoRealmAllowCCW ar(cx, global2);
         wrappee.set(JS_NewPlainObject(cx));
         if (wrappee->compartment() != global2->compartment()) {
             fprintf(stderr, "wrappee in wrong compartment");
             return false;
         }
     }
 
     wrapper.set(wrappee);
--- a/js/src/jsapi-tests/testMutedErrors.cpp
+++ b/js/src/jsapi-tests/testMutedErrors.cpp
@@ -41,17 +41,17 @@ eval(const char* asciiChars, bool mutedE
     for (size_t i = 0; i < len; ++i)
         chars[i] = asciiChars[i];
     chars[len] = 0;
 
     JS::RealmOptions globalOptions;
     JS::RootedObject global(cx, JS_NewGlobalObject(cx, getGlobalClass(), nullptr,
 						   JS::FireOnNewGlobalHook, globalOptions));
     CHECK(global);
-    JSAutoRealm ar(cx, global);
+    JSAutoRealmAllowCCW ar(cx, global);
     CHECK(JS::InitRealmStandardClasses(cx));
 
 
     JS::CompileOptions options(cx);
     options.setMutedErrors(mutedErrors)
            .setFileAndLine("", 0);
 
     return JS::Evaluate(cx, options, chars.get(), len, rval);
--- a/js/src/jsapi-tests/testPreserveJitCode.cpp
+++ b/js/src/jsapi-tests/testPreserveJitCode.cpp
@@ -38,17 +38,17 @@ bool
 testPreserveJitCode(bool preserveJitCode, unsigned remainingIonScripts)
 {
     cx->options().setBaseline(true);
     cx->options().setIon(true);
     cx->runtime()->setOffthreadIonCompilationEnabled(false);
 
     RootedObject global(cx, createTestGlobal(preserveJitCode));
     CHECK(global);
-    JSAutoRealm ar(cx, global);
+    JSAutoRealmAllowCCW ar(cx, global);
 
     // The Ion JIT may be unavailable due to --disable-ion or lack of support
     // for this platform.
     if (!js::jit::IsIonEnabled(cx))
         knownFail = true;
 
     CHECK_EQUAL(countIonScripts(global), 0u);
 
--- a/js/src/jsapi-tests/testScriptObject.cpp
+++ b/js/src/jsapi-tests/testScriptObject.cpp
@@ -180,17 +180,17 @@ BEGIN_FIXTURE_TEST(ScriptObjectFixture, 
     options.setFileAndLine(__FILE__, __LINE__);
     CHECK(JS_CompileScript(cx, "val", 3, options, &script));
     JS::RootedValue value(cx);
     CHECK(JS_ExecuteScript(cx, script, &value));
     CHECK(value.toInt32() == 42);
     {
         JS::RootedObject global2(cx, createGlobal());
         CHECK(global2);
-        JSAutoRealm ar(cx, global2);
+        JSAutoRealmAllowCCW ar(cx, global2);
         CHECK(JS_WrapValue(cx, &fortyTwo));
         CHECK(JS_SetProperty(cx, global, "val", fortyTwo));
         JS::RootedValue value2(cx);
         CHECK(JS::CloneAndExecuteScript(cx, script, &value2));
         CHECK(value2.toInt32() == 42);
     }
     JS::RootedValue value3(cx);
     CHECK(JS_ExecuteScript(cx, script, &value3));
--- a/js/src/jsapi-tests/testStructuredClone.cpp
+++ b/js/src/jsapi-tests/testStructuredClone.cpp
@@ -14,27 +14,27 @@ BEGIN_TEST(testStructuredClone_object)
     JS::RootedObject g1(cx, createGlobal());
     JS::RootedObject g2(cx, createGlobal());
     CHECK(g1);
     CHECK(g2);
 
     JS::RootedValue v1(cx);
 
     {
-        JSAutoRealm ar(cx, g1);
+        JSAutoRealmAllowCCW ar(cx, g1);
         JS::RootedValue prop(cx, JS::Int32Value(1337));
 
         JS::RootedObject obj(cx, JS_NewPlainObject(cx));
         v1 = JS::ObjectOrNullValue(obj);
         CHECK(v1.isObject());
         CHECK(JS_SetProperty(cx, obj, "prop", prop));
     }
 
     {
-        JSAutoRealm ar(cx, g2);
+        JSAutoRealmAllowCCW ar(cx, g2);
         JS::RootedValue v2(cx);
 
         CHECK(JS_StructuredClone(cx, v1, &v2, nullptr, nullptr));
         CHECK(v2.isObject());
         JS::RootedObject obj(cx, &v2.toObject());
 
         JS::RootedValue prop(cx);
         CHECK(JS_GetProperty(cx, obj, "prop", &prop));
@@ -52,26 +52,26 @@ BEGIN_TEST(testStructuredClone_string)
     JS::RootedObject g1(cx, createGlobal());
     JS::RootedObject g2(cx, createGlobal());
     CHECK(g1);
     CHECK(g2);
 
     JS::RootedValue v1(cx);
 
     {
-        JSAutoRealm ar(cx, g1);
+        JSAutoRealmAllowCCW ar(cx, g1);
         JS::RootedValue prop(cx, JS::Int32Value(1337));
 
         v1 = JS::StringValue(JS_NewStringCopyZ(cx, "Hello World!"));
         CHECK(v1.isString());
         CHECK(v1.toString());
     }
 
     {
-        JSAutoRealm ar(cx, g2);
+        JSAutoRealmAllowCCW ar(cx, g2);
         JS::RootedValue v2(cx);
 
         CHECK(JS_StructuredClone(cx, v1, &v2, nullptr, nullptr));
         CHECK(v2.isString());
         CHECK(v2.toString());
 
         JS::RootedValue expected(cx, JS::StringValue(
             JS_NewStringCopyZ(cx, "Hello World!")));
@@ -88,28 +88,28 @@ BEGIN_TEST(testStructuredClone_externalA
     JS::RootedObject g1(cx, createGlobal());
     JS::RootedObject g2(cx, createGlobal());
     CHECK(g1);
     CHECK(g2);
 
     JS::RootedValue v1(cx);
 
     {
-        JSAutoRealm ar(cx, g1);
+        JSAutoRealmAllowCCW ar(cx, g1);
 
         JS::RootedObject obj(cx, JS_NewExternalArrayBuffer(cx, data.len(), data.contents(),
             &ExternalData::freeCallback, &data));
         CHECK(!data.wasFreed());
 
         v1 = JS::ObjectOrNullValue(obj);
         CHECK(v1.isObject());
     }
 
     {
-        JSAutoRealm ar(cx, g2);
+        JSAutoRealmAllowCCW ar(cx, g2);
         JS::RootedValue v2(cx);
 
         CHECK(JS_StructuredClone(cx, v1, &v2, nullptr, nullptr));
         CHECK(v2.isObject());
 
         JS::RootedObject obj(cx, &v2.toObject());
         CHECK(&v1.toObject() != obj);
 
@@ -264,17 +264,17 @@ BEGIN_TEST(testStructuredClone_SavedFram
 
     for (auto* pp = principalsToTest; pp->principals != DONE; pp++) {
         fprintf(stderr, "Testing with principals '%s'\n", pp->name);
 
         JS::RealmOptions options;
         JS::RootedObject g(cx, JS_NewGlobalObject(cx, getGlobalClass(), pp->principals,
                                                   JS::FireOnNewGlobalHook, options));
         CHECK(g);
-        JSAutoRealm ar(cx, g);
+        JSAutoRealmAllowCCW ar(cx, g);
 
         CHECK(js::DefineTestingFunctions(cx, g, false, false));
 
         JS::RootedValue srcVal(cx);
         CHECK(evaluate("(function one() {                      \n"  // 1
                        "  return (function two() {             \n"  // 2
                        "    return (function three() {         \n"  // 3
                        "      return saveStack();              \n"  // 4
--- a/js/src/jsapi-tests/testUbiNode.cpp
+++ b/js/src/jsapi-tests/testUbiNode.cpp
@@ -92,17 +92,17 @@ BEGIN_TEST(test_ubiNodeZone)
     RootedString string1(cx, JS_NewStringCopyZ(cx, "Simpson's Individual Stringettes!"));
     CHECK(string1);
     RootedScript script1(cx);
     CHECK(JS::Compile(cx, options, "", 0, &script1));
 
     {
         // ... and then enter global2's zone and create a string and script
         // there, too.
-        JSAutoRealm ar(cx, global2);
+        JSAutoRealmAllowCCW ar(cx, global2);
 
         RootedString string2(cx, JS_NewStringCopyZ(cx, "A million household uses!"));
         CHECK(string2);
         RootedScript script2(cx);
         CHECK(JS::Compile(cx, options, "", 0, &script2));
 
         CHECK(JS::ubi::Node(string1).zone() == global1->zone());
         CHECK(JS::ubi::Node(script1).zone() == global1->zone());
@@ -137,17 +137,17 @@ BEGIN_TEST(test_ubiNodeCompartment)
 
     // Create a script in the original realm...
     RootedScript script1(cx);
     CHECK(JS::Compile(cx, options, "", 0, &script1));
 
     {
         // ... and then enter global2's realm and create a script
         // there, too.
-        JSAutoRealm ar(cx, global2);
+        JSAutoRealmAllowCCW ar(cx, global2);
 
         RootedScript script2(cx);
         CHECK(JS::Compile(cx, options, "", 0, &script2));
 
         CHECK(JS::ubi::Node(script1).compartment() == global1->compartment());
         CHECK(JS::ubi::Node(script2).compartment() == global2->compartment());
         CHECK(JS::ubi::Node(script1).realm() == global1->nonCCWRealm());
         CHECK(JS::ubi::Node(script2).realm() == global2->nonCCWRealm());
--- a/js/src/jsapi-tests/testWeakMap.cpp
+++ b/js/src/jsapi-tests/testWeakMap.cpp
@@ -81,17 +81,17 @@ BEGIN_TEST(testWeakMap_keyDelegates)
     CHECK(key);
 
     JS::RootedObject delegate(cx, newDelegate());
     CHECK(delegate);
     keyDelegate = delegate;
 
     JS::RootedObject delegateRoot(cx);
     {
-        JSAutoRealm ar(cx, delegate);
+        JSAutoRealmAllowCCW ar(cx, delegate);
         delegateRoot = JS_NewPlainObject(cx);
         CHECK(delegateRoot);
         JS::RootedValue delegateValue(cx, JS::ObjectValue(*delegate));
         CHECK(JS_DefineProperty(cx, delegateRoot, "delegate", delegateValue, 0));
     }
     delegate = nullptr;
 
     /*
@@ -180,23 +180,23 @@ JSObject* newCCW(JS::HandleObject source
 {
     /*
      * Now ensure that this zone will be swept first by adding a cross
      * compartment wrapper to a new objct in the same zone as the
      * delegate obejct.
      */
     JS::RootedObject object(cx);
     {
-        JSAutoRealm ar(cx, destZone);
+        JSAutoRealmAllowCCW ar(cx, destZone);
         object = JS_NewPlainObject(cx);
         if (!object)
             return nullptr;
     }
     {
-        JSAutoRealm ar(cx, sourceZone);
+        JSAutoRealmAllowCCW ar(cx, sourceZone);
         if (!JS_WrapObject(cx, &object))
             return nullptr;
     }
 
     // In order to test the SCC algorithm, we need the wrapper/wrappee to be
     // tenured.
     cx->runtime()->gc.evictNursery();
 
--- a/js/src/jsapi-tests/tests.cpp
+++ b/js/src/jsapi-tests/tests.cpp
@@ -83,17 +83,17 @@ JSObject* JSAPITest::createGlobal(JSPrin
 #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;
 
     global = newGlobal;
     return newGlobal;
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -681,37 +681,37 @@ 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);
 }
 
-JSAutoRealm::JSAutoRealm(JSContext* cx, JSScript* target
-                         MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
+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);
 }
 
-JSAutoRealm::~JSAutoRealm()
+JSAutoRealmAllowCCW::~JSAutoRealmAllowCCW()
 {
     cx_->leaveRealm(oldRealm_);
 }
 
 JSAutoNullableRealm::JSAutoNullableRealm(JSContext* cx,
                                          JSObject* targetOrNull
                                          MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL)
   : cx_(cx),
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -1032,24 +1032,24 @@ 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)
+class MOZ_RAII JS_PUBLIC_API(JSAutoRealmAllowCCW)
 {
     JSContext* cx_;
     JS::Realm* oldRealm_;
   public:
-    JSAutoRealm(JSContext* cx, JSObject* target MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
-    JSAutoRealm(JSContext* cx, JSScript* target MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
-    ~JSAutoRealm();
+    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(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/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/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;