Bug 1291702 - Refactor the input node iteration loop on destination node when disconnecting nodes. r=karlt
authorPaul Adenot <paul@paul.cx>
Fri, 09 Sep 2016 13:41:01 +0200
changeset 318833 4c6215e05eccb53a3500c1d63b038c03b606785f
parent 318832 37434b4379d9b9891cbbb6157a709e45b64f2a41
child 318834 0be26309f50b477ec9f0ef800c5f2475e097125f
push id30854
push userryanvm@gmail.com
push dateFri, 21 Oct 2016 21:08:02 +0000
treeherdermozilla-central@806054dd12bd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskarlt
bugs1291702
milestone52.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 1291702 - Refactor the input node iteration loop on destination node when disconnecting nodes. r=karlt MozReview-Commit-ID: FE19hEVhA7R
dom/media/webaudio/AudioNode.cpp
dom/media/webaudio/AudioNode.h
--- a/dom/media/webaudio/AudioNode.cpp
+++ b/dom/media/webaudio/AudioNode.cpp
@@ -287,22 +287,22 @@ AudioNode::SendChannelMixingParametersTo
 {
   if (mStream) {
     mStream->SetChannelMixingParameters(mChannelCount, mChannelCountMode,
                                         mChannelInterpretation);
   }
 }
 
 bool
-AudioNode::DisconnectFromOutputIfConnected(AudioNode& aDestination, uint32_t aOutputIndex, uint32_t aInputIndex)
+AudioNode::DisconnectFromOutputIfConnected(AudioNode& aDestination, uint32_t aOutputNodeIndex, uint32_t aInputIndex)
 {
   WEB_AUDIO_API_LOG("%f: %s %u Disconnect()", Context()->CurrentTime(),
                     NodeType(), Id());
 
-  MOZ_ASSERT(aOutputIndex < mOutputNodes.Length());
+  MOZ_ASSERT(aOutputNodeIndex < mOutputNodes.Length());
   MOZ_ASSERT(aInputIndex < aDestination.InputNodes().Length());
 
   // An upstream node may be starting to play on the graph thread, and the
   // engine for a downstream node may be sending a PlayingRefChangeHandler
   // ADDREF message to this (main) thread.  Wait for a round trip before
   // releasing nodes, to give engines receiving sound now time to keep their
   // nodes alive.
   class RunnableRelease final : public Runnable
@@ -327,99 +327,104 @@ AudioNode::DisconnectFromOutputIfConnect
 
   // Destroying the InputNode here sends a message to the graph thread
   // to disconnect the streams, which should be sent before the
   // RunAfterPendingUpdates() call below.
   aDestination.mInputNodes.RemoveElementAt(aInputIndex);
   // Remove one instance of 'dest' from mOutputNodes. There could be
   // others, and it's not correct to remove them all since some of them
   // could be for different output ports.
-  RefPtr<AudioNode> output = mOutputNodes[aOutputIndex].forget();
-  mOutputNodes.RemoveElementAt(aOutputIndex);
+  RefPtr<AudioNode> output = mOutputNodes[aOutputNodeIndex].forget();
+  mOutputNodes.RemoveElementAt(aOutputNodeIndex);
   output->NotifyInputsChanged();
   if (mStream) {
     nsCOMPtr<nsIRunnable> runnable = new RunnableRelease(output.forget());
     mStream->RunAfterPendingUpdates(runnable.forget());
   }
   return true;
 }
 
 bool
-AudioNode::DisconnectFromParamIfConnected(AudioParam& aDestination, uint32_t aOutputIndex, uint32_t aInputIndex)
+AudioNode::DisconnectFromOutputIfConnected(AudioParam& aDestination, uint32_t aOutputParamIndex, uint32_t aInputIndex)
 {
-  MOZ_ASSERT(aOutputIndex < mOutputParams.Length());
+  MOZ_ASSERT(aOutputParamIndex < mOutputParams.Length());
   MOZ_ASSERT(aInputIndex < aDestination.InputNodes().Length());
 
   const InputNode& input = aDestination.InputNodes()[aInputIndex];
   if (input.mInputNode != this) {
     return false;
   }
   aDestination.RemoveInputNode(aInputIndex);
   // Remove one instance of 'dest' from mOutputParams. There could be
   // others, and it's not correct to remove them all since some of them
   // could be for different output ports.
-  mOutputParams.RemoveElementAt(aOutputIndex);
+  mOutputParams.RemoveElementAt(aOutputParamIndex);
   return true;
 }
 
