Bug 1547923 part 4. Add nsIGlobalObject::HasJSGlobal(). r=mccr8
authorBoris Zbarsky <bzbarsky@mit.edu>
Thu, 02 May 2019 21:32:17 +0000
changeset 531316 2d60837b8f3c38281997ab84a80a490f7f478496
parent 531315 358e6f08d9c5612f6cffdcda1ff2457696312886
child 531317 9437efdc6fc3bc29853cda4ddd0986316097e10d
push id11265
push userffxbld-merge
push dateMon, 13 May 2019 10:53:39 +0000
treeherdermozilla-beta@77e0fe8dbdd3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmccr8
bugs1547923
milestone68.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1547923 part 4. Add nsIGlobalObject::HasJSGlobal(). r=mccr8 Consumers that just care about this boolean state should use this instead of getting the JSObject* directly. Differential Revision: https://phabricator.services.mozilla.com/D29705
dom/base/Document.cpp
dom/base/nsIGlobalObject.h
dom/bindings/CallbackObject.cpp
dom/events/EventListenerManager.cpp
dom/media/webaudio/AudioBuffer.cpp
dom/script/ScriptSettings.cpp
js/xpconnect/src/XPCWrappedJSClass.cpp
layout/printing/nsPrintJob.cpp
xpcom/base/CycleCollectedJSRuntime.cpp
--- a/dom/base/Document.cpp
+++ b/dom/base/Document.cpp
@@ -6739,18 +6739,17 @@ nsINode* Document::AdoptNode(nsINode& aA
 
   nsCOMPtr<Document> oldDocument = adoptedNode->OwnerDoc();
   bool sameDocument = oldDocument == this;
 
   AutoJSContext cx;
   JS::Rooted<JSObject*> newScope(cx, nullptr);
   if (!sameDocument) {
     newScope = GetWrapper();
-    if (!newScope && GetScopeObject() &&
-        GetScopeObject()->GetGlobalJSObject()) {
+    if (!newScope && GetScopeObject() && GetScopeObject()->HasJSGlobal()) {
       // Make sure cx is in a semi-sane compartment before we call WrapNative.
       // It's kind of irrelevant, given that we're passing aAllowWrapping =
       // false, and documents should always insist on being wrapped in an
       // canonical scope. But we try to pass something sane anyway.
       JSObject* globalObject = GetScopeObject()->GetGlobalJSObject();
       JS::ExposeObjectToActiveJS(globalObject);
       JSAutoRealm ar(cx, globalObject);
       JS::Rooted<JS::Value> v(cx);
@@ -7430,17 +7429,17 @@ bool Document::IsScriptEnabled() {
   // If this document is sandboxed without 'allow-scripts'
   // script is not enabled
   if (HasScriptsBlockedBySandbox()) {
     return false;
   }
 
   nsCOMPtr<nsIScriptGlobalObject> globalObject =
       do_QueryInterface(GetInnerWindow());
-  if (!globalObject || !globalObject->GetGlobalJSObject()) {
+  if (!globalObject || !globalObject->HasJSGlobal()) {
     return false;
   }
 
   return xpc::Scriptability::Get(globalObject->GetGlobalJSObject()).Allowed();
 }
 
 void Document::RetrieveRelevantHeaders(nsIChannel* aChannel) {
   PRTime modDate = 0;
@@ -9883,33 +9882,35 @@ nsIDOMXULCommandDispatcher* Document::Ge
 
 void Document::InitializeXULBroadcastManager() {
   if (mXULBroadcastManager) {
     return;
   }
   mXULBroadcastManager = new XULBroadcastManager(this);
 }
 
-static JSObject* GetScopeObjectOfNode(nsINode* node) {
+static bool NodeHasScopeObject(nsINode* node) {
   MOZ_ASSERT(node, "Must not be called with null.");
 
   // Window root occasionally keeps alive a node of a document whose
   // window is already dead. If in this brief period someone calls
   // GetPopupNode and we return that node, we can end up creating a
   // reflector for the node in the wrong global (the current global,
   // not the document global, because we won't know what the document
   // global is).  Returning an orphan node like that to JS would be a
   // bug anyway, so to avoid this, let's do the same check as fetching
-  // GetParentObjet() on the document does to determine the scope and
-  // if it returns null let's just return null in XULDocument::GetPopupNode.
+  // GetParentObject() on the document does to determine the scope and
+  // if there is no usable scope object let's report that and return
+  // null from Document::GetPopupNode instead of returning a node that
+  // will get a reflector in the wrong scope.
   Document* doc = node->OwnerDoc();
   MOZ_ASSERT(doc, "This should never happen.");
 
   nsIGlobalObject* global = doc->GetScopeObject();
-  return global ? global->GetGlobalJSObject() : nullptr;
+  return global ? global->HasJSGlobal() : false;
 }
 
 already_AddRefed<nsPIWindowRoot> Document::GetWindowRoot() {
   if (!mDocumentContainer) {
     return nullptr;
   }
   // XXX It's unclear why this can't just use GetWindow().
   nsCOMPtr<nsPIDOMWindowOuter> piWin = mDocumentContainer->GetWindow();
@@ -9925,17 +9926,17 @@ already_AddRefed<nsINode> Document::GetP
 
   if (!node) {
     nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
     if (pm) {
       node = pm->GetLastTriggerPopupNode(this);
     }
   }
 
-  if (node && GetScopeObjectOfNode(node)) {
+  if (node && NodeHasScopeObject(node)) {
     return node.forget();
   }
 
   return nullptr;
 }
 
 void Document::SetPopupNode(nsINode* aNode) {
   nsCOMPtr<nsPIWindowRoot> rootWin = GetWindowRoot();
--- a/dom/base/nsIGlobalObject.h
+++ b/dom/base/nsIGlobalObject.h
@@ -91,16 +91,22 @@ class nsIGlobalObject : public nsISuppor
    * situations where we are sure no CC activity can happen while the return
    * value is used and the return value does not end up escaping to the heap in
    * any way.  In all other cases, and in particular in cases where the return
    * value is held in a JS::Rooted or passed to the JSAutoRealm constructor, use
    * GetGlobalJSObject.
    */
   virtual JSObject* GetGlobalJSObjectPreserveColor() const = 0;
 
+  /**
+   * Check whether this nsIGlobalObject still has a JSObject associated with it,
+   * or whether it's torn-down enough that the JSObject is gone.
+   */
+  bool HasJSGlobal() const { return GetGlobalJSObjectPreserveColor(); }
+
   // This method is not meant to be overridden.
   nsIPrincipal* PrincipalOrNull();
 
   void RegisterHostObjectURI(const nsACString& aURI);
 
   void UnregisterHostObjectURI(const nsACString& aURI);
 
   // Any CC class inheriting nsIGlobalObject should call these 2 methods if it
--- a/dom/bindings/CallbackObject.cpp
+++ b/dom/bindings/CallbackObject.cpp
@@ -199,34 +199,34 @@ CallbackObject::CallSetup::CallSetup(Cal
     } else {
       // No DOM Window. Store the global.
       globalObject = xpc::NativeGlobal(realCallback);
       MOZ_ASSERT(globalObject);
     }
   }
 
   // Bail out if there's no useful global.
-  if (!globalObject->GetGlobalJSObject()) {
+  if (!globalObject->HasJSGlobal()) {
     aRv.ThrowDOMException(
         NS_ERROR_DOM_NOT_SUPPORTED_ERR,
         NS_LITERAL_CSTRING("Refusing to execute function from global which is "
                            "being torn down."));
     return;
   }
 
   mAutoEntryScript.emplace(globalObject, aExecutionReason, mIsMainThread);
   mAutoEntryScript->SetWebIDLCallerPrincipal(webIDLCallerPrincipal);
   nsIGlobalObject* incumbent = aCallback->IncumbentGlobalOrNull();
   if (incumbent) {
     // The callback object traces its incumbent JS global, so in general it
     // should be alive here. However, it's possible that we could run afoul
     // of the same IPC global weirdness described above, wherein the
     // nsIGlobalObject has severed its reference to the JS global. Let's just
     // be safe here, so that nobody has to waste a day debugging gaia-ui tests.
-    if (!incumbent->GetGlobalJSObject()) {
+    if (!incumbent->HasJSGlobal()) {
       aRv.ThrowDOMException(
           NS_ERROR_DOM_NOT_SUPPORTED_ERR,
           NS_LITERAL_CSTRING("Refusing to execute function because our "
                              "incumbent global is being torn down."));
       return;
     }
     mAutoIncumbentScript.emplace(incumbent);
   }
--- a/dom/events/EventListenerManager.cpp
+++ b/dom/events/EventListenerManager.cpp
@@ -820,17 +820,17 @@ nsresult EventListenerManager::SetEventH
   // We must init the language before we attempt to fetch its context.
   if (NS_FAILED(global->EnsureScriptEnvironment())) {
     NS_WARNING("Failed to setup script environment for this language");
     // but fall through and let the inevitable failure below handle it.
   }
 
   nsIScriptContext* context = global->GetScriptContext();
   NS_ENSURE_TRUE(context, NS_ERROR_FAILURE);
-  NS_ENSURE_STATE(global->GetGlobalJSObject());
+  NS_ENSURE_STATE(global->HasJSGlobal());
 
   Listener* listener = SetEventHandlerInternal(aName, TypedEventHandler(),
                                                aPermitUntrustedEvents);
 
   if (!aDeferCompilation) {
     return CompileEventHandlerInternal(listener, &aBody, aElement);
   }
 
--- a/dom/media/webaudio/AudioBuffer.cpp
+++ b/dom/media/webaudio/AudioBuffer.cpp
@@ -255,17 +255,17 @@ static void CopyChannelDataToFloat(const
     MOZ_ASSERT(aChunk.mBufferFormat == AUDIO_FORMAT_S16);
     ConvertAudioSamples(aChunk.ChannelData<int16_t>()[aChannel] + aSrcOffset,
                         aOutput, aLength);
   }
 }
 
 bool AudioBuffer::RestoreJSChannelData(JSContext* aJSContext) {
   nsPIDOMWindowInner* global = GetParentObject();
-  if (!global || !global->AsGlobal()->GetGlobalJSObject()) {
+  if (!global || !global->AsGlobal()->HasJSGlobal()) {
     return false;
   }
 
   JSAutoRealm ar(aJSContext, global->AsGlobal()->GetGlobalJSObject());
 
   for (uint32_t i = 0; i < mJSChannels.Length(); ++i) {
     if (mJSChannels[i]) {
       // Already have data in JS array.
@@ -385,17 +385,17 @@ void AudioBuffer::GetChannelData(JSConte
   }
 
   aRetval.set(mJSChannels[aChannel]);
 }
 
 already_AddRefed<ThreadSharedFloatArrayBufferList>
 AudioBuffer::StealJSArrayDataIntoSharedChannels(JSContext* aJSContext) {
   nsPIDOMWindowInner* global = GetParentObject();
-  if (!global || !global->AsGlobal()->GetGlobalJSObject()) {
+  if (!global || !global->AsGlobal()->HasJSGlobal()) {
     return nullptr;
   }
 
   JSAutoRealm ar(aJSContext, global->AsGlobal()->GetGlobalJSObject());
 
   // "1. If any of the AudioBuffer's ArrayBuffer have been detached, abort
   // these steps, and return a zero-length channel data buffers to the
   // invoker."
--- a/dom/script/ScriptSettings.cpp
+++ b/dom/script/ScriptSettings.cpp
@@ -126,26 +126,26 @@ void DestroyScriptSettings() {
 }
 
 bool ScriptSettingsInitialized() { return sScriptSettingsTLSInitialized; }
 
 ScriptSettingsStackEntry::ScriptSettingsStackEntry(nsIGlobalObject* aGlobal,
                                                    Type aType)
     : mGlobalObject(aGlobal), mType(aType), mOlder(nullptr) {
   MOZ_ASSERT_IF(IsIncumbentCandidate() && !NoJSAPI(), mGlobalObject);
-  MOZ_ASSERT(!mGlobalObject || mGlobalObject->GetGlobalJSObject(),
+  MOZ_ASSERT(!mGlobalObject || mGlobalObject->HasJSGlobal(),
              "Must have an actual JS global for the duration on the stack");
   MOZ_ASSERT(
       !mGlobalObject || JS_IsGlobalObject(mGlobalObject->GetGlobalJSObject()),
       "No outer windows allowed");
 }
 
 ScriptSettingsStackEntry::~ScriptSettingsStackEntry() {
   // We must have an actual JS global for the entire time this is on the stack.
-  MOZ_ASSERT_IF(mGlobalObject, mGlobalObject->GetGlobalJSObject());
+  MOZ_ASSERT_IF(mGlobalObject, mGlobalObject->HasJSGlobal());
 }
 
 // If the entry or incumbent global ends up being something that the subject
 // principal doesn't subsume, we don't want to use it. This never happens on
 // the web, but can happen with asymmetric privilege relationships (i.e.
 // ExpandedPrincipal and System Principal).
 //
 // The most correct thing to use instead would be the topmost global on the
@@ -378,17 +378,17 @@ void AutoJSAPI::InitInternal(nsIGlobalOb
 #endif  // DEBUG
 }
 
 AutoJSAPI::AutoJSAPI(nsIGlobalObject* aGlobalObject, bool aIsMainThread,
                      Type aType)
     : ScriptSettingsStackEntry(aGlobalObject, aType),
       mIsMainThread(aIsMainThread) {
   MOZ_ASSERT(aGlobalObject);
-  MOZ_ASSERT(aGlobalObject->GetGlobalJSObject(), "Must have a JS global");
+  MOZ_ASSERT(aGlobalObject->HasJSGlobal(), "Must have a JS global");
   MOZ_ASSERT(aIsMainThread == NS_IsMainThread());
 
   InitInternal(aGlobalObject, aGlobalObject->GetGlobalJSObject(),
                danger::GetJSContext(), aIsMainThread);
 }
 
 void AutoJSAPI::Init() {
   MOZ_ASSERT(!mCx, "An AutoJSAPI should only be initialised once");
--- a/js/xpconnect/src/XPCWrappedJSClass.cpp
+++ b/js/xpconnect/src/XPCWrappedJSClass.cpp
@@ -324,17 +324,17 @@ nsresult nsXPCWrappedJS::DelegatedQueryI
   // QI on an XPCWrappedJS can run script, so we need an AutoEntryScript.
   // This is inherently Gecko-specific.
   // We check both nativeGlobal and nativeGlobal->GetGlobalJSObject() even
   // though we have derived nativeGlobal from the JS global, because we know
   // there are cases where this can happen. See bug 1094953.
   RootedObject obj(RootingCx(), GetJSObject());
   nsIGlobalObject* nativeGlobal = NativeGlobal(js::UncheckedUnwrap(obj));
   NS_ENSURE_TRUE(nativeGlobal, NS_ERROR_FAILURE);
-  NS_ENSURE_TRUE(nativeGlobal->GetGlobalJSObject(), NS_ERROR_FAILURE);
+  NS_ENSURE_TRUE(nativeGlobal->HasJSGlobal(), NS_ERROR_FAILURE);
   AutoEntryScript aes(nativeGlobal, "XPCWrappedJS QueryInterface",
                       /* aIsMainThread = */ true);
   XPCCallContext ccx(aes.cx());
   if (!ccx.IsValid()) {
     *aInstancePtr = nullptr;
     return NS_NOINTERFACE;
   }
 
--- a/layout/printing/nsPrintJob.cpp
+++ b/layout/printing/nsPrintJob.cpp
@@ -3214,38 +3214,38 @@ void nsPrintJob::TurnScriptingOn(bool aD
 
     Document* doc = po->mDocument;
     if (!doc) {
       continue;
     }
 
     if (nsCOMPtr<nsPIDOMWindowInner> window = doc->GetInnerWindow()) {
       nsCOMPtr<nsIGlobalObject> go = window->AsGlobal();
-      NS_WARNING_ASSERTION(go->GetGlobalJSObject(), "Can't get global");
+      NS_WARNING_ASSERTION(go->HasJSGlobal(), "Window has no global");
       nsresult propThere = NS_PROPTABLE_PROP_NOT_THERE;
       doc->GetProperty(nsGkAtoms::scriptEnabledBeforePrintOrPreview,
                        &propThere);
       if (aDoTurnOn) {
         if (propThere != NS_PROPTABLE_PROP_NOT_THERE) {
           doc->DeleteProperty(nsGkAtoms::scriptEnabledBeforePrintOrPreview);
-          if (go->GetGlobalJSObject()) {
+          if (go->HasJSGlobal()) {
             xpc::Scriptability::Get(go->GetGlobalJSObject()).Unblock();
           }
           window->Resume();
         }
       } else {
         // Have to be careful, because people call us over and over again with
         // aDoTurnOn == false.  So don't set the property if it's already
         // set, since in that case we'd set it to the wrong value.
         if (propThere == NS_PROPTABLE_PROP_NOT_THERE) {
           // Stash the current value of IsScriptEnabled on the document, so
           // that layout code running in print preview doesn't get confused.
           doc->SetProperty(nsGkAtoms::scriptEnabledBeforePrintOrPreview,
                            NS_INT32_TO_PTR(doc->IsScriptEnabled()));
-          if (go && go->GetGlobalJSObject()) {
+          if (go && go->HasJSGlobal()) {
             xpc::Scriptability::Get(go->GetGlobalJSObject()).Block();
           }
           window->Suspend();
         }
       }
     }
   }
 }
--- a/xpcom/base/CycleCollectedJSRuntime.cpp
+++ b/xpcom/base/CycleCollectedJSRuntime.cpp
@@ -1439,17 +1439,17 @@ void CycleCollectedJSRuntime::PrepareWai
 }
 
 void CycleCollectedJSRuntime::EnvironmentPreparer::invoke(
     JS::HandleObject global, js::ScriptEnvironmentPreparer::Closure& closure) {
   MOZ_ASSERT(JS_IsGlobalObject(global));
   nsIGlobalObject* nativeGlobal = xpc::NativeGlobal(global);
 
   // Not much we can do if we simply don't have a usable global here...
-  NS_ENSURE_TRUE_VOID(nativeGlobal && nativeGlobal->GetGlobalJSObject());
+  NS_ENSURE_TRUE_VOID(nativeGlobal && nativeGlobal->HasJSGlobal());
 
   AutoEntryScript aes(nativeGlobal, "JS-engine-initiated execution");
 
   MOZ_ASSERT(!JS_IsExceptionPending(aes.cx()));
 
   DebugOnly<bool> ok = closure(aes.cx());
 
   MOZ_ASSERT_IF(ok, !JS_IsExceptionPending(aes.cx()));