Backed out 7 changesets (bug 1521907) for failing at unit/test_bug1151385.js on a CLOSED TREE.
authorGurzau Raul <rgurzau@mozilla.com>
Sat, 02 Feb 2019 00:58:16 +0200
changeset 456494 bcb403c04f1c869e7a64636077deb8f6a9ef2aff
parent 456493 cc76d4da63a5503bf9bd1c133776b350428faa56
child 456495 6d3b8198f3995d6400433eddd85ae040ecdba310
push id35487
push userdvarga@mozilla.com
push dateSat, 02 Feb 2019 09:42:37 +0000
treeherdermozilla-central@cb5ed33ae30d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1521907, 1151385
milestone67.0a1
backs outef04359ccf0dfb82a65e82fbffff5143a60e941b
ac1c61bf61e990ea7100932636a096a1d09a049f
df09b7be63c5a642faf52ec29ff5da15d5ae4b04
585fa0024d46a6ee33266c11bbe07a40be1be470
e593c29aaff4ef032f7c8ede910dd8331d8c9a40
ac2e180a35b653adf5f27af2e7de43416b3b341e
270b1db9ea81e8fd365405fe08248291e842578a
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
Backed out 7 changesets (bug 1521907) for failing at unit/test_bug1151385.js on a CLOSED TREE. Backed out changeset ef04359ccf0d (bug 1521907) Backed out changeset ac1c61bf61e9 (bug 1521907) Backed out changeset df09b7be63c5 (bug 1521907) Backed out changeset 585fa0024d46 (bug 1521907) Backed out changeset e593c29aaff4 (bug 1521907) Backed out changeset ac2e180a35b6 (bug 1521907) Backed out changeset 270b1db9ea81 (bug 1521907)
dom/base/ChromeUtils.cpp
dom/base/CustomElementRegistry.cpp
dom/base/MaybeCrossOriginObject.cpp
dom/base/MaybeCrossOriginObject.h
dom/base/StructuredCloneBlob.cpp
dom/base/StructuredCloneHolder.cpp
dom/base/nsContentPermissionHelper.cpp
dom/base/nsContentUtils.cpp
dom/base/nsGlobalWindowOuter.cpp
dom/base/nsJSUtils.cpp
dom/bindings/BindingUtils.cpp
dom/bindings/BindingUtils.h
dom/bindings/Codegen.py
dom/bindings/Date.h
dom/bindings/Exceptions.cpp
dom/bindings/WebIDLGlobalNameHash.cpp
dom/bindings/test/TestFunctions.cpp
dom/media/webaudio/AudioContext.cpp
dom/media/webaudio/AudioWorkletGlobalScope.cpp
dom/plugins/base/nsJSNPRuntime.cpp
dom/promise/PromiseDebugging.cpp
dom/workers/WorkerScope.cpp
dom/xbl/nsXBLProtoImplField.cpp
js/ipc/WrapperOwner.cpp
js/public/Wrapper.h
js/src/proxy/Wrapper.cpp
js/src/vm/Debugger-inl.h
js/src/vm/Debugger.cpp
js/xpconnect/src/ExportHelpers.cpp
js/xpconnect/src/Sandbox.cpp
js/xpconnect/src/XPCCallContext.cpp
js/xpconnect/src/XPCComponents.cpp
js/xpconnect/src/XPCConvert.cpp
js/xpconnect/src/XPCJSContext.cpp
js/xpconnect/src/XPCJSID.cpp
js/xpconnect/src/XPCJSRuntime.cpp
js/xpconnect/src/XPCJSWeakReference.cpp
js/xpconnect/src/XPCVariant.cpp
js/xpconnect/src/XPCWrappedNativeJSOps.cpp
js/xpconnect/src/nsXPConnect.cpp
js/xpconnect/src/xpcpublic.h
js/xpconnect/wrappers/WrapperFactory.cpp
js/xpconnect/wrappers/WrapperFactory.h
js/xpconnect/wrappers/XrayWrapper.cpp
toolkit/components/mozintl/MozIntlHelper.cpp
toolkit/components/telemetry/core/Stopwatch.cpp
toolkit/recordreplay/ipc/JSControl.cpp
xpcom/reflect/xptinfo/xptcodegen.py
xpcom/reflect/xptinfo/xptinfo.h
--- a/dom/base/ChromeUtils.cpp
+++ b/dom/base/ChromeUtils.cpp
@@ -216,20 +216,17 @@ namespace dom {
 
   auto cleanup = MakeScopeExit([&]() { aRv.NoteJSContextException(cx); });
 
   JS::Rooted<JS::IdVector> ids(cx, JS::IdVector(cx));
   JS::AutoValueVector values(cx);
   JS::AutoIdVector valuesIds(cx);
 
   {
-    // cx represents our current Realm, so it makes sense to use it for the
-    // CheckedUnwrapDynamic call.  We do want CheckedUnwrapDynamic, in case
-    // someone is shallow-cloning a Window.
-    JS::RootedObject obj(cx, js::CheckedUnwrapDynamic(aObj, cx));
+    JS::RootedObject obj(cx, js::CheckedUnwrap(aObj));
     if (!obj) {
       js::ReportAccessDenied(cx);
       return;
     }
 
     if (js::IsScriptedProxy(obj)) {
       JS_ReportErrorASCII(cx, "Shallow cloning a proxy object is not allowed");
       return;
@@ -256,20 +253,17 @@ namespace dom {
       values.infallibleAppend(desc.value());
     }
   }
 
   JS::RootedObject obj(cx);
   {
     Maybe<JSAutoRealm> ar;
     if (aTarget) {
-      // Our target could be anything, so we want CheckedUnwrapDynamic here.
-      // "cx" represents the current Realm when we were called from bindings, so
-      // we can just use that.
-      JS::RootedObject target(cx, js::CheckedUnwrapDynamic(aTarget, cx));
+      JS::RootedObject target(cx, js::CheckedUnwrap(aTarget));
       if (!target) {
         js::ReportAccessDenied(cx);
         return;
       }
       ar.emplace(cx, target);
     }
 
     obj = JS_NewPlainObject(cx);
--- a/dom/base/CustomElementRegistry.cpp
+++ b/dom/base/CustomElementRegistry.cpp
@@ -375,19 +375,17 @@ CustomElementDefinition* CustomElementRe
     return data;
   }
 
   return nullptr;
 }
 
 CustomElementDefinition* CustomElementRegistry::LookupCustomElementDefinition(
     JSContext* aCx, JSObject* aConstructor) const {
-  // We're looking up things that tested true for JS::IsConstructor,
-  // so doing a CheckedUnwrapStatic is fine here.
-  JS::Rooted<JSObject*> constructor(aCx, js::CheckedUnwrapStatic(aConstructor));
+  JS::Rooted<JSObject*> constructor(aCx, js::CheckedUnwrap(aConstructor));
 
   const auto& ptr = mConstructors.lookup(constructor);
   if (!ptr) {
     return nullptr;
   }
 
   CustomElementDefinition* definition =
       mCustomDefinitions.GetWeak(ptr->value());
@@ -662,24 +660,18 @@ int32_t CustomElementRegistry::InferName
 
 // https://html.spec.whatwg.org/multipage/scripting.html#element-definition
 void CustomElementRegistry::Define(JSContext* aCx, const nsAString& aName,
                                    Function& aFunctionConstructor,
                                    const ElementDefinitionOptions& aOptions,
                                    ErrorResult& aRv) {
   JS::Rooted<JSObject*> constructor(aCx, aFunctionConstructor.CallableOrNull());
 
-  // We need to do a dynamic unwrap in order to throw the right exception.  We
-  // could probably avoid that if we just threw MSG_NOT_CONSTRUCTOR if unwrap
-  // fails.
-  //
-  // In any case, aCx represents the global we want to be using for the unwrap
-  // here.
-  JS::Rooted<JSObject*> constructorUnwrapped(
-      aCx, js::CheckedUnwrapDynamic(constructor, aCx));
+  JS::Rooted<JSObject*> constructorUnwrapped(aCx,
+                                             js::CheckedUnwrap(constructor));
   if (!constructorUnwrapped) {
     // If the caller's compartment does not have permission to access the
     // unwrapped constructor then throw.
     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
     return;
   }
 
   /**
--- a/dom/base/MaybeCrossOriginObject.cpp
+++ b/dom/base/MaybeCrossOriginObject.cpp
@@ -22,18 +22,18 @@ static bool IsLocation(JSObject* obj) {
   return strcmp(js::GetObjectClass(obj)->name, "Location") == 0;
 }
 #endif  // DEBUG
 
 namespace mozilla {
 namespace dom {
 
 /* static */
-bool MaybeCrossOriginObjectMixins::IsPlatformObjectSameOrigin(JSContext* cx,
-                                                              JSObject* obj) {
+bool MaybeCrossOriginObjectMixins::IsPlatformObjectSameOrigin(
+    JSContext* cx, JS::Handle<JSObject*> obj) {
   MOZ_ASSERT(!js::IsCrossCompartmentWrapper(obj));
   // WindowProxy and Window must always be same-Realm, so we can do
   // our IsPlatformObjectSameOrigin check against either one.  But verify that
   // in case we have a WindowProxy the right things happen.
   MOZ_ASSERT(js::GetNonCCWObjectRealm(obj) ==
                  // "true" for second arg means to unwrap WindowProxy to
                  // get at the Window.
                  js::GetNonCCWObjectRealm(js::UncheckedUnwrap(obj, true)),
--- a/dom/base/MaybeCrossOriginObject.h
+++ b/dom/base/MaybeCrossOriginObject.h
@@ -33,27 +33,27 @@
 
 namespace mozilla {
 namespace dom {
 
 // Methods that MaybeCrossOriginObject wants that do not depend on the "Base"
 // template parameter.  We can avoid having multiple instantiations of them by
 // pulling them out into this helper class.
 class MaybeCrossOriginObjectMixins {
- public:
+ protected:
   /**
    * Implementation of
    * <https://html.spec.whatwg.org/multipage/browsers.html#isplatformobjectsameorigin-(-o-)>.
    * "cx" and "obj" may or may not be same-compartment and even when
    * same-compartment may not be same-Realm.  "obj" can be a WindowProxy, a
    * Window, or a Location.
    */
-  static bool IsPlatformObjectSameOrigin(JSContext* cx, JSObject* obj);
+  static bool IsPlatformObjectSameOrigin(JSContext* cx,
+                                         JS::Handle<JSObject*> obj);
 
- protected:
   /**
    * Implementation of
    * <https://html.spec.whatwg.org/multipage/browsers.html#crossorigingetownpropertyhelper-(-o,-p-)>.
    *
    * "cx" and "obj" are expected to be different-Realm here, and may be
    * different-compartment.  "obj" can be a "WindowProxy" or a "Location" or a
    * cross-process proxy for one of those.
    */
--- a/dom/base/StructuredCloneBlob.cpp
+++ b/dom/base/StructuredCloneBlob.cpp
@@ -35,34 +35,31 @@ StructuredCloneBlob::Constructor(GlobalO
   JSContext* cx = aGlobal.Context();
 
   RefPtr<StructuredCloneBlob> holder = StructuredCloneBlob::Create();
 
   Maybe<JSAutoRealm> ar;
   JS::RootedValue value(cx, aValue);
 
   if (aTargetGlobal) {
-    // OK to unwrap if our caller (represented by cx's Realm) can do it.
-    JS::RootedObject targetGlobal(cx,
-                                  js::CheckedUnwrapDynamic(aTargetGlobal, cx));
+    JS::RootedObject targetGlobal(cx, js::CheckedUnwrap(aTargetGlobal));
     if (!targetGlobal) {
       js::ReportAccessDenied(cx);
       aRv.NoteJSContextException(cx);
       return nullptr;
     }
 
     ar.emplace(cx, targetGlobal);
 
     if (!JS_WrapValue(cx, &value)) {
       aRv.NoteJSContextException(cx);
       return nullptr;
     }
   } else if (value.isObject()) {
-    // OK to unwrap if our caller (represented by cx's Realm) can do it.
-    JS::RootedObject obj(cx, js::CheckedUnwrapDynamic(&value.toObject(), cx));
+    JS::RootedObject obj(cx, js::CheckedUnwrap(&value.toObject()));
     if (!obj) {
       js::ReportAccessDenied(cx);
       aRv.NoteJSContextException(cx);
       return nullptr;
     }
 
     ar.emplace(cx, obj);
     value = JS::ObjectValue(*obj);
@@ -76,18 +73,17 @@ StructuredCloneBlob::Constructor(GlobalO
   return holder.forget();
 }
 
 void StructuredCloneBlob::Deserialize(JSContext* aCx,
                                       JS::HandleObject aTargetScope,
                                       bool aKeepData,
                                       JS::MutableHandleValue aResult,
                                       ErrorResult& aRv) {
-  // OK to unwrap if our caller (represented by aCx's Realm) can do it.
-  JS::RootedObject scope(aCx, js::CheckedUnwrapDynamic(aTargetScope, aCx));
+  JS::RootedObject scope(aCx, js::CheckedUnwrap(aTargetScope));
   if (!scope) {
     js::ReportAccessDenied(aCx);
     aRv.NoteJSContextException(aCx);
     return;
   }
 
   if (!mHolder.isSome()) {
     aRv.Throw(NS_ERROR_NOT_INITIALIZED);
--- a/dom/base/StructuredCloneHolder.cpp
+++ b/dom/base/StructuredCloneHolder.cpp
@@ -463,19 +463,18 @@ void StructuredCloneHolder::ReadFromBuff
         xpc::Throw(aCx, NS_ERROR_DOM_DATA_CLONE_ERR);
         return false;
       }
 
       return sct->WriteStructuredClone(aWriter);
     }
   }
 
-  if (NS_IsMainThread() && xpc::IsReflector(obj, aCx)) {
-    // We only care about principals, so ReflectorToISupportsStatic is fine.
-    nsCOMPtr<nsISupports> base = xpc::ReflectorToISupportsStatic(obj);
+  if (NS_IsMainThread() && xpc::IsReflector(obj)) {
+    nsCOMPtr<nsISupports> base = xpc::UnwrapReflectorToISupports(obj);
     nsCOMPtr<nsIPrincipal> principal = do_QueryInterface(base);
     if (principal) {
       auto nsjsprincipals = nsJSPrincipals::get(principal);
       return nsjsprincipals->write(aCx, aWriter);
     }
   }
 
   // Don't know what this is
@@ -1038,18 +1037,17 @@ bool StructuredCloneHolder::CustomWriteH
       JS::IsWasmModuleObject(obj)) {
     RefPtr<JS::WasmModule> module = JS::GetWasmModule(obj);
     MOZ_ASSERT(module);
 
     return WriteWasmModule(aWriter, module, this);
   }
 
   {
-    // We only care about streams, so ReflectorToISupportsStatic is fine.
-    nsCOMPtr<nsISupports> base = xpc::ReflectorToISupportsStatic(aObj);
+    nsCOMPtr<nsISupports> base = xpc::UnwrapReflectorToISupports(aObj);
     nsCOMPtr<nsIInputStream> inputStream = do_QueryInterface(base);
     if (inputStream) {
       return WriteInputStream(aWriter, inputStream, this);
     }
   }
 
   return WriteFullySerializableObjects(aCx, aWriter, aObj);
 }
--- a/dom/base/nsContentPermissionHelper.cpp
+++ b/dom/base/nsContentPermissionHelper.cpp
@@ -665,19 +665,17 @@ nsresult TranslateChoices(
   if (aChoices.isNullOrUndefined()) {
     // No choice is specified.
   } else if (aChoices.isObject()) {
     // Iterate through all permission types.
     for (uint32_t i = 0; i < aPermissionRequests.Length(); ++i) {
       nsCString type = aPermissionRequests[i].type();
 
       JS::Rooted<JSObject*> obj(RootingCx(), &aChoices.toObject());
-      // People really shouldn't be passing WindowProxy or Location
-      // objects for the choices here.
-      obj = js::CheckedUnwrapStatic(obj);
+      obj = CheckedUnwrap(obj);
       if (!obj) {
         return NS_ERROR_FAILURE;
       }
 
       AutoJSAPI jsapi;
       jsapi.Init();
 
       JSContext* cx = jsapi.cx();
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -10291,19 +10291,18 @@ NS_IMPL_ISUPPORTS(nsContentUtils::UserIn
   ExtractExceptionValues<mozilla::dom::prototypes::id::T,         \
                          T##_Binding::NativeType, T>(__VA_ARGS__) \
       .isOk()
 
 template <prototypes::ID PrototypeID, class NativeType, typename T>
 static Result<Ok, nsresult> ExtractExceptionValues(
     JSContext* aCx, JS::HandleObject aObj, nsAString& aSourceSpecOut,
     uint32_t* aLineOut, uint32_t* aColumnOut, nsString& aMessageOut) {
-  AssertStaticUnwrapOK<PrototypeID>();
   RefPtr<T> exn;
-  MOZ_TRY((UnwrapObject<PrototypeID, NativeType>(aObj, exn, nullptr)));
+  MOZ_TRY((UnwrapObject<PrototypeID, NativeType>(aObj, exn)));
 
   exn->GetFilename(aCx, aSourceSpecOut);
   if (!aSourceSpecOut.IsEmpty()) {
     *aLineOut = exn->LineNumber(aCx);
     *aColumnOut = exn->ColumnNumber();
   }
 
   exn->GetName(aMessageOut);
--- a/dom/base/nsGlobalWindowOuter.cpp
+++ b/dom/base/nsGlobalWindowOuter.cpp
@@ -5775,22 +5775,18 @@ nsGlobalWindowInner* nsGlobalWindowOuter
   // 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(aCx, scope);
     JS::Rooted<JSObject*> scopeProto(aCx);
     bool ok = JS_GetPrototype(aCx, scope, &scopeProto);
     NS_ENSURE_TRUE(ok, nullptr);
     if (scopeProto && xpc::IsSandboxPrototypeProxy(scopeProto) &&
-        // Our current Realm on aCx is the sandbox.  Using that for the
-        // CheckedUnwrapDynamic call makes sense: if the sandbox can unwrap the
-        // window, we can use it.  And we do want CheckedUnwrapDynamic, because
-        // the whole point is to unwrap windows.
-        (scopeProto = js::CheckedUnwrapDynamic(
-             scopeProto, aCx, /* stopAtWindowProxy = */ false))) {
+        (scopeProto =
+             js::CheckedUnwrap(scopeProto, /* stopAtWindowProxy = */ false))) {
       global = xpc::NativeGlobal(scopeProto);
       NS_ENSURE_TRUE(global, nullptr);
     }
   }
 
   // The calling window must be holding a reference, so we can return a weak
   // pointer.
   nsCOMPtr<nsPIDOMWindowInner> win = do_QueryInterface(global);
--- a/dom/base/nsJSUtils.cpp
+++ b/dom/base/nsJSUtils.cpp
@@ -395,18 +395,17 @@ nsresult nsJSUtils::ExecutionContext::Ex
   return NS_OK;
 }
 
 static bool IsPromiseValue(JSContext* aCx, JS::Handle<JS::Value> aValue) {
   if (!aValue.isObject()) {
     return false;
   }
 
-  // We only care about Promise here, so CheckedUnwrapStatic is fine.
-  JS::Rooted<JSObject*> obj(aCx, js::CheckedUnwrapStatic(&aValue.toObject()));
+  JS::Rooted<JSObject*> obj(aCx, js::CheckedUnwrap(&aValue.toObject()));
   if (!obj) {
     return false;
   }
 
   return JS::IsPromiseObject(obj);
 }
 
 nsresult nsJSUtils::ExecutionContext::ExecScript(
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -1216,19 +1216,19 @@ bool QueryInterface(JSContext* cx, unsig
   if (!args.thisv().isObject()) {
     JS_ReportErrorASCII(cx, "QueryInterface called on incompatible non-object");
     return false;
   }
 
   // Get the object. It might be a security wrapper, in which case we do a
   // checked unwrap.
   JS::Rooted<JSObject*> origObj(cx, &args.thisv().toObject());
-  JS::Rooted<JSObject*> obj(
-      cx, js::CheckedUnwrapDynamic(origObj, cx,
-                                   /* stopAtWindowProxy = */ false));
+  JS::Rooted<JSObject*> obj(cx,
+                            js::CheckedUnwrap(origObj,
+                                              /* stopAtWindowProxy = */ false));
   if (!obj) {
     JS_ReportErrorASCII(cx, "Permission denied to access object");
     return false;
   }
 
   nsCOMPtr<nsISupports> native = UnwrapDOMObjectToISupports(obj);
   if (!native) {
     return Throw(cx, NS_ERROR_FAILURE);
@@ -2256,18 +2256,17 @@ void UpdateReflectorGlobal(JSContext* aC
   }
 }
 
 GlobalObject::GlobalObject(JSContext* aCx, JSObject* aObject)
     : mGlobalJSObject(aCx), mCx(aCx), mGlobalObject(nullptr) {
   MOZ_ASSERT(mCx);
   JS::Rooted<JSObject*> obj(aCx, aObject);
   if (js::IsWrapper(obj)) {
-    // aCx correctly represents the current global here.
-    obj = js::CheckedUnwrapDynamic(obj, aCx, /* stopAtWindowProxy = */ false);
+    obj = js::CheckedUnwrap(obj, /* stopAtWindowProxy = */ false);
     if (!obj) {
       // We should never end up here on a worker thread, since there shouldn't
       // be any security wrappers to worry about.
       if (!MOZ_LIKELY(NS_IsMainThread())) {
         MOZ_CRASH();
       }
 
       Throw(aCx, NS_ERROR_XPC_SECURITY_MANAGER_VETO);
@@ -2298,20 +2297,17 @@ nsISupports* GlobalObject::GetAsSupports
   // Remove everything below here once all our global objects are using new
   // bindings.  If that ever happens; it would need to include Sandbox and
   // BackstagePass.
 
   // See whether mGlobalJSObject is an XPCWrappedNative.  This will redo the
   // IsWrapper bit above and the UnwrapDOMObjectToISupports in the case when
   // we're not actually an XPCWrappedNative, but this should be a rare-ish case
   // anyway.
-  //
-  // It's OK to use ReflectorToISupportsStatic, because we know we don't have a
-  // cross-compartment wrapper.
-  nsCOMPtr<nsISupports> supp = xpc::ReflectorToISupportsStatic(mGlobalJSObject);
+  nsCOMPtr<nsISupports> supp = xpc::UnwrapReflectorToISupports(mGlobalJSObject);
   if (supp) {
     // See documentation for mGlobalJSObject for why this assignment is OK.
     mGlobalObject = supp;
     return mGlobalObject;
   }
 
   // And now a final hack.  Sandbox is not a reflector, but it does have an
   // nsIGlobalObject hanging out in its private slot.  Handle that case here,
@@ -2368,21 +2364,20 @@ bool InterfaceHasInstance(JSContext* cx,
   // OrdinaryHasInstance).
   if (!args.thisv().isObject()) {
     args.rval().setBoolean(false);
     return true;
   }
 
   // If "this" doesn't have a DOMIfaceAndProtoJSClass, it's not a DOM
   // constructor, so just fall back to OrdinaryHasInstance.  But note that we
-  // should CheckedUnwrapStatic here, because otherwise we won't get the right
-  // answers.  The static version is OK, because we're looking for DOM
-  // constructors, which are not cross-origin objects.
-  JS::Rooted<JSObject*> thisObj(
-      cx, js::CheckedUnwrapStatic(&args.thisv().toObject()));
+  // should CheckedUnwrap here, because otherwise we won't get the right
+  // answers.
+  JS::Rooted<JSObject*> thisObj(cx,
+                                js::CheckedUnwrap(&args.thisv().toObject()));
   if (!thisObj) {
     // Just fall back on the normal thing, in case it still happens to work.
     return CallOrdinaryHasInstance(cx, args);
   }
 
   const js::Class* thisClass = js::GetObjectClass(thisObj);
 
   if (!IsDOMIfaceAndProtoClass(thisClass)) {
@@ -2445,20 +2440,18 @@ bool InterfaceIsInstance(JSContext* cx, 
 
   // If "this" isn't a DOM constructor or is a constructor for an interface
   // without a prototype, return false.
   if (!args.thisv().isObject()) {
     args.rval().setBoolean(false);
     return true;
   }
 
-  // CheckedUnwrapStatic is fine, since we're just interested in finding out
-  // whether this is a DOM constructor.
-  JS::Rooted<JSObject*> thisObj(
-      cx, js::CheckedUnwrapStatic(&args.thisv().toObject()));
+  JS::Rooted<JSObject*> thisObj(cx,
+                                js::CheckedUnwrap(&args.thisv().toObject()));
   if (!thisObj) {
     args.rval().setBoolean(false);
     return true;
   }
 
   const js::Class* thisClass = js::GetObjectClass(thisObj);
   if (!IsDOMIfaceAndProtoClass(thisClass)) {
     args.rval().setBoolean(false);
@@ -2818,19 +2811,16 @@ namespace binding_detail {
  *                   the native (which is why aSelf is a reference to a void*).
  *                   The ThisPolicy user should use the this JSObject* to
  *                   determine what C++ class aSelf contains. aObj is used to
  *                   keep the reflector object alive while self is being used,
  *                   so its value before and after the UnwrapThisObject call
  *                   could be different (if aObj was wrapped). The return value
  *                   is an nsresult, which will signal if an error occurred.
  *
- *                   This is passed a JSContext for dynamic unwrapping purposes,
- *                   but should not throw exceptions on that JSContext.
- *
  * HandleInvalidThis: If the |this| is not valid (wrong type of value, wrong
  *                    object, etc), decide what to do about it.  Returns a
  *                    boolean to return from the JSNative (false for failure,
  *                    true for succcess).
  */
 struct NormalThisPolicy {
   // This needs to be inlined because it's called on no-exceptions fast-paths.
   static MOZ_ALWAYS_INLINE bool HasValidThisValue(const JS::CallArgs& aArgs) {
@@ -2848,22 +2838,22 @@ struct NormalThisPolicy {
       const JS::CallArgs& aArgs) {
     return &aArgs.thisv().toObject();
   }
 
   static MOZ_ALWAYS_INLINE JSObject* MaybeUnwrapThisObject(JSObject* aObj) {
     return aObj;
   }
 
-  static MOZ_ALWAYS_INLINE nsresult UnwrapThisObject(
-      JS::MutableHandle<JSObject*> aObj, JSContext* aCx, void*& aSelf,
-      prototypes::ID aProtoID, uint32_t aProtoDepth) {
+  static MOZ_ALWAYS_INLINE nsresult
+  UnwrapThisObject(JS::MutableHandle<JSObject*> aObj, void*& aSelf,
+                   prototypes::ID aProtoID, uint32_t aProtoDepth) {
     binding_detail::MutableObjectHandleWrapper wrapper(aObj);
     return binding_detail::UnwrapObjectInternal<void, true>(
-        wrapper, aSelf, aProtoID, aProtoDepth, aCx);
+        wrapper, aSelf, aProtoID, aProtoDepth);
   }
 
   static bool HandleInvalidThis(JSContext* aCx, JS::CallArgs& aArgs,
                                 bool aSecurityError, prototypes::ID aProtoId) {
     return ThrowInvalidThis(aCx, aArgs, aSecurityError, aProtoId);
   }
 };
 
@@ -2921,46 +2911,42 @@ struct CrossOriginThisPolicy : public Ma
     // CheckedUnwrap it, and either succeed or get a security error as needed.
     return aObj;
   }
 
   // After calling UnwrapThisObject aSelf can contain one of 2 types, depending
   // on whether aObj is a proxy with a RemoteObjectProxy handler or a (maybe
   // wrapped) normal WebIDL reflector. The generated binding code relies on this
   // and uses IsRemoteObjectProxy to determine what type aSelf points to.
-  static MOZ_ALWAYS_INLINE nsresult UnwrapThisObject(
-      JS::MutableHandle<JSObject*> aObj, JSContext* aCx, void*& aSelf,
-      prototypes::ID aProtoID, uint32_t aProtoDepth) {
+  static MOZ_ALWAYS_INLINE nsresult
+  UnwrapThisObject(JS::MutableHandle<JSObject*> aObj, void*& aSelf,
+                   prototypes::ID aProtoID, uint32_t aProtoDepth) {
     binding_detail::MutableObjectHandleWrapper wrapper(aObj);
     // We need to pass false here, because if aObj doesn't have a DOMJSClass
     // it might be a remote proxy object, and we don't want to throw in that
     // case (even though unwrapping would fail).
     nsresult rv = binding_detail::UnwrapObjectInternal<void, false>(
-        wrapper, aSelf, aProtoID, aProtoDepth, nullptr);
+        wrapper, aSelf, aProtoID, aProtoDepth);
     if (NS_SUCCEEDED(rv)) {
       return rv;
     }
 
     if (js::IsWrapper(wrapper)) {
-      // We want CheckedUnwrapDynamic here: aCx represents the Realm we are in
-      // right now, so we want to check whether that Realm should be able to
-      // access the object.  And this object can definitely be a WindowProxy, so
-      // we need he dynamic check.
-      JSObject* unwrappedObj = js::CheckedUnwrapDynamic(
-          wrapper, aCx, /* stopAtWindowProxy = */ false);
+      JSObject* unwrappedObj =
+          js::CheckedUnwrap(wrapper, /* stopAtWindowProxy = */ false);
       if (!unwrappedObj) {
         return NS_ERROR_XPC_SECURITY_MANAGER_VETO;
       }
 
       // At this point we want to keep "unwrappedObj" alive, because we don't
       // hold a strong reference in "aSelf".
       wrapper = unwrappedObj;
 
       return binding_detail::UnwrapObjectInternal<void, false>(
-          wrapper, aSelf, aProtoID, aProtoDepth, nullptr);
+          wrapper, aSelf, aProtoID, aProtoDepth);
     }
 
     if (!IsRemoteObjectProxy(wrapper, aProtoID)) {
       return NS_ERROR_XPC_BAD_CONVERT_JS;
     }
     aSelf = RemoteObjectProxyBase::GetNative(wrapper);
     return NS_OK;
   }
@@ -3016,17 +3002,17 @@ bool GenericGetter(JSContext* cx, unsign
 
   // NOTE: we want to leave obj in its initial compartment, so don't want to
   // pass it to UnwrapObjectInternal.  Also, the thing we pass to
   // UnwrapObjectInternal may be affected by our ThisPolicy.
   JS::Rooted<JSObject*> rootSelf(cx, ThisPolicy::MaybeUnwrapThisObject(obj));
   void* self;
   {
     nsresult rv =
-        ThisPolicy::UnwrapThisObject(&rootSelf, cx, self, protoID, info->depth);
+        ThisPolicy::UnwrapThisObject(&rootSelf, self, protoID, info->depth);
     if (NS_FAILED(rv)) {
       bool ok = ThisPolicy::HandleInvalidThis(
           cx, args, rv == NS_ERROR_XPC_SECURITY_MANAGER_VETO, protoID);
       return ExceptionPolicy::HandleException(cx, args, info, ok);
     }
   }
 
   MOZ_ASSERT(info->type() == JSJitInfo::Getter);
@@ -3072,17 +3058,17 @@ bool GenericSetter(JSContext* cx, unsign
 
   // NOTE: we want to leave obj in its initial compartment, so don't want to
   // pass it to UnwrapObject.  Also the thing we pass to UnwrapObjectInternal
   // may be affected by our ThisPolicy.
   JS::Rooted<JSObject*> rootSelf(cx, ThisPolicy::MaybeUnwrapThisObject(obj));
   void* self;
   {
     nsresult rv =
-        ThisPolicy::UnwrapThisObject(&rootSelf, cx, self, protoID, info->depth);
+        ThisPolicy::UnwrapThisObject(&rootSelf, self, protoID, info->depth);
     if (NS_FAILED(rv)) {
       return ThisPolicy::HandleInvalidThis(
           cx, args, rv == NS_ERROR_XPC_SECURITY_MANAGER_VETO, protoID);
     }
   }
   if (args.length() == 0) {
     return ThrowNoSetterArg(cx, args, protoID);
   }
@@ -3121,17 +3107,17 @@ bool GenericMethod(JSContext* cx, unsign
 
   // NOTE: we want to leave obj in its initial compartment, so don't want to
   // pass it to UnwrapObjectInternal.  Also, the thing we pass to
   // UnwrapObjectInternal may be affected by our ThisPolicy.
   JS::Rooted<JSObject*> rootSelf(cx, ThisPolicy::MaybeUnwrapThisObject(obj));
   void* self;
   {
     nsresult rv =
-        ThisPolicy::UnwrapThisObject(&rootSelf, cx, self, protoID, info->depth);
+        ThisPolicy::UnwrapThisObject(&rootSelf, self, protoID, info->depth);
     if (NS_FAILED(rv)) {
       bool ok = ThisPolicy::HandleInvalidThis(
           cx, args, rv == NS_ERROR_XPC_SECURITY_MANAGER_VETO, protoID);
       return ExceptionPolicy::HandleException(cx, args, info, ok);
     }
   }
   MOZ_ASSERT(info->type() == JSJitInfo::Method);
   JSJitMethodOp method = info->method;
@@ -3264,19 +3250,17 @@ bool CallerSubsumes(JSObject* aObject) {
 }
 
 nsresult UnwrapArgImpl(JSContext* cx, JS::Handle<JSObject*> src,
                        const nsIID& iid, void** ppArg) {
   if (!NS_IsMainThread()) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
-  // The JSContext represents the "who is unwrapping" realm, so we want to use
-  // it for ReflectorToISupportsDynamic here.
-  nsCOMPtr<nsISupports> iface = xpc::ReflectorToISupportsDynamic(src, cx);
+  nsCOMPtr<nsISupports> iface = xpc::UnwrapReflectorToISupports(src);
   if (iface) {
     if (NS_FAILED(iface->QueryInterface(iid, ppArg))) {
       return NS_ERROR_XPC_BAD_CONVERT_JS;
     }
 
     return NS_OK;
   }
 
@@ -3437,19 +3421,18 @@ bool GetDesiredProto(JSContext* aCx, con
   // slow JS_GetProperty call.
   JS::Rooted<JSObject*> newTarget(aCx, &aCallArgs.newTarget().toObject());
   JS::Rooted<JSObject*> originalNewTarget(aCx, newTarget);
   // See whether we have a known DOM constructor here, such that we can take a
   // fast path.
   prototypes::ID protoID = GetProtoIdForNewtarget(newTarget);
   if (protoID == prototypes::id::_ID_Count) {
     // We might still have a cross-compartment wrapper for a known DOM
-    // constructor.  CheckedUnwrapStatic is fine here, because we're looking for
-    // DOM constructors and those can't be cross-origin objects.
-    newTarget = js::CheckedUnwrapStatic(newTarget);
+    // constructor.
+    newTarget = js::CheckedUnwrap(newTarget);
     if (newTarget && newTarget != originalNewTarget) {
       protoID = GetProtoIdForNewtarget(newTarget);
     }
   }
 
   if (protoID != prototypes::id::_ID_Count) {
     ProtoAndIfaceCache& protoAndIfaceCache =
         *GetProtoAndIfaceCache(JS::GetNonCCWObjectGlobal(newTarget));
@@ -3575,22 +3558,18 @@ bool HTMLConstructor(JSContext* aCx, uns
     return Throw(aCx, NS_ERROR_UNEXPECTED);
   }
 
   // Step 2.
 
   // The newTarget might be a cross-compartment wrapper. Get the underlying
   // object so we can do the spec's object-identity checks.  If we ever stop
   // unwrapping here, carefully audit uses of newTarget below!
-  //
-  // Note that the ES spec enforces that newTarget is always a constructor (in
-  // the sense of having a [[Construct]]), so it's not a cross-origin object and
-  // we can use CheckedUnwrapStatic.
   JS::Rooted<JSObject*> newTarget(
-      aCx, js::CheckedUnwrapStatic(&args.newTarget().toObject()));
+      aCx, js::CheckedUnwrap(&args.newTarget().toObject()));
   if (!newTarget) {
     return ThrowErrorMessage(aCx, MSG_ILLEGAL_CONSTRUCTOR);
   }
 
   // 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
@@ -3655,19 +3634,17 @@ bool HTMLConstructor(JSContext* aCx, uns
       cb = HTMLElement_Binding::GetConstructorObject;
     }
 
     // We want to get the constructor from our global's realm, not the
     // caller realm.
     JSAutoRealm ar(aCx, global.Get());
     JS::Rooted<JSObject*> constructor(aCx, cb(aCx));
 
-    // CheckedUnwrapStatic is OK here, since our callee is callable, hence not a
-    // cross-origin object.
-    if (constructor != js::CheckedUnwrapStatic(callee)) {
+    if (constructor != js::CheckedUnwrap(callee)) {
       return ThrowErrorMessage(aCx, MSG_ILLEGAL_CONSTRUCTOR);
     }
   } else {
     if (ns == kNameSpaceID_XHTML) {
       // Step 5.
       // If the definition is for a customized built-in element, the localName
       // should be one of the ones defined in the specification for this
       // interface.
@@ -3690,19 +3667,17 @@ bool HTMLConstructor(JSContext* aCx, uns
     // We want to get the constructor from our global's realm, not the
     // caller realm.
     JSAutoRealm ar(aCx, global.Get());
     JS::Rooted<JSObject*> constructor(aCx, cb(aCx));
     if (!constructor) {
       return false;
     }
 
-    // CheckedUnwrapStatic is OK here, since our callee is callable, hence not a
-    // cross-origin object.
-    if (constructor != js::CheckedUnwrapStatic(callee)) {
+    if (constructor != js::CheckedUnwrap(callee)) {
       return ThrowErrorMessage(aCx, MSG_ILLEGAL_CONSTRUCTOR);
     }
   }
 
   // Step 6.
   JS::Rooted<JSObject*> desiredProto(aCx);
   if (!GetDesiredProto(aCx, args, &desiredProto)) {
     return false;
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -153,32 +153,20 @@ inline nsISupports* UnwrapDOMObjectToISu
 inline bool IsDOMObject(JSObject* obj) {
   return IsDOMClass(js::GetObjectClass(obj));
 }
 
 // There are two valid ways to use UNWRAP_OBJECT: Either obj needs to
 // be a MutableHandle<JSObject*>, or value needs to be a strong-reference
 // smart pointer type (OwningNonNull or RefPtr or nsCOMPtr), in which case obj
 // can be anything that converts to JSObject*.
-//
-// This can't be used with Window, EventTarget, or Location as the "Interface"
-// argument (and will fail a static_assert if you try to do that).  Use
-// UNWRAP_MAYBE_CROSS_ORIGIN_OBJECT to unwrap to those interfaces.
-#define UNWRAP_OBJECT(Interface, obj, value)                        \
-  mozilla::dom::binding_detail::UnwrapObjectWithCrossOriginAsserts< \
-      mozilla::dom::prototypes::id::Interface,                      \
-      mozilla::dom::Interface##_Binding::NativeType>(obj, value)
-
-// UNWRAP_MAYBE_CROSS_ORIGIN_OBJECT is just like UNWRAP_OBJECT but requires a
-// JSContext in a Realm that represents "who is doing the unwrapping?" to
-// properly unwrap the object.
-#define UNWRAP_MAYBE_CROSS_ORIGIN_OBJECT(Interface, obj, value, cx)          \
+#define UNWRAP_OBJECT(Interface, obj, value)                                 \
   mozilla::dom::UnwrapObject<mozilla::dom::prototypes::id::Interface,        \
                              mozilla::dom::Interface##_Binding::NativeType>( \
-      obj, value, cx)
+      obj, value)
 
 // Test whether the given object is an instance of the given interface.
 #define IS_INSTANCE_OF(Interface, obj)                                       \
   mozilla::dom::IsInstanceOf<mozilla::dom::prototypes::id::Interface,        \
                              mozilla::dom::Interface##_Binding::NativeType>( \
       obj)
 
 // Unwrap the given non-wrapper object.  This can be used with any obj that
@@ -202,33 +190,21 @@ inline bool IsDOMObject(JSObject* obj) {
 // MutableHandle<JSObject*>, with an assignment operator that sets the handle to
 // the given object, or U needs to be a strong-reference smart pointer type
 // (OwningNonNull or RefPtr or nsCOMPtr), or the value being stored in "value"
 // must not escape past being tested for falsiness immediately after the
 // UnwrapObjectInternal call.
 //
 // If mayBeWrapper is false, obj can just be a JSObject*, and U anything that a
 // T* can be assigned to.
-//
-// CxType is in practice allowed to be either decltype(nullptr) or JSContext*.
-// If it's decltype(nullptr) we will do a CheckedUnwrapStatic and it's the
-// caller's responsibility to make sure they're not trying to work with Window
-// or Location objects.  Otherwise we'll do a CheckedUnwrapDynamic.  This all
-// only matters if mayBeWrapper is true; if it's false just pass nullptr for
-// the cx arg.
 namespace binding_detail {
-template <class T, bool mayBeWrapper, typename U, typename V, typename CxType>
+template <class T, bool mayBeWrapper, typename U, typename V>
 MOZ_ALWAYS_INLINE nsresult UnwrapObjectInternal(V& obj, U& value,
                                                 prototypes::ID protoID,
-                                                uint32_t protoDepth,
-                                                CxType cx) {
-  static_assert(IsSame<CxType, JSContext*>::value ||
-                    IsSame<CxType, decltype(nullptr)>::value,
-                "Unexpected CxType");
-
+                                                uint32_t protoDepth) {
   /* First check to see whether we have a DOM object */
   const DOMJSClass* domClass = GetDOMClass(obj);
   if (domClass) {
     /* This object is a DOM object.  Double-check that it is safely
        castable to T by checking whether it claims to inherit from the
        class identified by protoID. */
     if (domClass->mInterfaceChain[protoDepth] == protoID) {
       value = UnwrapDOMObject<T>(obj);
@@ -237,49 +213,33 @@ MOZ_ALWAYS_INLINE nsresult UnwrapObjectI
   }
 
   /* Maybe we have a security wrapper or outer window? */
   if (!mayBeWrapper || !js::IsWrapper(obj)) {
     /* Not a DOM object, not a wrapper, just bail */
     return NS_ERROR_XPC_BAD_CONVERT_JS;
   }
 
-  JSObject* unwrappedObj;
-  if (IsSame<CxType, decltype(nullptr)>::value) {
-    unwrappedObj = js::CheckedUnwrapStatic(obj);
-  } else {
-    unwrappedObj =
-        js::CheckedUnwrapDynamic(obj, cx, /* stopAtWindowProxy = */ false);
-  }
+  JSObject* unwrappedObj =
+      js::CheckedUnwrap(obj, /* stopAtWindowProxy = */ false);
   if (!unwrappedObj) {
     return NS_ERROR_XPC_SECURITY_MANAGER_VETO;
   }
-
-  if (IsSame<CxType, decltype(nullptr)>::value) {
-    // We might still have a windowproxy here.  But it shouldn't matter, because
-    // that's not what the caller is looking for, so we're going to fail out
-    // anyway below once we do the recursive call to ourselves with wrapper
-    // unwrapping disabled.
-    MOZ_ASSERT(!js::IsWrapper(unwrappedObj) || js::IsWindowProxy(unwrappedObj));
-  } else {
-    // We shouldn't have a wrapper by now.
-    MOZ_ASSERT(!js::IsWrapper(unwrappedObj));
-  }
-
+  MOZ_ASSERT(!js::IsWrapper(unwrappedObj));
   // Recursive call is OK, because now we're using false for mayBeWrapper and
   // we never reach this code if that boolean is false, so can't keep calling
   // ourselves.
   //
   // Unwrap into a temporary pointer, because in general unwrapping into
   // something of type U might trigger GC (e.g. release the value currently
   // stored in there, with arbitrary consequences) and invalidate the
   // "unwrappedObj" pointer.
   T* tempValue = nullptr;
   nsresult rv = UnwrapObjectInternal<T, false>(unwrappedObj, tempValue, protoID,
-                                               protoDepth, nullptr);
+                                               protoDepth);
   if (NS_SUCCEEDED(rv)) {
     // It's very important to not update "obj" with the "unwrappedObj" value
     // until we know the unwrap has succeeded.  Otherwise, in a situation in
     // which we have an overload of object and primitive we could end up
     // converting to the primitive from the unwrappedObj, whereas we want to do
     // it from the original object.
     obj = unwrappedObj;
     // And now assign to "value"; at this point we don't care if a GC happens
@@ -320,104 +280,73 @@ struct MutableValueHandleWrapper {
 
  private:
   JS::MutableHandle<JS::Value> mHandle;
 };
 
 }  // namespace binding_detail
 
 // UnwrapObject overloads that ensure we have a MutableHandle to keep it alive.
-template <prototypes::ID PrototypeID, class T, typename U, typename CxType>
+template <prototypes::ID PrototypeID, class T, typename U>
 MOZ_ALWAYS_INLINE nsresult UnwrapObject(JS::MutableHandle<JSObject*> obj,
-                                        U& value, CxType cx) {
+                                        U& value) {
   binding_detail::MutableObjectHandleWrapper wrapper(obj);
   return binding_detail::UnwrapObjectInternal<T, true>(
-      wrapper, value, PrototypeID, PrototypeTraits<PrototypeID>::Depth, cx);
+      wrapper, value, PrototypeID, PrototypeTraits<PrototypeID>::Depth);
 }
 
-template <prototypes::ID PrototypeID, class T, typename U, typename CxType>
+template <prototypes::ID PrototypeID, class T, typename U>
 MOZ_ALWAYS_INLINE nsresult UnwrapObject(JS::MutableHandle<JS::Value> obj,
-                                        U& value, CxType cx) {
+                                        U& value) {
   MOZ_ASSERT(obj.isObject());
   binding_detail::MutableValueHandleWrapper wrapper(obj);
   return binding_detail::UnwrapObjectInternal<T, true>(
-      wrapper, value, PrototypeID, PrototypeTraits<PrototypeID>::Depth, cx);
+      wrapper, value, PrototypeID, PrototypeTraits<PrototypeID>::Depth);
 }
 
 // UnwrapObject overloads that ensure we have a strong ref to keep it alive.
-template <prototypes::ID PrototypeID, class T, typename U, typename CxType>
-MOZ_ALWAYS_INLINE nsresult UnwrapObject(JSObject* obj, RefPtr<U>& value,
-                                        CxType cx) {
+template <prototypes::ID PrototypeID, class T, typename U>
+MOZ_ALWAYS_INLINE nsresult UnwrapObject(JSObject* obj, RefPtr<U>& value) {
   return binding_detail::UnwrapObjectInternal<T, true>(
-      obj, value, PrototypeID, PrototypeTraits<PrototypeID>::Depth, cx);
+      obj, value, PrototypeID, PrototypeTraits<PrototypeID>::Depth);
 }
 
-template <prototypes::ID PrototypeID, class T, typename U, typename CxType>
-MOZ_ALWAYS_INLINE nsresult UnwrapObject(JSObject* obj, nsCOMPtr<U>& value,
-                                        CxType cx) {
+template <prototypes::ID PrototypeID, class T, typename U>
+MOZ_ALWAYS_INLINE nsresult UnwrapObject(JSObject* obj, nsCOMPtr<U>& value) {
   return binding_detail::UnwrapObjectInternal<T, true>(
-      obj, value, PrototypeID, PrototypeTraits<PrototypeID>::Depth, cx);
+      obj, value, PrototypeID, PrototypeTraits<PrototypeID>::Depth);
 }
 
-template <prototypes::ID PrototypeID, class T, typename U, typename CxType>
-MOZ_ALWAYS_INLINE nsresult UnwrapObject(JSObject* obj, OwningNonNull<U>& value,
-                                        CxType cx) {
+template <prototypes::ID PrototypeID, class T, typename U>
+MOZ_ALWAYS_INLINE nsresult UnwrapObject(JSObject* obj,
+                                        OwningNonNull<U>& value) {
   return binding_detail::UnwrapObjectInternal<T, true>(
-      obj, value, PrototypeID, PrototypeTraits<PrototypeID>::Depth, cx);
+      obj, value, PrototypeID, PrototypeTraits<PrototypeID>::Depth);
 }
 
 // An UnwrapObject overload that just calls one of the JSObject* ones.
-template <prototypes::ID PrototypeID, class T, typename U, typename CxType>
-MOZ_ALWAYS_INLINE nsresult UnwrapObject(JS::Handle<JS::Value> obj, U& value,
-                                        CxType cx) {
+template <prototypes::ID PrototypeID, class T, typename U>
+MOZ_ALWAYS_INLINE nsresult UnwrapObject(JS::Handle<JS::Value> obj, U& value) {
   MOZ_ASSERT(obj.isObject());
-  return UnwrapObject<PrototypeID, T>(&obj.toObject(), value, cx);
+  return UnwrapObject<PrototypeID, T>(&obj.toObject(), value);
 }
 
-template <prototypes::ID PrototypeID>
-MOZ_ALWAYS_INLINE void AssertStaticUnwrapOK() {
-  static_assert(PrototypeID != prototypes::id::Window,
-                "Can't do static unwrap of WindowProxy; use "
-                "UNWRAP_MAYBE_CROSS_ORIGIN_OBJECT or a cross-origin-object "
-                "aware version of IS_INSTANCE_OF");
-  static_assert(PrototypeID != prototypes::id::EventTarget,
-                "Can't do static unwrap of WindowProxy (which an EventTarget "
-                "might be); use UNWRAP_MAYBE_CROSS_ORIGIN_OBJECT or a "
-                "cross-origin-object aware version of IS_INSTANCE_OF");
-  static_assert(PrototypeID != prototypes::id::Location,
-                "Can't do static unwrap of Location; use "
-                "UNWRAP_MAYBE_CROSS_ORIGIN_OBJECT or a cross-origin-object "
-                "aware version of IS_INSTANCE_OF");
-}
-
-namespace binding_detail {
-// This function is just here so we can do some static asserts in a centralized
-// place instead of putting them in every single UnwrapObject overload.
-template <prototypes::ID PrototypeID, class T, typename U, typename V>
-MOZ_ALWAYS_INLINE nsresult UnwrapObjectWithCrossOriginAsserts(V&& obj,
-                                                              U& value) {
-  AssertStaticUnwrapOK<PrototypeID>();
-  return UnwrapObject<PrototypeID, T>(obj, value, nullptr);
-}
-}  // namespace binding_detail
-
 template <prototypes::ID PrototypeID, class T>
 MOZ_ALWAYS_INLINE bool IsInstanceOf(JSObject* obj) {
-  AssertStaticUnwrapOK<PrototypeID>();
   void* ignored;
   nsresult unwrapped = binding_detail::UnwrapObjectInternal<T, true>(
-      obj, ignored, PrototypeID, PrototypeTraits<PrototypeID>::Depth, nullptr);
+      obj, ignored, PrototypeID, PrototypeTraits<PrototypeID>::Depth);
   return NS_SUCCEEDED(unwrapped);
 }
 
 template <prototypes::ID PrototypeID, class T, typename U>
 MOZ_ALWAYS_INLINE nsresult UnwrapNonWrapperObject(JSObject* obj, U& value) {
   MOZ_ASSERT(!js::IsWrapper(obj));
   return binding_detail::UnwrapObjectInternal<T, false>(
-      obj, value, PrototypeID, PrototypeTraits<PrototypeID>::Depth, nullptr);
+      obj, value, PrototypeID, PrototypeTraits<PrototypeID>::Depth);
 }
 
 MOZ_ALWAYS_INLINE bool IsConvertibleToDictionary(JS::Handle<JS::Value> val) {
   return val.isNullOrUndefined() || val.isObject();
 }
 
 // The items in the protoAndIfaceCache are indexed by the prototypes::id::ID,
 // constructors::id::ID and namedpropertiesobjects::id::ID enums, in that order.
@@ -1157,20 +1086,17 @@ inline bool WrapNewBindingNonWrapperCach
     // before we call JS_WrapValue.
     Maybe<JSAutoRealm> 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)) {
-      // We are working in the Realm of cx and will be producing our reflector
-      // there, so we need to succeed if that realm has access to the scope.
-      scope =
-          js::CheckedUnwrapDynamic(scope, cx, /* stopAtWindowProxy = */ false);
+      scope = js::CheckedUnwrap(scope, /* stopAtWindowProxy = */ false);
       if (!scope) return false;
       ar.emplace(cx, scope);
       if (!JS_WrapObject(cx, &proto)) {
         return false;
       }
     }
 
     MOZ_ASSERT(js::IsObjectInContextCompartment(scope, cx));
@@ -1209,20 +1135,17 @@ inline bool WrapNewBindingNonWrapperCach
     // before we call JS_WrapValue.
     Maybe<JSAutoRealm> 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)) {
-      // We are working in the Realm of cx and will be producing our reflector
-      // there, so we need to succeed if that realm has access to the scope.
-      scope =
-          js::CheckedUnwrapDynamic(scope, cx, /* stopAtWindowProxy = */ false);
+      scope = js::CheckedUnwrap(scope, /* stopAtWindowProxy = */ false);
       if (!scope) return false;
       ar.emplace(cx, scope);
       if (!JS_WrapObject(cx, &proto)) {
         return false;
       }
     }
 
     MOZ_ASSERT(js::IsObjectInContextCompartment(scope, cx));
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -2984,24 +2984,19 @@ class CGCollectJSONAttributesMethod(CGAb
                         { // scope for "temp"
                           $*{getAndDefine}
                         }
                         """,
                         getAndDefine=getAndDefine)
         ret += 'return true;\n'
 
         if needUnwrappedObj:
-            # If we started allowing cross-origin objects here, we'd need to
-            # use CheckedUnwrapDynamic and figure out whether it makes sense.
-            # But in practice no one is trying to add toJSON methods to those,
-            # so let's just guard against it.
-            assert not self.descriptor.isMaybeCrossOriginObject()
             ret= fill(
                 """
-                JS::Rooted<JSObject*> unwrappedObj(cx, js::CheckedUnwrapStatic(obj));
+                JS::Rooted<JSObject*> unwrappedObj(cx, js::CheckedUnwrap(obj));
                 if (!unwrappedObj) {
                   // How did that happen?  We managed to get called with that
                   // object as "this"!  Just give up on sanity.
                   return false;
                 }
 
                 $*{ret}
                 """,
@@ -4371,18 +4366,17 @@ class CastableObjectUnwrapper():
     def __str__(self):
         substitution = self.substitution.copy()
         substitution["codeOnFailure"] %= {
             'securityError': 'rv == NS_ERROR_XPC_SECURITY_MANAGER_VETO'
         }
         return fill(
             """
             {
-              // Our JSContext should be in the right global to do unwrapping in.
-              nsresult rv = UnwrapObject<${protoID}, ${type}>(${mutableSource}, ${target}, cx);
+              nsresult rv = UnwrapObject<${protoID}, ${type}>(${mutableSource}, ${target});
               if (NS_FAILED(rv)) {
                 $*{codeOnFailure}
               }
             }
             """,
             **substitution)
 
 
@@ -5484,18 +5478,18 @@ def getJSToNativeConversionInfo(type, de
         #    the JS implementation.  But if the JS implementation returned
         #    a page-side Promise (which is a totally sane thing to do, and
         #    in fact the right thing to do given that this return value is
         #    going right to content script) then we don't want to
         #    Promise.resolve with our current compartment Promise, because
         #    that will wrap it up in a chrome-side Promise, which is
         #    decidedly _not_ what's desired here.  So in that case we
         #    should really unwrap the return value and use the global of
-        #    the result.  CheckedUnwrapStatic should be good enough for that;
-        #    if it fails, then we're failing unwrap while in a
+        #    the result.  CheckedUnwrap should be good enough for that; if
+        #    it fails, then we're failing unwrap while in a
         #    system-privileged compartment, so presumably we have a dead
         #    object wrapper.  Just error out.  Do NOT fall back to using
         #    the current compartment instead: that will return a
         #    system-privileged rejected (because getting .then inside
         #    resolve() failed) Promise to the caller, which they won't be
         #    able to touch.  That's not helpful.  If we error out, on the
         #    other hand, they will get a content-side rejected promise.
         #    Same thing if the value returned is not even an object.
@@ -5506,17 +5500,17 @@ def getJSToNativeConversionInfo(type, de
             # which we don't really want here.
             assert exceptionCode == "aRv.Throw(NS_ERROR_UNEXPECTED);\nreturn nullptr;\n"
             getPromiseGlobal = fill(
                 """
                 if (!$${val}.isObject()) {
                   aRv.ThrowTypeError<MSG_NOT_OBJECT>(NS_LITERAL_STRING("${sourceDescription}"));
                   return nullptr;
                 }
-                JSObject* unwrappedVal = js::CheckedUnwrapStatic(&$${val}.toObject());
+                JSObject* unwrappedVal = js::CheckedUnwrap(&$${val}.toObject());
                 if (!unwrappedVal) {
                   // A slight lie, but not much of one, for a dead object wrapper.
                   aRv.ThrowTypeError<MSG_NOT_OBJECT>(NS_LITERAL_STRING("${sourceDescription}"));
                   return nullptr;
                 }
                 globalObj = JS::GetNonCCWObjectGlobal(unwrappedVal);
                 """,
                 sourceDescription=sourceDescription)
@@ -7748,26 +7742,21 @@ class CGPerSignatureCall(CGThing):
         elif descriptor.interface.isJSImplemented():
             if not idlNode.isStatic():
                 needsUnwrap = True
                 needsUnwrappedVar = True
                 argsPost.append("(unwrappedObj ? js::GetNonCCWObjectRealm(*unwrappedObj) : js::GetContextRealm(cx))")
         elif needScopeObject(returnType, arguments, self.extendedAttributes,
                              descriptor.wrapperCache, True,
                              idlNode.getExtendedAttribute("StoreInSlot")):
-            # If we ever end up with APIs like this on cross-origin objects,
-            # figure out how the CheckedUnwrapDynamic bits should work.  Chances
-            # are, just calling it with "cx" is fine...  For now, though, just
-            # assert that it does not matter.
-            assert not descriptor.isMaybeCrossOriginObject()
             # The scope object should always be from the relevant
             # global.  Make sure to unwrap it as needed.
             cgThings.append(CGGeneric(dedent(
                 """
-                JS::Rooted<JSObject*> unwrappedObj(cx, js::CheckedUnwrapStatic(obj));
+                JS::Rooted<JSObject*> unwrappedObj(cx, js::CheckedUnwrap(obj));
                 // Caller should have ensured that "obj" can be unwrapped already.
                 MOZ_DIAGNOSTIC_ASSERT(unwrappedObj);
                 """)))
             argsPre.append("unwrappedObj")
 
         if needsUnwrap and needsUnwrappedVar:
             # We cannot assign into obj because it's a Handle, not a
             # MutableHandle, so we need a separate Rooted.
@@ -7832,19 +7821,17 @@ class CGPerSignatureCall(CGThing):
         if needsUnwrap:
             # Something depends on having the unwrapped object, so unwrap it now.
             xraySteps = []
             # XXXkhuey we should be able to MOZ_ASSERT that ${obj} is
             # not null.
             xraySteps.append(
                 CGGeneric(fill(
                     """
-                    // Since our object is an Xray, we can just CheckedUnwrapStatic:
-                    // we know Xrays have no dynamic unwrap behavior.
-                    ${obj} = js::CheckedUnwrapStatic(${obj});
+                    ${obj} = js::CheckedUnwrap(${obj});
                     if (!${obj}) {
                       return false;
                     }
                     """,
                     obj=unwrappedVar)))
             if isConstructor:
                 # If we're called via an xray, we need to enter the underlying
                 # object's compartment and then wrap up all of our arguments into
--- a/dom/bindings/Date.h
+++ b/dom/bindings/Date.h
@@ -28,17 +28,17 @@ class Date {
   // Returns an integer in the range [-8.64e15, +8.64e15] (-0 excluded), *or*
   // returns NaN.  DO NOT ASSUME THIS IS FINITE!
   double ToDouble() const { return mMsecSinceEpoch.toDouble(); }
 
   void SetTimeStamp(JS::ClippedTime aMilliseconds) {
     mMsecSinceEpoch = aMilliseconds;
   }
 
-  // Can return false if unboxing fails.  This will NOT throw;
+  // Can return false if CheckedUnwrap fails.  This will NOT throw;
   // callers should do it as needed.
   bool SetTimeStamp(JSContext* aCx, JSObject* aObject);
 
   bool ToDateObject(JSContext* aCx, JS::MutableHandle<JS::Value> aRval) const;
 
  private:
   JS::ClippedTime mMsecSinceEpoch;
 };
--- a/dom/bindings/Exceptions.cpp
+++ b/dom/bindings/Exceptions.cpp
@@ -37,21 +37,19 @@ static void ThrowExceptionValueIfSafe(JS
   if (!exnVal.isObject()) {
     JS_SetPendingException(aCx, exnVal);
     return;
   }
 
   JS::Rooted<JSObject*> exnObj(aCx, &exnVal.toObject());
   MOZ_ASSERT(js::IsObjectInContextCompartment(exnObj, aCx),
              "exnObj needs to be in the right compartment for the "
-             "CheckedUnwrapDynamic thing to make sense");
+             "CheckedUnwrap thing to make sense");
 
-  // aCx's current Realm is where we're throwing, so using it in the
-  // CheckedUnwrapDynamic check makes sense.
-  if (js::CheckedUnwrapDynamic(exnObj, aCx)) {
+  if (js::CheckedUnwrap(exnObj)) {
     // This is an object we're allowed to work with, so just go ahead and throw
     // it.
     JS_SetPendingException(aCx, exnVal);
     return;
   }
 
   // We could probably Throw(aCx, NS_ERROR_UNEXPECTED) here, and it would do the
   // right thing due to there not being an existing exception on the runtime at
--- a/dom/bindings/WebIDLGlobalNameHash.cpp
+++ b/dom/bindings/WebIDLGlobalNameHash.cpp
@@ -68,40 +68,34 @@ bool WebIDLGlobalNameHash::DefineIfEnabl
   if (!entry) {
     *aFound = false;
     return true;
   }
 
   *aFound = true;
 
   ConstructorEnabled checkEnabledForScope = entry->mEnabled;
-  // We do the enabled check on the current Realm of aCx, but for the
+  // We do the enabled check on the current compartment of aCx, but for the
   // actual object we pass in the underlying object in the Xray case.  That
   // way the callee can decide whether to allow access based on the caller
   // or the window being touched.
-  //
-  // Using aCx to represent the current Realm for CheckedUnwrapDynamic
-  // purposes is OK here, because that's the Realm where we plan to do
-  // our property-defining.
   JS::Rooted<JSObject*> global(
-      aCx,
-      js::CheckedUnwrapDynamic(aObj, aCx, /* stopAtWindowProxy = */ false));
+      aCx, js::CheckedUnwrap(aObj, /* stopAtWindowProxy = */ false));
   if (!global) {
     return Throw(aCx, NS_ERROR_DOM_SECURITY_ERR);
   }
 
   {
     // It's safe to pass "&global" here, because we've already unwrapped it, but
     // for general sanity better to not have debug code even having the
     // appearance of mutating things that opt code uses.
 #ifdef DEBUG
     JS::Rooted<JSObject*> temp(aCx, global);
     DebugOnly<nsGlobalWindowInner*> win;
-    MOZ_ASSERT(NS_SUCCEEDED(
-        UNWRAP_MAYBE_CROSS_ORIGIN_OBJECT(Window, &temp, win, aCx)));
+    MOZ_ASSERT(NS_SUCCEEDED(UNWRAP_OBJECT(Window, &temp, win)));
 #endif
   }
 
   if (checkEnabledForScope && !checkEnabledForScope(aCx, global)) {
     return true;
   }
 
   // The DOM constructor resolve machinery interacts with Xrays in tricky
--- a/dom/bindings/test/TestFunctions.cpp
+++ b/dom/bindings/test/TestFunctions.cpp
@@ -96,17 +96,17 @@ already_AddRefed<Promise> TestFunctions:
 int32_t TestFunctions::One() const { return 1; }
 
 int32_t TestFunctions::Two() const { return 2; }
 
 bool TestFunctions::ObjectFromAboutBlank(JSContext* aCx, JSObject* aObj) {
   // We purposefully don't use WindowOrNull here, because we want to
   // demonstrate the incorrect behavior we get, not just fail some asserts.
   RefPtr<nsGlobalWindowInner> win;
-  UNWRAP_MAYBE_CROSS_ORIGIN_OBJECT(Window, aObj, win, aCx);
+  UNWRAP_OBJECT(Window, aObj, win);
   if (!win) {
     return false;
   }
 
   Document* doc = win->GetDoc();
   if (!doc) {
     return false;
   }
--- a/dom/media/webaudio/AudioContext.cpp
+++ b/dom/media/webaudio/AudioContext.cpp
@@ -540,18 +540,17 @@ already_AddRefed<Promise> AudioContext::
     const Optional<OwningNonNull<DecodeErrorCallback> >& aFailureCallback,
     ErrorResult& aRv) {
   nsCOMPtr<nsIGlobalObject> parentObject = do_QueryInterface(GetParentObject());
   RefPtr<Promise> promise;
   AutoJSAPI jsapi;
   jsapi.Init();
   JSContext* cx = jsapi.cx();
 
-  // CheckedUnwrapStatic is OK, since we know we have an ArrayBuffer.
-  JS::Rooted<JSObject*> obj(cx, js::CheckedUnwrapStatic(aBuffer.Obj()));
+  JS::Rooted<JSObject*> obj(cx, js::CheckedUnwrap(aBuffer.Obj()));
   if (!obj) {
     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
     return nullptr;
   }
 
   JSAutoRealm ar(cx, obj);
 
   promise = Promise::Create(parentObject, aRv);
--- a/dom/media/webaudio/AudioWorkletGlobalScope.cpp
+++ b/dom/media/webaudio/AudioWorkletGlobalScope.cpp
@@ -69,19 +69,18 @@ void AudioWorkletGlobalScope::RegisterPr
     aRv.ThrowDOMException(
         NS_ERROR_DOM_NOT_SUPPORTED_ERR,
         NS_LITERAL_CSTRING(
             "Argument 1 of AudioWorkletGlobalScope.registerProcessor "
             "is invalid: a class with the same name is already registered."));
     return;
   }
 
-  // We know processorConstructor is callable, so not a WindowProxy or Location.
   JS::Rooted<JSObject*> constructorUnwrapped(
-      aCx, js::CheckedUnwrapStatic(processorConstructor));
+      aCx, js::CheckedUnwrap(processorConstructor));
   if (!constructorUnwrapped) {
     // If the caller's compartment does not have permission to access the
     // unwrapped constructor then throw.
     aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
     return;
   }
 
   /**
--- a/dom/plugins/base/nsJSNPRuntime.cpp
+++ b/dom/plugins/base/nsJSNPRuntime.cpp
@@ -517,19 +517,17 @@ bool JSValToNPVariant(NPP npp, JSContext
   // element has since been adopted into a new document. We don't bother
   // transplanting the plugin objects, and just do a unwrap with security
   // checks if we encounter one of them as an argument. If the unwrap fails,
   // we run with the original wrapped object, since sometimes there are
   // legitimate cases where a security wrapper ends up here (for example,
   // Location objects, which are _always_ behind security wrappers).
   JS::Rooted<JSObject *> obj(cx, &val.toObject());
   JS::Rooted<JSObject *> global(cx);
-  // CheckedUnwrapStatic is fine here; if we get a Location or WindowProxy,
-  // we'll just use the current global instead.
-  obj = js::CheckedUnwrapStatic(obj);
+  obj = js::CheckedUnwrap(obj);
   if (obj) {
     global = JS::GetNonCCWObjectGlobal(obj);
   } else {
     obj = &val.toObject();
     global = JS::CurrentGlobalOrNull(cx);
   }
 
   NPObject *npobj = nsJSObjWrapper::GetNewOrUsed(npp, obj, global);
@@ -1071,20 +1069,17 @@ NPObject *nsJSObjWrapper::GetNewOrUsed(N
 //
 // Because this function unwraps, its return value must be wrapped for the cx
 // compartment for callers that plan to hold onto the result or do anything
 // substantial with it.
 static JSObject *GetNPObjectWrapper(JSContext *cx, JS::Handle<JSObject *> aObj,
                                     bool wrapResult = true) {
   JS::Rooted<JSObject *> obj(cx, aObj);
 
-  // We can't have WindowProxy or Location objects with NP object wrapper
-  // objects on their proto chain, since they have immutable prototypes.  So
-  // CheckedUnwrapStatic is ok here.
-  while (obj && (obj = js::CheckedUnwrapStatic(obj))) {
+  while (obj && (obj = js::CheckedUnwrap(obj))) {
     if (nsNPObjWrapper::IsWrapper(obj)) {
       if (wrapResult && !JS_WrapObject(cx, &obj)) {
         return nullptr;
       }
       return obj;
     }
 
     JSAutoRealm ar(cx, obj);
--- a/dom/promise/PromiseDebugging.cpp
+++ b/dom/promise/PromiseDebugging.cpp
@@ -68,18 +68,17 @@ class FlushRejections : public Cancelabl
 };
 
 /* static */ MOZ_THREAD_LOCAL(bool) FlushRejections::sDispatched;
 
 /* static */ void PromiseDebugging::GetState(
     GlobalObject& aGlobal, JS::Handle<JSObject*> aPromise,
     PromiseDebuggingStateHolder& aState, ErrorResult& aRv) {
   JSContext* cx = aGlobal.Context();
-  // CheckedUnwrapStatic is fine, since we're looking for promises only.
-  JS::Rooted<JSObject*> obj(cx, js::CheckedUnwrapStatic(aPromise));
+  JS::Rooted<JSObject*> obj(cx, js::CheckedUnwrap(aPromise));
   if (!obj || !JS::IsPromiseObject(obj)) {
     aRv.ThrowTypeError<MSG_IS_NOT_PROMISE>(
         NS_LITERAL_STRING("Argument of PromiseDebugging.getState"));
     return;
   }
   switch (JS::GetPromiseState(obj)) {
     case JS::PromiseState::Pending:
       aState.mState = PromiseDebuggingState::Pending;
@@ -95,62 +94,58 @@ class FlushRejections : public Cancelabl
   }
 }
 
 /* static */ void PromiseDebugging::GetPromiseID(GlobalObject& aGlobal,
                                                  JS::Handle<JSObject*> aPromise,
                                                  nsString& aID,
                                                  ErrorResult& aRv) {
   JSContext* cx = aGlobal.Context();
-  // CheckedUnwrapStatic is fine, since we're looking for promises only.
-  JS::Rooted<JSObject*> obj(cx, js::CheckedUnwrapStatic(aPromise));
+  JS::Rooted<JSObject*> obj(cx, js::CheckedUnwrap(aPromise));
   if (!obj || !JS::IsPromiseObject(obj)) {
     aRv.ThrowTypeError<MSG_IS_NOT_PROMISE>(
         NS_LITERAL_STRING("Argument of PromiseDebugging.getState"));
     return;
   }
   uint64_t promiseID = JS::GetPromiseID(obj);
   aID = sIDPrefix;
   aID.AppendInt(promiseID);
 }
 
 /* static */ void PromiseDebugging::GetAllocationStack(
     GlobalObject& aGlobal, JS::Handle<JSObject*> aPromise,
     JS::MutableHandle<JSObject*> aStack, ErrorResult& aRv) {
   JSContext* cx = aGlobal.Context();
-  // CheckedUnwrapStatic is fine, since we're looking for promises only.
-  JS::Rooted<JSObject*> obj(cx, js::CheckedUnwrapStatic(aPromise));
+  JS::Rooted<JSObject*> obj(cx, js::CheckedUnwrap(aPromise));
   if (!obj || !JS::IsPromiseObject(obj)) {
     aRv.ThrowTypeError<MSG_IS_NOT_PROMISE>(
         NS_LITERAL_STRING("Argument of PromiseDebugging.getAllocationStack"));
     return;
   }
   aStack.set(JS::GetPromiseAllocationSite(obj));
 }
 
 /* static */ void PromiseDebugging::GetRejectionStack(
     GlobalObject& aGlobal, JS::Handle<JSObject*> aPromise,
     JS::MutableHandle<JSObject*> aStack, ErrorResult& aRv) {
   JSContext* cx = aGlobal.Context();
-  // CheckedUnwrapStatic is fine, since we're looking for promises only.
-  JS::Rooted<JSObject*> obj(cx, js::CheckedUnwrapStatic(aPromise));
+  JS::Rooted<JSObject*> obj(cx, js::CheckedUnwrap(aPromise));
   if (!obj || !JS::IsPromiseObject(obj)) {
     aRv.ThrowTypeError<MSG_IS_NOT_PROMISE>(
         NS_LITERAL_STRING("Argument of PromiseDebugging.getRejectionStack"));
     return;
   }
   aStack.set(JS::GetPromiseResolutionSite(obj));
 }
 
 /* static */ void PromiseDebugging::GetFullfillmentStack(
     GlobalObject& aGlobal, JS::Handle<JSObject*> aPromise,
     JS::MutableHandle<JSObject*> aStack, ErrorResult& aRv) {
   JSContext* cx = aGlobal.Context();
-  // CheckedUnwrapStatic is fine, since we're looking for promises only.
-  JS::Rooted<JSObject*> obj(cx, js::CheckedUnwrapStatic(aPromise));
+  JS::Rooted<JSObject*> obj(cx, js::CheckedUnwrap(aPromise));
   if (!obj || !JS::IsPromiseObject(obj)) {
     aRv.ThrowTypeError<MSG_IS_NOT_PROMISE>(
         NS_LITERAL_STRING("Argument of PromiseDebugging.getFulfillmentStack"));
     return;
   }
   aStack.set(JS::GetPromiseResolutionSite(obj));
 }
 
--- a/dom/workers/WorkerScope.cpp
+++ b/dom/workers/WorkerScope.cpp
@@ -871,21 +871,18 @@ void WorkerDebuggerGlobalScope::CreateSa
 
 void WorkerDebuggerGlobalScope::LoadSubScript(
     JSContext* aCx, const nsAString& aURL,
     const Optional<JS::Handle<JSObject*>>& aSandbox, ErrorResult& aRv) {
   mWorkerPrivate->AssertIsOnWorkerThread();
 
   Maybe<JSAutoRealm> ar;
   if (aSandbox.WasPassed()) {
-    // We only care about worker debugger sandbox objects here, so
-    // CheckedUnwrapStatic is fine.
-    JS::Rooted<JSObject*> sandbox(aCx,
-                                  js::CheckedUnwrapStatic(aSandbox.Value()));
-    if (!sandbox || !IsWorkerDebuggerSandbox(sandbox)) {
+    JS::Rooted<JSObject*> sandbox(aCx, js::CheckedUnwrap(aSandbox.Value()));
+    if (!IsWorkerDebuggerSandbox(sandbox)) {
       aRv.Throw(NS_ERROR_INVALID_ARG);
       return;
     }
 
     ar.emplace(aCx, sandbox);
   }
 
   nsTArray<nsString> urls;
--- a/dom/xbl/nsXBLProtoImplField.cpp
+++ b/dom/xbl/nsXBLProtoImplField.cpp
@@ -136,20 +136,17 @@ static bool InstallXBLField(JSContext* c
   //
   // FieldAccessorGuard already determined whether |thisObj| was acceptable as
   // |this| in terms of not throwing a TypeError.  Assert this for good measure.
   MOZ_ASSERT(ValueHasISupportsPrivate(cx, JS::ObjectValue(*thisObj)));
 
   // But there are some cases where we must accept |thisObj| but not install a
   // property on it, or otherwise touch it.  Hence this split of |this|-vetting
   // duties.
-  //
-  // OK to use ReflectorToISupportsStatic, because we only care about nodes
-  // here.
-  nsCOMPtr<nsISupports> native = xpc::ReflectorToISupportsStatic(thisObj);
+  nsCOMPtr<nsISupports> native = xpc::UnwrapReflectorToISupports(thisObj);
   if (!native) {
     // Looks like whatever |thisObj| is it's not our nsIContent.  It might well
     // be the proto our binding installed, however, where the private is the
     // nsXBLDocumentInfo, so just baul out quietly.  Do NOT throw an exception
     // here.
     //
     // We could make this stricter by checking the class maybe, but whatever.
     return true;
--- a/js/ipc/WrapperOwner.cpp
+++ b/js/ipc/WrapperOwner.cpp
@@ -1029,19 +1029,17 @@ bool WrapperOwner::ok(JSContext* cx, con
   }
   return result.succeed();
 }
 
 // CPOWs can have a tag string attached to them, originating in the local
 // process from this function.  It's sent with the CPOW to the remote process,
 // where it can be fetched with Components.utils.getCrossProcessWrapperTag.
 static nsCString GetRemoteObjectTag(JS::Handle<JSObject*> obj) {
-  // OK to use ReflectorToISupportsStatic, because we only care about docshells
-  // and documents here.
-  if (nsCOMPtr<nsISupports> supports = xpc::ReflectorToISupportsStatic(obj)) {
+  if (nsCOMPtr<nsISupports> supports = xpc::UnwrapReflectorToISupports(obj)) {
     nsCOMPtr<nsIDocShellTreeItem> treeItem(do_QueryInterface(supports));
     if (treeItem) {
       return NS_LITERAL_CSTRING("ContentDocShellTreeItem");
     }
 
     nsCOMPtr<dom::Document> doc(do_QueryInterface(supports));
     if (doc) {
       return NS_LITERAL_CSTRING("ContentDocument");
--- a/js/public/Wrapper.h
+++ b/js/public/Wrapper.h
@@ -126,27 +126,16 @@ class JS_FRIEND_API Wrapper : public For
  public:
   explicit constexpr Wrapper(unsigned aFlags, bool aHasPrototype = false,
                              bool aHasSecurityPolicy = false)
       : ForwardingProxyHandler(&family, aHasPrototype, aHasSecurityPolicy),
         mFlags(aFlags) {}
 
   virtual bool finalizeInBackground(const Value& priv) const override;
 
-  /**
-   * A hook subclasses can override to implement CheckedUnwrapDynamic
-   * behavior.  The JSContext represents the "who is trying to unwrap?" Realm.
-   * The JSObject is the wrapper that the caller is trying to unwrap.
-   */
-  virtual bool dynamicCheckedUnwrapAllowed(HandleObject obj,
-                                           JSContext* cx) const {
-    MOZ_ASSERT(hasSecurityPolicy(), "Why are you asking?");
-    return false;
-  }
-
   using BaseProxyHandler::Action;
 
   enum Flags { CROSS_COMPARTMENT = 1 << 0, LAST_USED_FLAG = CROSS_COMPARTMENT };
 
   static JSObject* New(JSContext* cx, JSObject* obj, const Wrapper* handler,
                        const WrapperOptions& options = WrapperOptions());
 
   static JSObject* Renew(JSObject* existing, JSObject* obj,
@@ -393,76 +382,32 @@ inline bool IsCrossCompartmentWrapper(co
 //
 // ExposeToActiveJS is called on wrapper targets to allow gray marking
 // assertions to work while an incremental GC is in progress, but this means
 // that this cannot be called from the GC or off the main thread.
 JS_FRIEND_API JSObject* UncheckedUnwrap(JSObject* obj,
                                         bool stopAtWindowProxy = true,
                                         unsigned* flagsp = nullptr);
 
-// Given a JSObject, returns that object stripped of wrappers, except
-// WindowProxy wrappers.  At each stage, the wrapper has the opportunity to veto
-// the unwrap. Null is returned if there are security wrappers that can't be
-// unwrapped.
-//
-// This does a static-only unwrap check: it basically checks whether _all_
-// globals in the wrapper's source compartment should be able to access the
-// wrapper target.  This won't necessarily return the right thing for the HTML
-// spec's cross-origin objects (WindowProxy and Location), but is fine to use
-// when failure to unwrap one of those objects wouldn't be a problem.  For
-// example, if you want to test whether your target object is a specific class
-// that's not WindowProxy or Location, you can use this.
+// Given a JSObject, returns that object stripped of wrappers. At each stage,
+// the security wrapper has the opportunity to veto the unwrap. If
+// stopAtWindowProxy is true, then this returns the WindowProxy if it was
+// previously wrapped.
 //
 // ExposeToActiveJS is called on wrapper targets to allow gray marking
 // assertions to work while an incremental GC is in progress, but this means
 // that this cannot be called from the GC or off the main thread.
-JS_FRIEND_API JSObject* CheckedUnwrapStatic(JSObject* obj);
-
-// Old CheckedUnwrap API that we would like to remove once we convert all
-// callers to CheckedUnwrapStatic or CheckedUnwrapDynamic.  If stopAtWindowProxy
-// is true, then this returns the WindowProxy if a WindowProxy is encountered;
-// otherwise it will unwrap the WindowProxy and return a Window.
 JS_FRIEND_API JSObject* CheckedUnwrap(JSObject* obj,
                                       bool stopAtWindowProxy = true);
 
 // Unwrap only the outermost security wrapper, with the same semantics as
 // above. This is the checked version of Wrapper::wrappedObject.
 JS_FRIEND_API JSObject* UnwrapOneChecked(JSObject* obj,
                                          bool stopAtWindowProxy = true);
 
-// Given a JSObject, returns that object stripped of wrappers. At each stage,
-// the security wrapper has the opportunity to veto the unwrap. If
-// stopAtWindowProxy is true, then this returns the WindowProxy if it was
-// previously wrapped.  Null is returned if there are security wrappers that
-// can't be unwrapped.
-//
-// ExposeToActiveJS is called on wrapper targets to allow gray marking
-// assertions to work while an incremental GC is in progress, but this means
-// that this cannot be called from the GC or off the main thread.
-//
-// The JSContext argument will be used for dynamic checks (needed by WindowProxy
-// and Location) and should represent the Realm doing the unwrapping.  It is not
-// used to throw exceptions; this function never throws.
-//
-// This function may be able to GC (and the static analysis definitely thinks it
-// can), but it still takes a JSObject* argument, because some of its callers
-// would actually have a bit of a hard time producing a Rooted.  And it ends up
-// having to root internally anyway, because it wants to use the value in a loop
-// and you can't assign to a HandleObject.  What this means is that callers who
-// plan to use the argument object after they have called this function will
-// need to root it to avoid hazard failures, even though this function doesn't
-// require a Handle.
-JS_FRIEND_API JSObject* CheckedUnwrapDynamic(JSObject* obj, JSContext* cx,
-                                             bool stopAtWindowProxy = true);
-
-// Unwrap only the outermost security wrapper, with the same semantics as
-// above. This is the checked version of Wrapper::wrappedObject.
-JS_FRIEND_API JSObject* UnwrapOneCheckedDynamic(HandleObject obj, JSContext* cx,
-                                                bool stopAtWindowProxy = true);
-
 // Given a JSObject, returns that object stripped of wrappers. This returns the
 // WindowProxy if it was previously wrapped.
 //
 // ExposeToActiveJS is not called on wrapper targets so this can be called from
 // the GC or off the main thread.
 JS_FRIEND_API JSObject* UncheckedUnwrapWithoutExpose(JSObject* obj);
 
 void ReportAccessDenied(JSContext* cx);
--- a/js/src/proxy/Wrapper.cpp
+++ b/js/src/proxy/Wrapper.cpp
@@ -350,22 +350,16 @@ JS_FRIEND_API JSObject* js::UncheckedUnw
     wrapped = Wrapper::wrappedObject(wrapped);
   }
   if (flagsp) {
     *flagsp = flags;
   }
   return wrapped;
 }
 
-JS_FRIEND_API JSObject* js::CheckedUnwrapStatic(JSObject* obj) {
-  // For now, just forward to the old API.  Once we remove it, we can
-  // inline it here, without the stopAtWindowProxy bits.
-  return CheckedUnwrap(obj);
-}
-
 JS_FRIEND_API JSObject* js::CheckedUnwrap(JSObject* obj,
                                           bool stopAtWindowProxy) {
   while (true) {
     JSObject* wrapper = obj;
     obj = UnwrapOneChecked(obj, stopAtWindowProxy);
     if (!obj || obj == wrapper) {
       return obj;
     }
@@ -381,52 +375,16 @@ JS_FRIEND_API JSObject* js::UnwrapOneChe
       MOZ_UNLIKELY(stopAtWindowProxy && IsWindowProxy(obj))) {
     return obj;
   }
 
   const Wrapper* handler = Wrapper::wrapperHandler(obj);
   return handler->hasSecurityPolicy() ? nullptr : Wrapper::wrappedObject(obj);
 }
 
-JS_FRIEND_API JSObject* js::CheckedUnwrapDynamic(JSObject* obj, JSContext* cx,
-                                                 bool stopAtWindowProxy) {
-  RootedObject wrapper(cx, obj);
-  while (true) {
-    JSObject* unwrapped =
-        UnwrapOneCheckedDynamic(wrapper, cx, stopAtWindowProxy);
-    if (!unwrapped || unwrapped == wrapper) {
-      return wrapper;
-    }
-    wrapper = unwrapped;
-  }
-}
-
-JS_FRIEND_API JSObject* js::UnwrapOneCheckedDynamic(HandleObject obj,
-                                                    JSContext* cx,
-                                                    bool stopAtWindowProxy) {
-  MOZ_ASSERT(!JS::RuntimeHeapIsCollecting());
-  MOZ_ASSERT(CurrentThreadCanAccessRuntime(obj->runtimeFromAnyThread()));
-  // We should know who's asking.
-  MOZ_ASSERT(cx);
-  MOZ_ASSERT(cx->realm());
-
-  if (!obj->is<WrapperObject>() ||
-      MOZ_UNLIKELY(stopAtWindowProxy && IsWindowProxy(obj))) {
-    return obj;
-  }
-
-  const Wrapper* handler = Wrapper::wrapperHandler(obj);
-  if (!handler->hasSecurityPolicy() ||
-      handler->dynamicCheckedUnwrapAllowed(obj, cx)) {
-    return Wrapper::wrappedObject(obj);
-  }
-
-  return nullptr;
-}
-
 void js::ReportAccessDenied(JSContext* cx) {
   JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
                             JSMSG_OBJECT_ACCESS_DENIED);
 }
 
 const char Wrapper::family = 0;
 const Wrapper Wrapper::singleton((unsigned)0);
 const Wrapper Wrapper::singletonWithPrototype((unsigned)0, true);
--- a/js/src/vm/Debugger-inl.h
+++ b/js/src/vm/Debugger-inl.h
@@ -119,17 +119,16 @@ inline js::Debugger* js::DebuggerObject:
   return Debugger::fromJSObject(dbgobj);
 }
 
 inline js::PromiseObject* js::DebuggerObject::promise() const {
   MOZ_ASSERT(isPromise());
 
   JSObject* referent = this->referent();
   if (IsCrossCompartmentWrapper(referent)) {
-    // We know we have a Promise here, so CheckedUnwrapStatic is fine.
-    referent = CheckedUnwrapStatic(referent);
+    referent = CheckedUnwrap(referent);
     MOZ_ASSERT(referent);
   }
 
   return &referent->as<PromiseObject>();
 }
 
 #endif /* vm_Debugger_inl_h */
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -3762,26 +3762,25 @@ GlobalObject* Debugger::unwrapDebuggeeAr
     RootedValue rv(cx, v);
     if (!unwrapDebuggeeValue(cx, &rv)) {
       return nullptr;
     }
     obj = &rv.toObject();
   }
 
   // If we have a cross-compartment wrapper, dereference as far as is secure.
-  //
-  // Since we're dealing with globals, we may have a WindowProxy here.  So we
-  // have to make sure to do a dynamic unwrap, and we want to unwrap the
-  // WindowProxy too, if we have one.
-  obj = CheckedUnwrapDynamic(obj, cx, /* stopAtWindowProxy = */ false);
+  obj = CheckedUnwrap(obj);
   if (!obj) {
     ReportAccessDenied(cx);
     return nullptr;
   }
 
+  // If that produced a WindowProxy, get the Window (global).
+  obj = ToWindowIfWindowProxy(obj);
+
   // If that didn't produce a global object, it's an error.
   if (!obj->is<GlobalObject>()) {
     JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
                               JSMSG_UNEXPECTED_TYPE, "argument",
                               "not a global object");
     return nullptr;
   }
 
@@ -9377,34 +9376,32 @@ static DebuggerObject* DebuggerObject_ch
   RootedObject obj(cx, DebuggerObject_checkThis(cx, args, fnname));           \
   if (!obj) return false;                                                     \
   Debugger* dbg = Debugger::fromChildJSObject(obj);                           \
   obj = (JSObject*)obj->as<NativeObject>().getPrivate();                      \
   MOZ_ASSERT(obj)
 
 #define THIS_DEBUGOBJECT_PROMISE(cx, argc, vp, fnname, args, obj)             \
   THIS_DEBUGOBJECT_REFERENT(cx, argc, vp, fnname, args, obj);                 \
-  /* We only care about promises, so CheckedUnwrapStatic is OK. */            \
-  obj = CheckedUnwrapStatic(obj);                                             \
+  obj = CheckedUnwrap(obj);                                                   \
   if (!obj) {                                                                 \
     ReportAccessDenied(cx);                                                   \
     return false;                                                             \
   }                                                                           \
   if (!obj->is<PromiseObject>()) {                                            \
     JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,                   \
                               JSMSG_NOT_EXPECTED_TYPE, "Debugger", "Promise", \
                               obj->getClass()->name);                         \
     return false;                                                             \
   }                                                                           \
   Rooted<PromiseObject*> promise(cx, &obj->as<PromiseObject>());
 
 #define THIS_DEBUGOBJECT_OWNER_PROMISE(cx, argc, vp, fnname, args, dbg, obj)  \
   THIS_DEBUGOBJECT_OWNER_REFERENT(cx, argc, vp, fnname, args, dbg, obj);      \
-  /* We only care about promises, so CheckedUnwrapStatic is OK. */            \
-  obj = CheckedUnwrapStatic(obj);                                             \
+  obj = CheckedUnwrap(obj);                                                   \
   if (!obj) {                                                                 \
     ReportAccessDenied(cx);                                                   \
     return false;                                                             \
   }                                                                           \
   if (!obj->is<PromiseObject>()) {                                            \
     JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,                   \
                               JSMSG_NOT_EXPECTED_TYPE, "Debugger", "Promise", \
                               obj->getClass()->name);                         \
@@ -10648,18 +10645,17 @@ bool DebuggerObject::isGlobal() const { 
 bool DebuggerObject::isScriptedProxy() const {
   return js::IsScriptedProxy(referent());
 }
 
 bool DebuggerObject::isPromise() const {
   JSObject* referent = this->referent();
 
   if (IsCrossCompartmentWrapper(referent)) {
-    /* We only care about promises, so CheckedUnwrapStatic is OK. */
-    referent = CheckedUnwrapStatic(referent);
+    referent = CheckedUnwrap(referent);
     if (!referent) {
       return false;
     }
   }
 
   return referent->is<PromiseObject>();
 }
 
@@ -10823,18 +10819,17 @@ double DebuggerObject::promiseTimeToReso
   return true;
 }
 
 /* static */ bool DebuggerObject::getErrorReport(JSContext* cx,
                                                  HandleObject maybeError,
                                                  JSErrorReport*& report) {
   JSObject* obj = maybeError;
   if (IsCrossCompartmentWrapper(obj)) {
-    /* We only care about Error objects, so CheckedUnwrapStatic is OK. */
-    obj = CheckedUnwrapStatic(obj);
+    obj = CheckedUnwrap(obj);
   }
 
   if (!obj) {
     ReportAccessDenied(cx);
     return false;
   }
 
   if (!obj->is<ErrorObject>()) {
@@ -11517,18 +11512,17 @@ double DebuggerObject::promiseTimeToReso
   return true;
 }
 
 /* static */ bool DebuggerObject::requirePromise(JSContext* cx,
                                                  HandleDebuggerObject object) {
   RootedObject referent(cx, object->referent());
 
   if (IsCrossCompartmentWrapper(referent)) {
-    /* We only care about promises, so CheckedUnwrapStatic is OK. */
-    referent = CheckedUnwrapStatic(referent);
+    referent = CheckedUnwrap(referent);
     if (!referent) {
       ReportAccessDenied(cx);
       return false;
     }
   }
 
   if (!referent->is<PromiseObject>()) {
     JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
@@ -12298,27 +12292,25 @@ extern JS_PUBLIC_API bool JS_DefineDebug
   debugProto->setReservedSlot(Debugger::JSSLOT_DEBUG_ENV_PROTO,
                               ObjectValue(*envProto));
   debugProto->setReservedSlot(Debugger::JSSLOT_DEBUG_MEMORY_PROTO,
                               ObjectValue(*memoryProto));
   return true;
 }
 
 JS_PUBLIC_API bool JS::dbg::IsDebugger(JSObject& obj) {
-  /* We only care about debugger objects, so CheckedUnwrapStatic is OK. */
-  JSObject* unwrapped = CheckedUnwrapStatic(&obj);
+  JSObject* unwrapped = CheckedUnwrap(&obj);
   return unwrapped && unwrapped->getClass() == &Debugger::class_ &&
          js::Debugger::fromJSObject(unwrapped) != nullptr;
 }
 
 JS_PUBLIC_API bool JS::dbg::GetDebuggeeGlobals(JSContext* cx, JSObject& dbgObj,
                                                AutoObjectVector& vector) {
   MOZ_ASSERT(IsDebugger(dbgObj));
-  /* Since we know we have a debugger object, CheckedUnwrapStatic is fine. */
-  js::Debugger* dbg = js::Debugger::fromJSObject(CheckedUnwrapStatic(&dbgObj));
+  js::Debugger* dbg = js::Debugger::fromJSObject(CheckedUnwrap(&dbgObj));
 
   if (!vector.reserve(vector.length() + dbg->debuggees.count())) {
     JS_ReportOutOfMemory(cx);
     return false;
   }
 
   for (WeakGlobalObjectSet::Range r = dbg->allDebuggees(); !r.empty();
        r.popFront()) {
--- a/js/xpconnect/src/ExportHelpers.cpp
+++ b/js/xpconnect/src/ExportHelpers.cpp
@@ -19,18 +19,18 @@
 #include "nsJSUtils.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace JS;
 
 namespace xpc {
 
-bool IsReflector(JSObject* obj, JSContext* cx) {
-  obj = js::CheckedUnwrapDynamic(obj, cx, /* stopAtWindowProxy = */ false);
+bool IsReflector(JSObject* obj) {
+  obj = js::CheckedUnwrap(obj, /* stopAtWindowProxy = */ false);
   if (!obj) {
     return false;
   }
   return IS_WN_REFLECTOR(obj) || dom::IsDOMObject(obj);
 }
 
 enum StackScopedCloneTags {
   SCTAG_BASE = JS_SCTAG_USER_MIN,
@@ -65,18 +65,17 @@ class MOZ_STACK_CLASS StackScopedCloneDa
 
       size_t idx;
       if (!JS_ReadBytes(aReader, &idx, sizeof(size_t))) {
         return nullptr;
       }
 
       RootedObject reflector(aCx, mReflectors[idx]);
       MOZ_ASSERT(reflector, "No object pointer?");
-      MOZ_ASSERT(IsReflector(reflector, aCx),
-                 "Object pointer must be a reflector!");
+      MOZ_ASSERT(IsReflector(reflector), "Object pointer must be a reflector!");
 
       if (!JS_WrapObject(aCx, &reflector)) {
         return nullptr;
       }
 
       return reflector;
     }
 
@@ -142,18 +141,17 @@ class MOZ_STACK_CLASS StackScopedCloneDa
         }
 
         size_t idx = mBlobImpls.Length() - 1;
         return JS_WriteUint32Pair(aWriter, SCTAG_BLOB, 0) &&
                JS_WriteBytes(aWriter, &idx, sizeof(size_t));
       }
     }
 
-    if ((mOptions->wrapReflectors && IsReflector(aObj, aCx)) ||
-        IsFileList(aObj)) {
+    if ((mOptions->wrapReflectors && IsReflector(aObj)) || IsFileList(aObj)) {
       if (!mReflectors.append(aObj)) {
         return false;
       }
 
       size_t idx = mReflectors.length() - 1;
       if (!JS_WriteUint32Pair(aWriter, SCTAG_REFLECTOR, 0)) {
         return false;
       }
@@ -391,20 +389,18 @@ bool ExportFunction(JSContext* cx, Handl
   if (hasOptions && !options.Parse()) {
     return false;
   }
 
   // Restrictions:
   // * We must subsume the scope we are exporting to.
   // * We must subsume the function being exported, because the function
   //   forwarder manually circumvents security wrapper CALL restrictions.
-  targetScope = js::CheckedUnwrapDynamic(targetScope, cx);
-  // For the function we can just CheckedUnwrapStatic, because if it's
-  // not callable we're going to fail out anyway.
-  funObj = js::CheckedUnwrapStatic(funObj);
+  targetScope = js::CheckedUnwrap(targetScope);
+  funObj = js::CheckedUnwrap(funObj);
   if (!targetScope || !funObj) {
     JS_ReportErrorASCII(cx, "Permission denied to export function into scope");
     return false;
   }
 
   if (js::IsScriptedProxy(targetScope)) {
     JS_ReportErrorASCII(cx, "Defining property on proxy object is not allowed");
     return false;
@@ -479,18 +475,17 @@ bool ExportFunction(JSContext* cx, Handl
 
 bool CreateObjectIn(JSContext* cx, HandleValue vobj,
                     CreateObjectInOptions& options, MutableHandleValue rval) {
   if (!vobj.isObject()) {
     JS_ReportErrorASCII(cx, "Expected an object as the target scope");
     return false;
   }
 
-  // cx represents the caller Realm.
-  RootedObject scope(cx, js::CheckedUnwrapDynamic(&vobj.toObject(), cx));
+  RootedObject scope(cx, js::CheckedUnwrap(&vobj.toObject()));
   if (!scope) {
     JS_ReportErrorASCII(
         cx, "Permission denied to create object in the target scope");
     return false;
   }
 
   bool define = !JSID_IS_VOID(options.defineAs);
 
--- a/js/xpconnect/src/Sandbox.cpp
+++ b/js/xpconnect/src/Sandbox.cpp
@@ -340,24 +340,18 @@ static bool SandboxIsProxy(JSContext* cx
     return false;
   }
   if (!args[0].isObject()) {
     args.rval().setBoolean(false);
     return true;
   }
 
   RootedObject obj(cx, &args[0].toObject());
-  // CheckedUnwrapStatic is OK here, since we only care about whether
-  // it's a scripted proxy and the things CheckedUnwrapStatic fails on
-  // are not.
-  obj = js::CheckedUnwrapStatic(obj);
-  if (!obj) {
-    args.rval().setBoolean(false);
-    return true;
-  }
+  obj = js::CheckedUnwrap(obj);
+  NS_ENSURE_TRUE(obj, false);
 
   args.rval().setBoolean(js::IsScriptedProxy(obj));
   return true;
 }
 
 /*
  * Expected type of the arguments and the return value:
  * function exportFunction(function funToExport,
@@ -665,20 +659,19 @@ bool WrapAccessorFunction(JSContext* cx,
   if (!func) {
     return false;
   }
   op = JS_DATA_TO_FUNC_PTR(Op, func.get());
   return true;
 }
 
 static bool IsMaybeWrappedDOMConstructor(JSObject* obj) {
-  // We really care about the underlying object here, which might be wrapped in
-  // cross-compartment wrappers.  CheckedUnwrapStatic is fine, since we just
-  // care whether it's a DOM constructor.
-  obj = js::CheckedUnwrapStatic(obj);
+  // We really care about the underlying object here, which might be wrapped
+  // in cross-compartment wrappers.
+  obj = js::CheckedUnwrap(obj);
   if (!obj) {
     return false;
   }
 
   return dom::IsDOMConstructor(obj);
 }
 
 bool SandboxProxyHandler::getPropertyDescriptorImpl(
@@ -1137,21 +1130,17 @@ nsresult xpc::CreateSandboxObject(JSCont
       //
       // Note that, in the case of a window, we can't require that the
       // Sandbox subsumes the prototype, because we have to hold our
       // reference to it via an outer window, and the window may navigate
       // at any time. So we have to handle that case separately.
       bool useSandboxProxy =
           !!WindowOrNull(js::UncheckedUnwrap(options.proto, false));
       if (!useSandboxProxy) {
-        // We just wrapped options.proto into the compartment of whatever Realm
-        // is on the cx, so use that same realm for the CheckedUnwrapDynamic
-        // call.
-        JSObject* unwrappedProto =
-            js::CheckedUnwrapDynamic(options.proto, cx, false);
+        JSObject* unwrappedProto = js::CheckedUnwrap(options.proto, false);
         if (!unwrappedProto) {
           JS_ReportErrorASCII(cx, "Sandbox must subsume sandboxPrototype");
           return NS_ERROR_INVALID_ARG;
         }
         const js::Class* unwrappedClass = js::GetObjectClass(unwrappedProto);
         useSandboxProxy = IS_WN_CLASS(unwrappedClass) ||
                           mozilla::dom::IsDOMClass(Jsvalify(unwrappedClass));
       }
@@ -1270,18 +1259,17 @@ bool ParsePrincipal(JSContext* cx, Handl
  * For sandbox constructor the first argument can be a principal object or
  * a script object principal (Document, Window).
  */
 static bool GetPrincipalOrSOP(JSContext* cx, HandleObject from,
                               nsISupports** out) {
   MOZ_ASSERT(out);
   *out = nullptr;
 
-  // We might have a Window here, so need ReflectorToISupportsDynamic
-  nsCOMPtr<nsISupports> native = ReflectorToISupportsDynamic(from, cx);
+  nsCOMPtr<nsISupports> native = xpc::UnwrapReflectorToISupports(from);
 
   if (nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(native)) {
     sop.forget(out);
     return true;
   }
 
   nsCOMPtr<nsIPrincipal> principal = do_QueryInterface(native);
   principal.forget(out);
@@ -1808,19 +1796,17 @@ nsresult nsXPCComponents_utils_Sandbox::
 
 nsresult xpc::EvalInSandbox(JSContext* cx, HandleObject sandboxArg,
                             const nsAString& source, const nsACString& filename,
                             int32_t lineNo, MutableHandleValue rval) {
   JS_AbortIfWrongThread(cx);
   rval.set(UndefinedValue());
 
   bool waiveXray = xpc::WrapperFactory::HasWaiveXrayFlag(sandboxArg);
-  // CheckedUnwrapStatic is fine here, since we're checking for "is it a
-  // sandbox".
-  RootedObject sandbox(cx, js::CheckedUnwrapStatic(sandboxArg));
+  RootedObject sandbox(cx, js::CheckedUnwrap(sandboxArg));
   if (!sandbox || !IsSandbox(sandbox)) {
     return NS_ERROR_INVALID_ARG;
   }
 
   nsIScriptObjectPrincipal* sop =
       static_cast<nsIScriptObjectPrincipal*>(xpc_GetJSPrivate(sandbox));
   MOZ_ASSERT(sop, "Invalid sandbox passed");
   SandboxPrivate* priv = static_cast<SandboxPrivate*>(sop);
--- a/js/xpconnect/src/XPCCallContext.cpp
+++ b/js/xpconnect/src/XPCCallContext.cpp
@@ -56,18 +56,17 @@ XPCCallContext::XPCCallContext(
   }
 
   mMethodIndex = 0xDEAD;
 
   mState = HAVE_OBJECT;
 
   mTearOff = nullptr;
 
-  JSObject* unwrapped =
-      js::CheckedUnwrapDynamic(obj, cx, /* stopAtWindowProxy = */ false);
+  JSObject* unwrapped = js::CheckedUnwrap(obj, /* stopAtWindowProxy = */ false);
   if (!unwrapped) {
     JS_ReportErrorASCII(mJSContext,
                         "Permission denied to call method on |this|");
     mState = INIT_FAILED;
     return;
   }
   const js::Class* clasp = js::GetObjectClass(unwrapped);
   if (IS_WN_CLASS(clasp)) {
--- a/js/xpconnect/src/XPCComponents.cpp
+++ b/js/xpconnect/src/XPCComponents.cpp
@@ -1524,36 +1524,34 @@ nsXPCComponents_Utils::GetUAWidgetScope(
 NS_IMETHODIMP
 nsXPCComponents_Utils::GetSandboxMetadata(HandleValue sandboxVal, JSContext* cx,
                                           MutableHandleValue rval) {
   if (!sandboxVal.isObject()) {
     return NS_ERROR_INVALID_ARG;
   }
 
   RootedObject sandbox(cx, &sandboxVal.toObject());
-  // We only care about sandboxes here, so CheckedUnwrapStatic is fine.
-  sandbox = js::CheckedUnwrapStatic(sandbox);
+  sandbox = js::CheckedUnwrap(sandbox);
   if (!sandbox || !xpc::IsSandbox(sandbox)) {
     return NS_ERROR_INVALID_ARG;
   }
 
   return xpc::GetSandboxMetadata(cx, sandbox, rval);
 }
 
 NS_IMETHODIMP
 nsXPCComponents_Utils::SetSandboxMetadata(HandleValue sandboxVal,
                                           HandleValue metadataVal,
                                           JSContext* cx) {
   if (!sandboxVal.isObject()) {
     return NS_ERROR_INVALID_ARG;
   }
 
   RootedObject sandbox(cx, &sandboxVal.toObject());
-  // We only care about sandboxes here, so CheckedUnwrapStatic is fine.
-  sandbox = js::CheckedUnwrapStatic(sandbox);
+  sandbox = js::CheckedUnwrap(sandbox);
   if (!sandbox || !xpc::IsSandbox(sandbox)) {
     return NS_ERROR_INVALID_ARG;
   }
 
   nsresult rv = xpc::SetSandboxMetadata(cx, sandbox, metadataVal);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
@@ -1594,19 +1592,19 @@ nsXPCComponents_Utils::ImportGlobalPrope
   // Ensure we're working in the scripted caller's realm. This is not guaranteed
   // to be the current realm because we switch realms when calling cross-realm
   // functions.
   RootedObject global(cx, JS::GetScriptedCallerGlobal(cx));
   MOZ_ASSERT(global);
   js::AssertSameCompartment(cx, global);
   JSAutoRealm ar(cx, global);
 
-  // Don't allow doing this if the global is a Window.
+  // Don't allow doing this if the global is a Window
   nsGlobalWindowInner* win;
-  if (NS_SUCCEEDED(UNWRAP_NON_WRAPPER_OBJECT(Window, global, win))) {
+  if (NS_SUCCEEDED(UNWRAP_OBJECT(Window, &global, win))) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   GlobalProperties options;
   NS_ENSURE_TRUE(aPropertyList.isObject(), NS_ERROR_INVALID_ARG);
 
   RootedObject propertyList(cx, &aPropertyList.toObject());
   bool isArray;
@@ -1835,20 +1833,17 @@ nsXPCComponents_Utils::GetGlobalForObjec
 NS_IMETHODIMP
 nsXPCComponents_Utils::IsProxy(HandleValue vobj, JSContext* cx, bool* rval) {
   if (!vobj.isObject()) {
     *rval = false;
     return NS_OK;
   }
 
   RootedObject obj(cx, &vobj.toObject());
-  // We need to do a dynamic unwrap, because we apparently want to treat
-  // "failure to unwrap" differently from "not a proxy" (throw for the former,
-  // return false for the latter).
-  obj = js::CheckedUnwrapDynamic(obj, cx, /* stopAtWindowProxy = */ false);
+  obj = js::CheckedUnwrap(obj, /* stopAtWindowProxy = */ false);
   NS_ENSURE_TRUE(obj, NS_ERROR_FAILURE);
 
   *rval = js::IsScriptedProxy(obj);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsXPCComponents_Utils::ExportFunction(HandleValue vfunction, HandleValue vscope,
@@ -2317,18 +2312,17 @@ nsXPCComponents_Utils::GetJSEngineTeleme
 
 bool xpc::CloneInto(JSContext* aCx, HandleValue aValue, HandleValue aScope,
                     HandleValue aOptions, MutableHandleValue aCloned) {
   if (!aScope.isObject()) {
     return false;
   }
 
   RootedObject scope(aCx, &aScope.toObject());
-  // The scope could be a Window, so we need to CheckedUnwrapDynamic.
-  scope = js::CheckedUnwrapDynamic(scope, aCx);
+  scope = js::CheckedUnwrap(scope);
   if (!scope) {
     JS_ReportErrorASCII(aCx, "Permission denied to clone object into scope");
     return false;
   }
 
   if (!aOptions.isUndefined() && !aOptions.isObject()) {
     JS_ReportErrorASCII(aCx, "Invalid argument");
     return false;
@@ -2379,36 +2373,32 @@ nsXPCComponents_Utils::GetWebIDLCallerPr
 
 NS_IMETHODIMP
 nsXPCComponents_Utils::GetObjectPrincipal(HandleValue val, JSContext* cx,
                                           nsIPrincipal** result) {
   if (!val.isObject()) {
     return NS_ERROR_INVALID_ARG;
   }
   RootedObject obj(cx, &val.toObject());
-  // We need to be able to unwrap to WindowProxy or Location here, so
-  // use CheckedUnwrapDynamic.
-  obj = js::CheckedUnwrapDynamic(obj, cx);
+  obj = js::CheckedUnwrap(obj);
   MOZ_ASSERT(obj);
 
   nsCOMPtr<nsIPrincipal> prin = nsContentUtils::ObjectPrincipal(obj);
   prin.forget(result);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsXPCComponents_Utils::GetRealmLocation(HandleValue val, JSContext* cx,
                                         nsACString& result) {
   if (!val.isObject()) {
     return NS_ERROR_INVALID_ARG;
   }
   RootedObject obj(cx, &val.toObject());
-  // We need to be able to unwrap to WindowProxy or Location here, so
-  // use CheckedUnwrapDynamic.
-  obj = js::CheckedUnwrapDynamic(obj, cx);
+  obj = js::CheckedUnwrap(obj);
   MOZ_ASSERT(obj);
 
   result = xpc::RealmPrivate::Get(obj)->GetLocation();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsXPCComponents_Utils::ReadUTF8File(nsIFile* aFile, nsACString& aResult) {
--- a/js/xpconnect/src/XPCConvert.cpp
+++ b/js/xpconnect/src/XPCConvert.cpp
@@ -802,17 +802,17 @@ bool XPCConvert::JSData2Native(JSContext
         return true;
       }
 
       // Can't handle non-JSObjects
       if (!s.isObject()) {
         return false;
       }
 
-      nsresult err = type.GetDOMObjectInfo().Unwrap(s, (void**)d, cx);
+      nsresult err = type.GetDOMObjectInfo().Unwrap(s, (void**)d);
       if (pErr) {
         *pErr = err;
       }
       return NS_SUCCEEDED(err);
     }
 
     case nsXPTType::T_PROMISE: {
       nsIGlobalObject* glob = CurrentNativeGlobal(cx);
@@ -1064,19 +1064,19 @@ bool XPCConvert::JSObject2NativeInterfac
     // we aren't, throw an exception eagerly.
     //
     // NB: It's very important that we _don't_ unwrap in the aOuter case,
     // because the caller may explicitly want to create the XPCWrappedJS
     // around a security wrapper. XBL does this with Xrays from the XBL
     // scope - see nsBindingManager::GetBindingImplementation.
     //
     // It's also very important that "inner" be rooted here.
-    RootedObject inner(
-        cx, js::CheckedUnwrapDynamic(src, cx,
-                                     /* stopAtWindowProxy = */ false));
+    RootedObject inner(RootingCx(),
+                       js::CheckedUnwrap(src,
+                                         /* stopAtWindowProxy = */ false));
     if (!inner) {
       if (pErr) {
         *pErr = NS_ERROR_XPC_SECURITY_MANAGER_VETO;
       }
       return false;
     }
 
     // Is this really a native xpcom object with a wrapper?
@@ -1273,24 +1273,22 @@ nsresult XPCConvert::JSValToXPCException
 
     if (!obj) {
       NS_ERROR("when is an object not an object?");
       return NS_ERROR_FAILURE;
     }
 
     // is this really a native xpcom object with a wrapper?
     JSObject* unwrapped =
-        js::CheckedUnwrapDynamic(obj, cx, /* stopAtWindowProxy = */ false);
+        js::CheckedUnwrap(obj, /* stopAtWindowProxy = */ false);
     if (!unwrapped) {
       return NS_ERROR_XPC_SECURITY_MANAGER_VETO;
     }
-    // It's OK to use ReflectorToISupportsStatic, because we have already
-    // stripped off wrappers.
     if (nsCOMPtr<nsISupports> supports =
-            ReflectorToISupportsStatic(unwrapped)) {
+            UnwrapReflectorToISupports(unwrapped)) {
       nsCOMPtr<Exception> iface = do_QueryInterface(supports);
       if (iface) {
         // just pass through the exception (with extra ref and all)
         iface.forget(exceptn);
         return NS_OK;
       }
 
       // it is a wrapped native, but not an exception!
--- a/js/xpconnect/src/XPCJSContext.cpp
+++ b/js/xpconnect/src/XPCJSContext.cpp
@@ -654,18 +654,17 @@ bool XPCJSContext::InterruptCallback(JSC
     // If this is a sandbox associated with a DOMWindow via a
     // sandboxPrototype, use that DOMWindow. This supports GreaseMonkey
     // and JetPack content scripts.
     JS::Rooted<JSObject*> proto(cx);
     if (!JS_GetPrototype(cx, global, &proto)) {
       return false;
     }
     if (proto && xpc::IsSandboxPrototypeProxy(proto) &&
-        (proto = js::CheckedUnwrapDynamic(proto, cx,
-                                          /* stopAtWindowProxy = */ false))) {
+        (proto = js::CheckedUnwrap(proto, /* stopAtWindowProxy = */ false))) {
       win = WindowGlobalOrNull(proto);
     }
   }
 
   if (!win) {
     NS_WARNING("No active window");
     return true;
   }
--- a/js/xpconnect/src/XPCJSID.cpp
+++ b/js/xpconnect/src/XPCJSID.cpp
@@ -142,18 +142,17 @@ static JSObject* GetIDPrototype(JSContex
   }
 
   MOZ_CRASH("Unrecognized ID Object Class");
 }
 
 // Unwrap the given value to an object with the correct class, or nullptr.
 static JSObject* GetIDObject(HandleValue aVal, const Class* aClass) {
   if (aVal.isObject()) {
-    // We care only about IID/CID objects here, so CheckedUnwrapStatic is fine.
-    JSObject* obj = js::CheckedUnwrapStatic(&aVal.toObject());
+    JSObject* obj = js::CheckedUnwrap(&aVal.toObject());
     if (obj && js::GetObjectClass(obj) == aClass) {
       return obj;
     }
   }
   return nullptr;
 }
 
 /**
@@ -164,23 +163,18 @@ static JSObject* GetIDObject(HandleValue
  * and for ContractID objects, the ContractID's corresponding CID will be looked
  * up.
  */
 Maybe<nsID> JSValue2ID(JSContext* aCx, HandleValue aVal) {
   if (!aVal.isObject()) {
     return Nothing();
   }
 
-  // We only care about ID objects here, so CheckedUnwrapStatic is fine.
-  RootedObject obj(aCx, js::CheckedUnwrapStatic(&aVal.toObject()));
-  if (!obj) {
-    return Nothing();
-  }
-
   mozilla::Maybe<nsID> id;
+  RootedObject obj(aCx, js::CheckedUnwrap(&aVal.toObject()));
   if (js::GetObjectClass(obj) == &sID_Class) {
     // Extract the raw bytes of the nsID from reserved slots.
     uint32_t rawid[] = {js::GetReservedSlot(obj, kID_Slot0).toPrivateUint32(),
                         js::GetReservedSlot(obj, kID_Slot1).toPrivateUint32(),
                         js::GetReservedSlot(obj, kID_Slot2).toPrivateUint32(),
                         js::GetReservedSlot(obj, kID_Slot3).toPrivateUint32()};
 
     // Construct a nsID inside the Maybe, and copy the rawid into it.
@@ -368,21 +362,18 @@ static bool ID_Equals(JSContext* aCx, un
  * This static method handles both complexities, returning either an XPCWN, a
  * DOM object, or null. The object may well be cross-compartment from |cx|.
  */
 static nsresult FindObjectForHasInstance(JSContext* cx, HandleObject objArg,
                                          MutableHandleObject target) {
   using namespace mozilla::jsipc;
   RootedObject obj(cx, objArg), proto(cx);
   while (true) {
-    // Try the object, or the wrappee if allowed.  We want CheckedUnwrapDynamic
-    // here, because we might in fact be looking for a Window.  "cx" represents
-    // our current global.
-    JSObject* o =
-        js::IsWrapper(obj) ? js::CheckedUnwrapDynamic(obj, cx, false) : obj;
+    // Try the object, or the wrappee if allowed.
+    JSObject* o = js::IsWrapper(obj) ? js::CheckedUnwrap(obj, false) : obj;
     if (o && (IS_WN_REFLECTOR(o) || IsDOMObject(o) || IsCPOW(o))) {
       target.set(o);
       return NS_OK;
     }
 
     // Walk the prototype chain from the perspective of the callee (i.e.
     // respecting Xrays if they exist).
     if (!js::GetObjectProto(cx, obj, &proto)) {
@@ -409,18 +400,17 @@ nsresult HasInstance(JSContext* cx, Hand
   if (!obj) {
     return NS_OK;
   }
 
   if (mozilla::jsipc::IsCPOW(obj)) {
     return mozilla::jsipc::InstanceOf(obj, iid, bp);
   }
 
-  // Need to unwrap Window correctly here, so use ReflectorToISupportsDynamic.
-  nsCOMPtr<nsISupports> identity = ReflectorToISupportsDynamic(obj, cx);
+  nsCOMPtr<nsISupports> identity = UnwrapReflectorToISupports(obj);
   if (!identity) {
     return NS_OK;
   }
 
   nsCOMPtr<nsISupports> supp;
   identity->QueryInterface(*iid, getter_AddRefs(supp));
   *bp = supp;
 
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -2245,17 +2245,17 @@ class XPCJSRuntimeStats : public JS::Run
     extras->pathPrefix.AssignLiteral("explicit/js-non-window/zones/");
 
     // Get some global in this zone.
     Rooted<Realm*> realm(cx, js::GetAnyRealmInZone(zone));
     if (realm) {
       RootedObject global(cx, JS::GetRealmGlobalOrNull(realm));
       if (global) {
         RefPtr<nsGlobalWindowInner> window;
-        if (NS_SUCCEEDED(UNWRAP_NON_WRAPPER_OBJECT(Window, global, window))) {
+        if (NS_SUCCEEDED(UNWRAP_OBJECT(Window, global, window))) {
           // The global is a |window| object.  Use the path prefix that
           // we should have already created for it.
           if (mTopWindowPaths->Get(window->WindowID(), &extras->pathPrefix))
             extras->pathPrefix.AppendLiteral("/js-");
         }
       }
     }
 
@@ -2273,17 +2273,17 @@ class XPCJSRuntimeStats : public JS::Run
     GetRealmName(realm, rName, &mAnonymizeID, /* replaceSlashes = */ true);
 
     // Get the realm's global.
     AutoSafeJSContext cx;
     bool needZone = true;
     RootedObject global(cx, JS::GetRealmGlobalOrNull(realm));
     if (global) {
       RefPtr<nsGlobalWindowInner> window;
-      if (NS_SUCCEEDED(UNWRAP_NON_WRAPPER_OBJECT(Window, global, window))) {
+      if (NS_SUCCEEDED(UNWRAP_OBJECT(Window, global, window))) {
         // The global is a |window| object.  Use the path prefix that
         // we should have already created for it.
         if (mWindowPaths->Get(window->WindowID(), &extras->jsPathPrefix)) {
           extras->domPathPrefix.Assign(extras->jsPathPrefix);
           extras->domPathPrefix.AppendLiteral("/dom/");
           extras->jsPathPrefix.AppendLiteral("/js-");
           needZone = false;
         } else {
--- a/js/xpconnect/src/XPCJSWeakReference.cpp
+++ b/js/xpconnect/src/XPCJSWeakReference.cpp
@@ -20,17 +20,17 @@ nsresult xpcJSWeakReference::Init(JSCont
     return NS_OK;
   }
 
   JS::RootedObject obj(cx, &object.toObject());
 
   XPCCallContext ccx(cx);
 
   // See if the object is a wrapped native that supports weak references.
-  nsCOMPtr<nsISupports> supports = xpc::ReflectorToISupportsDynamic(obj, cx);
+  nsCOMPtr<nsISupports> supports = xpc::UnwrapReflectorToISupports(obj);
   nsCOMPtr<nsISupportsWeakReference> supportsWeakRef =
       do_QueryInterface(supports);
   if (supportsWeakRef) {
     supportsWeakRef->GetWeakReference(getter_AddRefs(mReferent));
     if (mReferent) {
       return NS_OK;
     }
   }
--- a/js/xpconnect/src/XPCVariant.cpp
+++ b/js/xpconnect/src/XPCVariant.cpp
@@ -39,21 +39,20 @@ XPCVariant::XPCVariant(JSContext* cx, co
     // be a problem anymore because SetParentToWindow will do the right
     // thing, but I'm saving the cleanup here for another day. Blake thinks
     // that we should just not store the WN if we're creating a variant for
     // an outer window.
     JSObject* obj = js::ToWindowIfWindowProxy(&mJSVal.toObject());
     mJSVal = JS::ObjectValue(*obj);
 
     JSObject* unwrapped =
-        js::CheckedUnwrapDynamic(obj, cx, /* stopAtWindowProxy = */ false);
+        js::CheckedUnwrap(obj, /* stopAtWindowProxy = */ false);
     mReturnRawObject = !(unwrapped && IS_WN_REFLECTOR(unwrapped));
-  } else {
+  } else
     mReturnRawObject = false;
-  }
 }
 
 XPCTraceableVariant::~XPCTraceableVariant() {
   Value val = GetJSValPreserveColor();
 
   MOZ_ASSERT(val.isGCThing() || val.isNull(), "Must be traceable or unlinked");
 
   mData.Cleanup();
--- a/js/xpconnect/src/XPCWrappedNativeJSOps.cpp
+++ b/js/xpconnect/src/XPCWrappedNativeJSOps.cpp
@@ -698,17 +698,17 @@ bool XPC_WN_MaybeResolvingDeleteProperty
     return result.succeed();
   }
   return Throw(NS_ERROR_XPC_CANT_MODIFY_PROP_ON_WN, cx);
 }
 
 // macro fun!
 #define PRE_HELPER_STUB                                                 \
   /* It's very important for "unwrapped" to be rooted here.  */         \
-  RootedObject unwrapped(cx, js::CheckedUnwrapDynamic(obj, cx, false)); \
+  RootedObject unwrapped(cx, js::CheckedUnwrap(obj, false));            \
   if (!unwrapped) {                                                     \
     JS_ReportErrorASCII(cx, "Permission denied to operate on object."); \
     return false;                                                       \
   }                                                                     \
   if (!IS_WN_REFLECTOR(unwrapped)) {                                    \
     return Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx);                  \
   }                                                                     \
   XPCWrappedNative* wrapper = XPCWrappedNative::Get(unwrapped);         \
--- a/js/xpconnect/src/nsXPConnect.cpp
+++ b/js/xpconnect/src/nsXPConnect.cpp
@@ -677,29 +677,31 @@ NS_IMETHODIMP
 nsXPConnect::GetWrappedNativeOfJSObject(JSContext* aJSContext,
                                         JSObject* aJSObjArg,
                                         nsIXPConnectWrappedNative** _retval) {
   MOZ_ASSERT(aJSContext, "bad param");
   MOZ_ASSERT(aJSObjArg, "bad param");
   MOZ_ASSERT(_retval, "bad param");
 
   RootedObject aJSObj(aJSContext, aJSObjArg);
-  aJSObj = js::CheckedUnwrapDynamic(aJSObj, aJSContext,
-                                    /* stopAtWindowProxy = */ false);
+  aJSObj = js::CheckedUnwrap(aJSObj, /* stopAtWindowProxy = */ false);
   if (!aJSObj || !IS_WN_REFLECTOR(aJSObj)) {
     *_retval = nullptr;
     return NS_ERROR_FAILURE;
   }
 
   RefPtr<XPCWrappedNative> temp = XPCWrappedNative::Get(aJSObj);
   temp.forget(_retval);
   return NS_OK;
 }
 
-static already_AddRefed<nsISupports> ReflectorToISupports(JSObject* reflector) {
+already_AddRefed<nsISupports> xpc::UnwrapReflectorToISupports(
+    JSObject* reflector) {
+  // Unwrap security wrappers, if allowed.
+  reflector = js::CheckedUnwrap(reflector, /* stopAtWindowProxy = */ false);
   if (!reflector) {
     return nullptr;
   }
 
   // Try XPCWrappedNatives.
   if (IS_WN_REFLECTOR(reflector)) {
     XPCWrappedNative* wn = XPCWrappedNative::Get(reflector);
     if (!wn) {
@@ -712,30 +714,16 @@ static already_AddRefed<nsISupports> Ref
   // Try DOM objects.  This QI without taking a ref first is safe, because
   // this if non-null our thing will definitely be a DOM object, and we know
   // their QI to nsISupports doesn't do anything weird.
   nsCOMPtr<nsISupports> canonical =
       do_QueryInterface(mozilla::dom::UnwrapDOMObjectToISupports(reflector));
   return canonical.forget();
 }
 
-already_AddRefed<nsISupports> xpc::ReflectorToISupportsStatic(
-    JSObject* reflector) {
-  // Unwrap security wrappers, if allowed.
-  return ReflectorToISupports(js::CheckedUnwrapStatic(reflector));
-}
-
-already_AddRefed<nsISupports> xpc::ReflectorToISupportsDynamic(
-    JSObject* reflector, JSContext* cx) {
-  // Unwrap security wrappers, if allowed.
-  return ReflectorToISupports(
-      js::CheckedUnwrapDynamic(reflector, cx,
-                               /* stopAtWindowProxy = */ false));
-}
-
 NS_IMETHODIMP
 nsXPConnect::CreateSandbox(JSContext* cx, nsIPrincipal* principal,
                            JSObject** _retval) {
   *_retval = nullptr;
 
   RootedValue rval(cx);
   SandboxOptions options;
   nsresult rv = CreateSandboxObject(cx, &rval, principal, options);
--- a/js/xpconnect/src/xpcpublic.h
+++ b/js/xpconnect/src/xpcpublic.h
@@ -134,21 +134,17 @@ bool AllowContentXBLScope(JS::Realm* rea
 bool UseContentXBLScope(JS::Realm* realm);
 
 // Clear out the content XBL scope (if any) on the given global.  This will
 // force creation of a new one if one is needed again.
 void ClearContentXBLScope(JSObject* global);
 
 bool IsSandboxPrototypeProxy(JSObject* obj);
 
-// The JSContext argument represents the Realm that's asking the question.  This
-// is needed to properly answer without exposing information unnecessarily
-// from behind security wrappers.  There will be no exceptions thrown on this
-// JSContext.
-bool IsReflector(JSObject* obj, JSContext* cx);
+bool IsReflector(JSObject* obj);
 
 bool IsXrayWrapper(JSObject* obj);
 
 // If this function was created for a given XrayWrapper, returns the global of
 // the Xrayed object. Otherwise, returns the global of the function.
 //
 // To emphasize the obvious: the return value here is not necessarily same-
 // compartment with the argument.
@@ -459,34 +455,19 @@ void ReportJSRuntimeExplicitTreeStats(co
 
 /**
  * Throws an exception on cx and returns false.
  */
 bool Throw(JSContext* cx, nsresult rv);
 
 /**
  * Returns the nsISupports native behind a given reflector (either DOM or
- * XPCWN).  If a non-reflector object is passed in, null will be returned.
- *
- * This function will not correctly handle Window or Location objects behind
- * cross-compartment wrappers: it will return null.  If you care about getting
- * non-null for Window or Location, use ReflectorToISupportsDynamic.
+ * XPCWN).
  */
-already_AddRefed<nsISupports> ReflectorToISupportsStatic(JSObject* reflector);
-
-/**
- * Returns the nsISupports native behind a given reflector (either DOM or
- * XPCWN).  If a non-reflector object is passed in, null will be returned.
- *
- * The JSContext argument represents the Realm that's asking for the
- * nsISupports.  This is needed to properly handle Window and Location objects,
- * which do dynamic security checks.
- */
-already_AddRefed<nsISupports> ReflectorToISupportsDynamic(JSObject* reflector,
-                                                          JSContext* cx);
+already_AddRefed<nsISupports> UnwrapReflectorToISupports(JSObject* reflector);
 
 /**
  * Singleton scopes for stuff that really doesn't fit anywhere else.
  *
  * If you find yourself wanting to use these compartments, you're probably doing
  * something wrong. Callers MUST consult with the XPConnect module owner before
  * using this compartment. If you don't, bholley will hunt you down.
  */
--- a/js/xpconnect/wrappers/WrapperFactory.cpp
+++ b/js/xpconnect/wrappers/WrapperFactory.cpp
@@ -14,17 +14,16 @@
 
 #include "xpcprivate.h"
 #include "XPCMaps.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "jsfriendapi.h"
 #include "mozilla/jsipc/CrossProcessObjectWrappers.h"
 #include "mozilla/Likely.h"
 #include "mozilla/dom/ScriptSettings.h"
-#include "mozilla/dom/MaybeCrossOriginObject.h"
 #include "nsContentUtils.h"
 #include "nsXULAppAPI.h"
 
 using namespace JS;
 using namespace js;
 using namespace mozilla;
 
 namespace xpc {
@@ -359,25 +358,16 @@ static void DEBUG_CheckUnwrapSafety(Hand
 }
 #else
 #  define DEBUG_CheckUnwrapSafety(obj, handler, origin, target) \
     {}
 #endif
 
 const CrossOriginObjectWrapper CrossOriginObjectWrapper::singleton;
 
-bool CrossOriginObjectWrapper::dynamicCheckedUnwrapAllowed(
-    HandleObject obj, JSContext* cx) const {
-  MOZ_ASSERT(js::GetProxyHandler(obj) == this,
-             "Why are we getting called for some random object?");
-  JSObject* target = wrappedObject(obj);
-  return dom::MaybeCrossOriginObjectMixins::IsPlatformObjectSameOrigin(cx,
-                                                                       target);
-}
-
 static const Wrapper* SelectWrapper(bool securityWrapper, XrayType xrayType,
                                     bool waiveXrays, JSObject* obj) {
   // Waived Xray uses a modified CCW that has transparent behavior but
   // transitively waives Xrays on arguments.
   if (waiveXrays) {
     MOZ_ASSERT(!securityWrapper);
     return &WaiveXrayWrapper::singleton;
   }
--- a/js/xpconnect/wrappers/WrapperFactory.h
+++ b/js/xpconnect/wrappers/WrapperFactory.h
@@ -33,18 +33,16 @@ class CrossOriginObjectWrapper : public 
   // We don't want to inherit from CrossCompartmentWrapper, because we don't
   // want the compartment-entering behavior it has.  But we do want to set the
   // CROSS_COMPARTMENT flag on js::Wrapper so that we test true for
   // is<js::CrossCompartmentWrapperObject> and so forth.
   constexpr explicit CrossOriginObjectWrapper()
       : js::Wrapper(CROSS_COMPARTMENT, /* aHasPrototype = */ false,
                     /* aHasSecurityPolicy = */ true) {}
 
-  bool dynamicCheckedUnwrapAllowed(JS::HandleObject obj, JSContext* cx) const override;
-
   static const CrossOriginObjectWrapper singleton;
 };
 
 class WrapperFactory {
  public:
   enum {
     WAIVE_XRAY_WRAPPER_FLAG = js::Wrapper::LAST_USED_FLAG << 1,
     IS_XRAY_WRAPPER_FLAG = WAIVE_XRAY_WRAPPER_FLAG << 1
--- a/js/xpconnect/wrappers/XrayWrapper.cpp
+++ b/js/xpconnect/wrappers/XrayWrapper.cpp
@@ -28,17 +28,17 @@
 #include "mozilla/dom/XrayExpandoClass.h"
 #include "nsGlobalWindow.h"
 
 using namespace mozilla::dom;
 using namespace JS;
 using namespace mozilla;
 
 using js::BaseProxyHandler;
-using js::CheckedUnwrapStatic;
+using js::CheckedUnwrap;
 using js::IsCrossCompartmentWrapper;
 using js::UncheckedUnwrap;
 using js::Wrapper;
 
 namespace xpc {
 
 using namespace XrayUtils;
 
@@ -1929,25 +1929,23 @@ static bool RecreateLostWaivers(JSContex
   if (valueWasWaived &&
       !IsCrossCompartmentWrapper(&wrapped.value().toObject())) {
     rewaived = &wrapped.value().toObject();
     rewaived = WrapperFactory::WaiveXray(cx, UncheckedUnwrap(rewaived));
     NS_ENSURE_TRUE(rewaived, false);
     wrapped.value().set(ObjectValue(*rewaived));
   }
   if (getterWasWaived && !IsCrossCompartmentWrapper(wrapped.getterObject())) {
-    // We can't end up with WindowProxy or Location as getters.
-    MOZ_ASSERT(CheckedUnwrapStatic(wrapped.getterObject()));
+    MOZ_ASSERT(CheckedUnwrap(wrapped.getterObject()));
     rewaived = WrapperFactory::WaiveXray(cx, wrapped.getterObject());
     NS_ENSURE_TRUE(rewaived, false);
     wrapped.setGetterObject(rewaived);
   }
   if (setterWasWaived && !IsCrossCompartmentWrapper(wrapped.setterObject())) {
-    // We can't end up with WindowProxy or Location as setters.
-    MOZ_ASSERT(CheckedUnwrapStatic(wrapped.setterObject()));
+    MOZ_ASSERT(CheckedUnwrap(wrapped.setterObject()));
     rewaived = WrapperFactory::WaiveXray(cx, wrapped.setterObject());
     NS_ENSURE_TRUE(rewaived, false);
     wrapped.setSetterObject(rewaived);
   }
 
   return true;
 }
 
--- a/toolkit/components/mozintl/MozIntlHelper.cpp
+++ b/toolkit/components/mozintl/MozIntlHelper.cpp
@@ -25,19 +25,17 @@ MozIntlHelper::MozIntlHelper() = default
 MozIntlHelper::~MozIntlHelper() = default;
 
 static nsresult AddFunctions(JSContext* cx, JS::Handle<JS::Value> val,
                              const JSFunctionSpec* funcs) {
   if (!val.isObject()) {
     return NS_ERROR_INVALID_ARG;
   }
 
-  // We might be adding functions to a Window.
-  JS::Rooted<JSObject*> realIntlObj(
-      cx, js::CheckedUnwrapDynamic(&val.toObject(), cx));
+  JS::Rooted<JSObject*> realIntlObj(cx, js::CheckedUnwrap(&val.toObject()));
   if (!realIntlObj) {
     return NS_ERROR_INVALID_ARG;
   }
 
   JSAutoRealm ar(cx, realIntlObj);
 
   if (!JS_DefineFunctions(cx, realIntlObj, funcs)) {
     return NS_ERROR_FAILURE;
@@ -66,19 +64,17 @@ MozIntlHelper::AddGetDisplayNames(JS::Ha
 
 NS_IMETHODIMP
 MozIntlHelper::AddDateTimeFormatConstructor(JS::Handle<JS::Value> val,
                                             JSContext* cx) {
   if (!val.isObject()) {
     return NS_ERROR_INVALID_ARG;
   }
 
-  // We might be adding this constructor to a Window
-  JS::Rooted<JSObject*> realIntlObj(
-      cx, js::CheckedUnwrapDynamic(&val.toObject(), cx));
+  JS::Rooted<JSObject*> realIntlObj(cx, js::CheckedUnwrap(&val.toObject()));
   if (!realIntlObj) {
     return NS_ERROR_INVALID_ARG;
   }
 
   JSAutoRealm ar(cx, realIntlObj);
 
   if (!js::AddMozDateTimeFormatConstructor(cx, realIntlObj)) {
     return NS_ERROR_FAILURE;
--- a/toolkit/components/telemetry/core/Stopwatch.cpp
+++ b/toolkit/components/telemetry/core/Stopwatch.cpp
@@ -20,18 +20,17 @@
 #include "nsRefPtrHashtable.h"
 #include "nsString.h"
 #include "xpcpublic.h"
 
 using mozilla::dom::AutoJSAPI;
 
 static inline nsQueryObject<nsISupports> do_QueryReflector(
     JSObject* aReflector) {
-  // None of the types we query to are implemented by Window or Location.
-  nsCOMPtr<nsISupports> reflector = xpc::ReflectorToISupportsStatic(aReflector);
+  nsCOMPtr<nsISupports> reflector = xpc::UnwrapReflectorToISupports(aReflector);
   return do_QueryObject(reflector);
 }
 
 static inline nsQueryObject<nsISupports> do_QueryReflector(
     const JS::Value& aReflector) {
   return do_QueryReflector(&aReflector.toObject());
 }
 
--- a/toolkit/recordreplay/ipc/JSControl.cpp
+++ b/toolkit/recordreplay/ipc/JSControl.cpp
@@ -332,19 +332,17 @@ static bool Middleman_RegisterReplayDebu
     }
 
     if (NS_FAILED(gControl->ConnectDebugger(debuggerValue))) {
       JS_ReportErrorASCII(aCx, "ConnectDebugger failed\n");
       return false;
     }
   }
 
-  // Who knows what values are being passed here.  Play it safe and do
-  // CheckedUnwrapDynamic.
-  obj = ::js::CheckedUnwrapDynamic(obj, aCx);
+  obj = ::js::CheckedUnwrap(obj);
   if (!obj) {
     ::js::ReportAccessDenied(aCx);
     return false;
   }
 
   gReplayDebugger = new PersistentRootedObject(aCx);
   *gReplayDebugger = obj;
 
--- a/xpcom/reflect/xptinfo/xptcodegen.py
+++ b/xpcom/reflect/xptinfo/xptcodegen.py
@@ -441,20 +441,20 @@ def link_to_cpp(interfaces, fd):
     fd.write("""
 #include "xptinfo.h"
 #include "mozilla/PerfectHash.h"
 #include "mozilla/TypeTraits.h"
 #include "mozilla/dom/BindingUtils.h"
 
 // These template methods are specialized to be used in the sDOMObjects table.
 template<mozilla::dom::prototypes::ID PrototypeID, typename T>
-static nsresult UnwrapDOMObject(JS::HandleValue aHandle, void** aObj, JSContext* aCx)
+static nsresult UnwrapDOMObject(JS::HandleValue aHandle, void** aObj)
 {
   RefPtr<T> p;
-  nsresult rv = mozilla::dom::UnwrapObject<PrototypeID, T>(aHandle, p, aCx);
+  nsresult rv = mozilla::dom::UnwrapObject<PrototypeID, T>(aHandle, p);
   p.forget(aObj);
   return rv;
 }
 
 template<typename T>
 static bool WrapDOMObject(JSContext* aCx, void* aObj, JS::MutableHandleValue aHandle)
 {
   return mozilla::dom::GetOrCreateDOMReflector(aCx, reinterpret_cast<T*>(aObj), aHandle);
--- a/xpcom/reflect/xptinfo/xptinfo.h
+++ b/xpcom/reflect/xptinfo/xptinfo.h
@@ -517,31 +517,31 @@ struct nsXPTConstantInfo {
 static_assert(sizeof(nsXPTConstantInfo) == 8, "wrong size");
 
 /**
  * Object representing the information required to wrap and unwrap DOMObjects.
  *
  * This object will not live in rodata as it contains relocations.
  */
 struct nsXPTDOMObjectInfo {
-  nsresult Unwrap(JS::HandleValue aHandle, void** aObj, JSContext* aCx) const {
-    return mUnwrap(aHandle, aObj, aCx);
+  nsresult Unwrap(JS::HandleValue aHandle, void** aObj) const {
+    return mUnwrap(aHandle, aObj);
   }
 
   bool Wrap(JSContext* aCx, void* aObj, JS::MutableHandleValue aHandle) const {
     return mWrap(aCx, aObj, aHandle);
   }
 
   void Cleanup(void* aObj) const { return mCleanup(aObj); }
 
   ////////////////////////////////////////////////////////////////
   // Ensure these fields are in the same order as xptcodegen.py //
   ////////////////////////////////////////////////////////////////
 
-  nsresult (*mUnwrap)(JS::HandleValue aHandle, void** aObj, JSContext* aCx);
+  nsresult (*mUnwrap)(JS::HandleValue aHandle, void** aObj);
   bool (*mWrap)(JSContext* aCx, void* aObj, JS::MutableHandleValue aHandle);
   void (*mCleanup)(void* aObj);
 };
 
 namespace xpt {
 namespace detail {
 
 // The UntypedTArray type allows low-level access from XPConnect to nsTArray