+template<typename DestinationType, typename Predicate>
+bool
+AudioNode::DisconnectMatchingDestinationInputs(DestinationType& aDestination,
+                                               uint32_t aDestinationIndex,
+                                               Predicate aPredicate)
+{
+  bool wasConnected = false;
+  for (int32_t inputIndex = aDestination.InputNodes().Length() - 1; inputIndex >= 0; --inputIndex) {
+    const InputNode& input = aDestination.InputNodes()[inputIndex];
+    if (aPredicate(input)) {
+      if (DisconnectFromOutputIfConnected(aDestination, aDestinationIndex, inputIndex)) {
+        wasConnected = true;
+        break;
+      }
+    }
+  }
+  return wasConnected;
+}
+
 void
 AudioNode::Disconnect(ErrorResult& aRv)
 {
   for (int32_t outputIndex = mOutputNodes.Length() - 1; outputIndex >= 0; --outputIndex) {
     AudioNode* dest = mOutputNodes[outputIndex];
-    for (int32_t inputIndex = dest->mInputNodes.Length() - 1; inputIndex >= 0; --inputIndex) {
-      if (DisconnectFromOutputIfConnected(*dest, outputIndex, inputIndex)) {
-        break;
-      }
-    }
+    DisconnectMatchingDestinationInputs(*dest, outputIndex,
+                                        [](const InputNode&) { return true; });
   }
 
   for (int32_t outputIndex = mOutputParams.Length() - 1; outputIndex >= 0; --outputIndex) {
     AudioParam* dest = mOutputParams[outputIndex];
-    for (int32_t inputIndex = dest->InputNodes().Length() - 1; inputIndex >= 0; --inputIndex) {
-      if (DisconnectFromParamIfConnected(*dest, outputIndex, inputIndex)) {
-        break;
-      }
-    }
+    DisconnectMatchingDestinationInputs(*dest, outputIndex,
+                                        [](const InputNode&) { return true; });
   }
 
   // This disconnection may have disconnected a panner and a source.
   Context()->UpdatePannerSource();
 }
 
 void
 AudioNode::Disconnect(uint32_t aOutput, ErrorResult& aRv)
 {
   if (aOutput >= NumberOfOutputs()) {
     aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
     return;
   }
 
   for (int32_t outputIndex = mOutputNodes.Length() - 1; outputIndex >= 0; --outputIndex) {
     AudioNode* dest = mOutputNodes[outputIndex];
-    for (int32_t inputIndex = dest->mInputNodes.Length() - 1; inputIndex >= 0; --inputIndex) {
-      InputNode& input = dest->mInputNodes[inputIndex];
-      if (input.mOutputPort == aOutput) {
-        if (DisconnectFromOutputIfConnected(*dest, outputIndex, inputIndex)) {
-          break;
-        }
-      }
-    }
+    DisconnectMatchingDestinationInputs(*dest, outputIndex,
+                                        [aOutput](const InputNode& aInput) {
+                                          return aInput.mOutputPort == aOutput;
+                                        });
   }
 
   for (int32_t outputIndex = mOutputParams.Length() - 1; outputIndex >= 0; --outputIndex) {
     AudioParam* dest = mOutputParams[outputIndex];
-    for (int32_t inputIndex = dest->InputNodes().Length() - 1; inputIndex >= 0; --inputIndex) {
-      const InputNode& input = dest->InputNodes()[inputIndex];
-      if (input.mOutputPort == aOutput) {
-        if (DisconnectFromParamIfConnected(*dest, outputIndex, inputIndex)) {
-          break;
-        }
-      }
-    }
+    DisconnectMatchingDestinationInputs(*dest, outputIndex,
+                                        [aOutput](const InputNode& aInput) {
+                                          return aInput.mOutputPort == aOutput;
+                                        });
   }
 
   // This disconnection may have disconnected a panner and a source.
   Context()->UpdatePannerSource();
 }
 
 void
 AudioNode::Disconnect(AudioNode& aDestination, ErrorResult& aRv)
