Bug 1538470 - Null-check the global when creating AudioNodes. r=karlt
authorPaul Adenot <paul@paul.cx>
Tue, 26 Mar 2019 12:22:10 +0000
changeset 466091 58fe84489519e891e049ad1eccee5f7ad046c1ba
parent 466090 6e7b485a2f314633b7f059095207ad3655d83759
child 466092 9f7a419466c3f4f13d426ba5c2cfb563e5e0bc03
child 466148 323398f596cc0d8770c130344f43c1663e1e0772
push id81435
push userpadenot@mozilla.com
push dateTue, 26 Mar 2019 12:40:33 +0000
treeherderautoland@58fe84489519 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskarlt
bugs1538470
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 1538470 - Null-check the global when creating AudioNodes. r=karlt This is now necessary, because it's possible to effectively create new AudioNodes on during shutdown, when the global is not available anymore. It is unnecessary to null-check in the AudioNodeEngine methods, because they will not run in this scenario. This also renames the function because it can now return nullptr. Differential Revision: https://phabricator.services.mozilla.com/D24688
dom/media/webaudio/AudioDestinationNode.cpp
dom/media/webaudio/AudioNode.cpp
dom/media/webaudio/AudioNode.h
dom/media/webaudio/AudioNodeEngine.cpp
dom/media/webaudio/MediaElementAudioSourceNode.cpp
--- a/dom/media/webaudio/AudioDestinationNode.cpp
+++ b/dom/media/webaudio/AudioDestinationNode.cpp
@@ -408,18 +408,18 @@ void AudioDestinationNode::DestroyMediaS
   }
   AudioNode::DestroyMediaStream();
 }
 
 void AudioDestinationNode::NotifyMainThreadStreamFinished() {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(mStream->IsFinished());
 
-  if (mIsOffline) {
-    AbstractMainThread()->Dispatch(NewRunnableMethod(
+  if (mIsOffline && GetAbstractMainThread()) {
+    GetAbstractMainThread()->Dispatch(NewRunnableMethod(
         "dom::AudioDestinationNode::FireOfflineCompletionEvent", this,
         &AudioDestinationNode::FireOfflineCompletionEvent));
   }
 }
 
 void AudioDestinationNode::FireOfflineCompletionEvent() {
   OfflineDestinationNodeEngine* engine =
       static_cast<OfflineDestinationNodeEngine*>(Stream()->Engine());
--- a/dom/media/webaudio/AudioNode.cpp
+++ b/dom/media/webaudio/AudioNode.cpp
@@ -48,18 +48,21 @@ AudioNode::AudioNode(AudioContext* aCont
                      ChannelInterpretation aChannelInterpretation)
     : DOMEventTargetHelper(aContext->GetParentObject()),
       mContext(aContext),
       mChannelCount(aChannelCount),
       mChannelCountMode(aChannelCountMode),
       mChannelInterpretation(aChannelInterpretation),
       mId(gId++),
       mPassThrough(false),
-      mAbstractMainThread(aContext->GetOwnerGlobal()->AbstractMainThreadFor(
-          TaskCategory::Other)) {
+      mAbstractMainThread(
+          aContext->GetOwnerGlobal()
+              ? aContext->GetOwnerGlobal()->AbstractMainThreadFor(
+                    TaskCategory::Other)
+              : nullptr) {
   MOZ_ASSERT(aContext);
   aContext->RegisterNode(this);
 }
 
 AudioNode::~AudioNode() {
   MOZ_ASSERT(mInputNodes.IsEmpty());
   MOZ_ASSERT(mOutputNodes.IsEmpty());
   MOZ_ASSERT(mOutputParams.IsEmpty());
--- a/dom/media/webaudio/AudioNode.h
+++ b/dom/media/webaudio/AudioNode.h
@@ -193,17 +193,19 @@ class AudioNode : public DOMEventTargetH
 
   virtual size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const;
   virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const;
 
   // Returns a string from constant static storage identifying the dom node
   // type.
   virtual const char* NodeType() const = 0;
 
-  AbstractThread* AbstractMainThread() const { return mAbstractMainThread; }
+  // This can return nullptr, but only when the AudioNode has been created
+  // during document shutdown.
+  AbstractThread* GetAbstractMainThread() const { return mAbstractMainThread; }
 
  private:
   // Given:
   //
   // - a DestinationType, that can be an AudioNode or an AudioParam ;
   // - a Predicate, a function that takes an InputNode& and returns a bool ;
   //
   // This method iterates on the InputNodes() of the node at the index
--- a/dom/media/webaudio/AudioNodeEngine.cpp
+++ b/dom/media/webaudio/AudioNodeEngine.cpp
@@ -362,18 +362,19 @@ float AudioBufferSumOfSquares(const floa
   return sum;
 }
 
 AudioNodeEngine::AudioNodeEngine(dom::AudioNode* aNode)
     : mNode(aNode),
       mNodeType(aNode ? aNode->NodeType() : nullptr),
       mInputCount(aNode ? aNode->NumberOfInputs() : 1),
       mOutputCount(aNode ? aNode->NumberOfOutputs() : 0),
-      mAbstractMainThread(aNode ? aNode->AbstractMainThread()
-                                : AbstractThread::MainThread()) {
+      mAbstractMainThread(aNode && aNode->GetAbstractMainThread()
+                              ? aNode->GetAbstractMainThread()
+                              : AbstractThread::MainThread()) {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_COUNT_CTOR(AudioNodeEngine);
 }
 
 void AudioNodeEngine::ProcessBlock(AudioNodeStream* aStream, GraphTime aFrom,
                                    const AudioBlock& aInput,
                                    AudioBlock* aOutput, bool* aFinished) {
   MOZ_ASSERT(mInputCount <= 1 && mOutputCount <= 1);
--- a/dom/media/webaudio/MediaElementAudioSourceNode.cpp
+++ b/dom/media/webaudio/MediaElementAudioSourceNode.cpp
@@ -48,17 +48,17 @@ JSObject* MediaElementAudioSourceNode::W
     JSContext* aCx, JS::Handle<JSObject*> aGivenProto) {
   return MediaElementAudioSourceNode_Binding::Wrap(aCx, this, aGivenProto);
 }
 
 void MediaElementAudioSourceNode::ListenForAllowedToPlay(
     const MediaElementAudioSourceOptions& aOptions) {
   aOptions.mMediaElement->GetAllowedToPlayPromise()
       ->Then(
-          AbstractMainThread(), __func__,
+          GetAbstractMainThread(), __func__,
           // Capture by reference to bypass the mozilla-refcounted-inside-lambda
           // static analysis. We capture a non-owning reference so as to allow
           // cycle collection of the node. The reference is cleared via
           // DisconnectIfExists() from Destroy() when the node is collected.
           [& self = *this]() {
             self.Context()->StartBlockedAudioContextIfAllowed();
             self.mAllowedToPlayRequest.Complete();
           })