@@ -450,25 +455,21 @@ AudioNode::Disconnect(AudioNode& aDestin
   if (aOutput >= NumberOfOutputs()) {
     aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
     return;
   }
 
   bool wasConnected = false;
 
   for (int32_t outputIndex = mOutputNodes.Length() - 1; outputIndex >= 0; --outputIndex) {
-    for (int32_t inputIndex = aDestination.mInputNodes.Length() - 1; inputIndex >= 0; --inputIndex) {
-      InputNode& input = aDestination.mInputNodes[inputIndex];
-      if (input.mOutputPort == aOutput) {
-        if (DisconnectFromOutputIfConnected(aDestination, outputIndex, inputIndex)) {
-          wasConnected = true;
-          break;
-        }
-      }
-    }
+    wasConnected |=
+      DisconnectMatchingDestinationInputs(aDestination, outputIndex,
+                                          [aOutput](const InputNode& aInput) {
+                                            return aInput.mOutputPort == aOutput;
+                                          });
   }
 
   if (!wasConnected) {
     aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
     return;
   }
 
   // This disconnection may have disconnected a panner and a source.
@@ -486,23 +487,22 @@ AudioNode::Disconnect(AudioNode& aDestin
   if (aInput >= aDestination.NumberOfInputs()) {
     aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
     return;
   }
 
   bool wasConnected = false;
 
   for (int32_t outputIndex = mOutputNodes.Length() - 1; outputIndex >= 0; --outputIndex) {
-    for (int32_t inputIndex = aDestination.mInputNodes.Length() - 1; inputIndex >= 0; --inputIndex) {
-      InputNode& input = aDestination.mInputNodes[inputIndex];
-      if (input.mOutputPort == aOutput && input.mInputPort == aInput) {
-        wasConnected |= DisconnectFromOutputIfConnected(aDestination, outputIndex, inputIndex);
-        break;
-      }
-    }
+    wasConnected |=
+      DisconnectMatchingDestinationInputs(aDestination, outputIndex,
+                                          [aOutput, aInput](const InputNode& aInputNode) {
+                                            return aInputNode.mOutputPort == aOutput &&
+                                                   aInputNode.mInputPort == aInput;
+                                          });
   }
 
   if (!wasConnected) {
     aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
     return;
   }
 
   // This disconnection may have disconnected a panner and a source.
@@ -510,22 +510,19 @@ AudioNode::Disconnect(AudioNode& aDestin
 }
 
 void
 AudioNode::Disconnect(AudioParam& aDestination, ErrorResult& aRv)
 {
   bool wasConnected = false;
 
   for (int32_t outputIndex = mOutputParams.Length() - 1; outputIndex >= 0; --outputIndex) {
-    for (int32_t inputIndex = aDestination.InputNodes().Length() - 1; inputIndex >= 0; --inputIndex) {
-        if (DisconnectFromParamIfConnected(aDestination, outputIndex, inputIndex)) {
-          wasConnected = true;
-          break;
-        }
-    }
+    wasConnected |=
+      DisconnectMatchingDestinationInputs(aDestination, outputIndex,
+                                          [](const InputNode&) { return true; });
   }
 
   if (!wasConnected) {
     aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
     return;
   }
 }
 
@@ -535,25 +532,21 @@ AudioNode::Disconnect(AudioParam& aDesti
   if (aOutput >= NumberOfOutputs()) {
     aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
     return;
   }
 
   bool wasConnected = false;
 
   for (int32_t outputIndex = mOutputParams.Length() - 1; outputIndex >= 0; --outputIndex) {
-    for (int32_t inputIndex = aDestination.InputNodes().Length() - 1; inputIndex >= 0; --inputIndex) {
-      const InputNode& input = aDestination.InputNodes()[inputIndex];
-      if (input.mOutputPort == aOutput) {
-        if (DisconnectFromParamIfConnected(aDestination, outputIndex, inputIndex)) {
-          wasConnected = true;
-          break;
-        }
-      }
-    }
+    wasConnected |=
+      DisconnectMatchingDestinationInputs(aDestination, outputIndex,
+                                          [aOutput](const InputNode& aNode) {
+                                            return aNode.mOutputPort == aOutput;
+                                          });
   }
 
   if (!wasConnected) {
     aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
     return;
   }
 }
 
--- a/dom/media/webaudio/AudioNode.h
+++ b/dom/media/webaudio/AudioNode.h
@@ -217,26 +217,39 @@ public:
   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;
 
 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 aDestination, and calls
+  // `DisconnectFromOutputIfConnected` with this input node, if aPredicate
+  // returns true.
+  template<typename DestinationType, typename Predicate>
+  bool DisconnectMatchingDestinationInputs(DestinationType& aDestination,
+                                           uint32_t aDestinationIndex,
+                                           Predicate aPredicate);
+
   virtual void LastRelease() override
   {
     // We are about to be deleted, disconnect the object from the graph before
     // the derived type is destroyed.
     DisconnectFromGraph();
   }
   // Callers must hold a reference to 'this'.
   void DisconnectFromGraph();
   bool DisconnectFromOutputIfConnected(AudioNode& aDestination, uint32_t aOutputIndex, uint32_t aInputIndex);
-  bool DisconnectFromParamIfConnected(AudioParam& aDestination, uint32_t aOutputIndex, uint32_t aInputIndex);
+  bool DisconnectFromOutputIfConnected(AudioParam& aDestination, uint32_t aOutputIndex, uint32_t aInputIndex);
 
 protected:
   // Helpers for sending different value types to streams
   void SendDoubleParameterToStream(uint32_t aIndex, double aValue);
   void SendInt32ParameterToStream(uint32_t aIndex, int32_t aValue);
   void SendThreeDPointParameterToStream(uint32_t aIndex, const ThreeDPoint& aValue);
   void SendChannelMixingParametersToStream();