Bug 1162663 - Convert nsHashtable to nsObserverTArray in AudioChannelService. r=alwu, r=ehsan, a=jocheng
☠☠ backed out by 8045028bf400 ☠ ☠
authorAndrea Marchesini <amarchesini@mozilla.com>
Wed, 03 Jun 2015 03:32:00 -0400
changeset 238637 bf3531db0d545c1950c7889539bd7ea31d7eb189
parent 238636 b69b68b8a0a719261469c61e1f9c2f4c2c9e0cfe
child 238638 6dd1b4a1f8b89a003538915776e8bb066500b14d
push id697
push userryanvm@gmail.com
push dateMon, 15 Jun 2015 15:18:08 +0000
treeherdermozilla-b2g37_v2_2@bf3531db0d54 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersalwu, ehsan, jocheng
bugs1162663
milestone37.0
Bug 1162663 - Convert nsHashtable to nsObserverTArray in AudioChannelService. r=alwu, r=ehsan, a=jocheng
dom/audiochannel/AudioChannelService.cpp
dom/audiochannel/AudioChannelService.h
dom/audiochannel/AudioChannelServiceChild.cpp
dom/audiochannel/AudioChannelServiceChild.h
--- a/dom/audiochannel/AudioChannelService.cpp
+++ b/dom/audiochannel/AudioChannelService.cpp
@@ -57,17 +57,16 @@ AudioChannelService::GetAudioChannelServ
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (XRE_GetProcessType() != GeckoProcessType_Default) {
     return AudioChannelServiceChild::GetAudioChannelService();
   }
 
   return gAudioChannelService;
-
 }
 
 // static
 AudioChannelService*
 AudioChannelService::GetOrCreateAudioChannelService()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
@@ -131,21 +130,22 @@ void
 AudioChannelService::RegisterAudioChannelAgent(AudioChannelAgent* aAgent,
                                                AudioChannel aChannel,
                                                bool aWithVideo)
 {
   if (mDisabled) {
     return;
   }
 
-  AudioChannelAgentData* data = new AudioChannelAgentData(aChannel,
-                                true /* aElementHidden */,
-                                AUDIO_CHANNEL_STATE_MUTED /* aState */,
-                                aWithVideo);
-  mAgents.Put(aAgent, data);
+  AudioChannelAgentData* data =
+    new AudioChannelAgentData(aAgent, aChannel,
+                              true /* aElementHidden */,
+                              AUDIO_CHANNEL_STATE_MUTED /* aState */,
+                              aWithVideo);
+  mAgents.AppendElement(data);
   RegisterType(aChannel, CONTENT_PROCESS_ID_MAIN, aWithVideo);
 
   // If this is the first agent for this window, we must notify the observers.
   uint32_t count = CountWindow(aAgent->Window());
   if (count == 1) {
     nsCOMPtr<nsIObserverService> observerService =
       services::GetObserverService();
     if (observerService) {
@@ -214,17 +214,26 @@ AudioChannelService::RegisterType(AudioC
 void
 AudioChannelService::UnregisterAudioChannelAgent(AudioChannelAgent* aAgent)
 {
   if (mDisabled) {
     return;
   }
 
   nsAutoPtr<AudioChannelAgentData> data;
-  mAgents.RemoveAndForget(aAgent, data);
+  nsTObserverArray<nsAutoPtr<AudioChannelAgentData>>::ForwardIterator iter(mAgents);
+  while (iter.HasMore()) {
+    nsAutoPtr<AudioChannelAgentData>& pData = iter.GetNext();
+    if (pData->mAgent == aAgent) {
+      uint32_t pos = mAgents.IndexOf(pData);
+      data = pData.forget();
+      mAgents.RemoveElementAt(pos);
+      break;
+    }
+  }
 
   if (data) {
     UnregisterType(data->mChannel, data->mElementHidden,
                    CONTENT_PROCESS_ID_MAIN, data->mWithVideo);
   }
 
 #ifdef MOZ_WIDGET_GONK
   bool active = AnyAudioChannelIsActive();
@@ -344,44 +353,45 @@ AudioChannelService::UpdateChannelType(A
       mChannelCounters[AUDIO_CHANNEL_INT_CONTENT].IsEmpty()) {
     mPlayableHiddenContentChildID = aChildID;
   }
 }
 
 AudioChannelState
 AudioChannelService::GetState(AudioChannelAgent* aAgent, bool aElementHidden)
 {
-  AudioChannelAgentData* data;
-  if (!mAgents.Get(aAgent, &data)) {
+  AudioChannelAgentData* agentData = Find(aAgent);
+  if (!agentData) {
     return AUDIO_CHANNEL_STATE_MUTED;
   }
 
-  bool oldElementHidden = data->mElementHidden;
+  bool oldElementHidden = agentData->mElementHidden;
   // Update visibility.
-  data->mElementHidden = aElementHidden;
+  agentData->mElementHidden = aElementHidden;
 
-  data->mState = GetStateInternal(data->mChannel, CONTENT_PROCESS_ID_MAIN,
-                                aElementHidden, oldElementHidden);
+  agentData->mState = GetStateInternal(agentData->mChannel,
+                                       CONTENT_PROCESS_ID_MAIN,
+                                       aElementHidden, oldElementHidden);
   #ifdef MOZ_WIDGET_GONK
   /** Only modify the speaker status when
    *  (1) apps in the foreground.
    *  (2) apps in the backgrund and inactive.
    *  Notice : check the state when the visible status is stable, because there
    *  has lantency in passing the visibility events.
    **/
   bool active = AnyAudioChannelIsActive();
   if (aElementHidden == oldElementHidden &&
       (!aElementHidden || (aElementHidden && !active))) {
     for (uint32_t i = 0; i < mSpeakerManager.Length(); i++) {
       mSpeakerManager[i]->SetAudioChannelActive(active);
     }
   }
   #endif
 
-  return data->mState;
+  return agentData->mState;
 }
 
 AudioChannelState
 AudioChannelService::GetStateInternal(AudioChannel aChannel, uint64_t aChildID,
                                       bool aElementHidden,
                                       bool aElementWasHidden)
 {
   UpdateChannelType(aChannel, aChildID, aElementHidden, aElementWasHidden);
@@ -665,25 +675,16 @@ AudioChannelService::SendAudioChannelCha
     }
 
     if (obs) {
       obs->NotifyObservers(nullptr, "visible-audio-channel-changed", channelName.get());
     }
   }
 }
 
-PLDHashOperator
-AudioChannelService::NotifyEnumerator(AudioChannelAgent* aAgent,
-                                      AudioChannelAgentData* aData, void* aUnused)
-{
-  MOZ_ASSERT(aAgent);
-  aAgent->NotifyAudioChannelStateChanged();
-  return PL_DHASH_NEXT;
-}
-
 class NotifyRunnable : public nsRunnable
 {
 public:
   explicit NotifyRunnable(AudioChannelService* aService)
     : mService(aService)
   {}
 
   NS_IMETHOD Run()
@@ -711,17 +712,21 @@ AudioChannelService::SendNotification()
 
 void
 AudioChannelService::Notify()
 {
   MOZ_ASSERT(NS_IsMainThread());
   mRunnable = nullptr;
 
   // Notify any agent for the main process.
-  mAgents.EnumerateRead(NotifyEnumerator, nullptr);
+  nsTObserverArray<nsAutoPtr<AudioChannelAgentData>>::ForwardIterator iter(mAgents);
+  while (iter.HasMore()) {
+    AudioChannelAgentData* data = iter.GetNext();
+    data->mAgent->NotifyAudioChannelStateChanged();
+  }
 
   // Notify for the child processes.
   nsTArray<ContentParent*> children;
   ContentParent::GetAll(children);
   for (uint32_t i = 0; i < children.Length(); i++) {
     unused << children[i]->SendAudioChannelNotify();
   }
 }
@@ -761,38 +766,16 @@ AudioChannelService::ChannelsActiveWithH
     if (!mChannelCounters[i].IsEmpty()) {
       return true;
     }
   }
 
   return false;
 }
 
-PLDHashOperator
-AudioChannelService::WindowDestroyedEnumerator(AudioChannelAgent* aAgent,
-                                               nsAutoPtr<AudioChannelAgentData>& aData,
-                                               void* aPtr)
-{
-  uint64_t* innerID = static_cast<uint64_t*>(aPtr);
-  MOZ_ASSERT(innerID);
-
-  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aAgent->Window());
-  if (!window || window->WindowID() != *innerID) {
-    return PL_DHASH_NEXT;
-  }
-
-  AudioChannelService* service = AudioChannelService::GetAudioChannelService();
-  MOZ_ASSERT(service);
-
-  service->UnregisterType(aData->mChannel, aData->mElementHidden,
-                          CONTENT_PROCESS_ID_MAIN, aData->mWithVideo);
-
-  return PL_DHASH_REMOVE;
-}
-
 NS_IMETHODIMP
 AudioChannelService::Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aData)
 {
   if (!strcmp(aTopic, "xpcom-shutdown")) {
     mDisabled = true;
   }
 
   if (!strcmp(aTopic, "ipc:content-shutdown")) {
@@ -884,17 +867,32 @@ AudioChannelService::Observe(nsISupports
     NS_ENSURE_TRUE(wrapper, NS_ERROR_FAILURE);
 
     uint64_t innerID;
     nsresult rv = wrapper->GetData(&innerID);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
-    mAgents.Enumerate(WindowDestroyedEnumerator, &innerID);
+    nsTObserverArray<nsAutoPtr<AudioChannelAgentData>>::ForwardIterator iter(mAgents);
+    while (iter.HasMore()) {
+      AudioChannelAgentData* data = iter.GetNext();
+
+      nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(data->mAgent->Window());
+      if (window && !window->IsInnerWindow()) {
+        window = window->GetCurrentInnerWindow();
+      }
+
+      if (!window || window->WindowID() != innerID) {
+        continue;
+      }
+
+      UnregisterType(data->mChannel, data->mElementHidden,
+                     CONTENT_PROCESS_ID_MAIN, data->mWithVideo);
+    }
 
 #ifdef MOZ_WIDGET_GONK
     bool active = AnyAudioChannelIsActive();
     for (uint32_t i = 0; i < mSpeakerManager.Length(); i++) {
       mSpeakerManager[i]->SetAudioChannelActive(active);
     }
 #endif
   }
@@ -944,89 +942,47 @@ AudioChannelService::GetInternalType(Aud
 
     default:
       break;
   }
 
   MOZ_CRASH("unexpected audio channel");
 }
 
-struct RefreshAgentsVolumeData
-{
-  explicit RefreshAgentsVolumeData(nsPIDOMWindow* aWindow)
-    : mWindow(aWindow)
-  {}
-
-  nsPIDOMWindow* mWindow;
-  nsTArray<nsRefPtr<AudioChannelAgent>> mAgents;
-};
-
-PLDHashOperator
-AudioChannelService::RefreshAgentsVolumeEnumerator(AudioChannelAgent* aAgent,
-                                                   AudioChannelAgentData* aUnused,
-                                                   void* aPtr)
-{
-  MOZ_ASSERT(aAgent);
-  RefreshAgentsVolumeData* data = static_cast<RefreshAgentsVolumeData*>(aPtr);
-  MOZ_ASSERT(data);
-
-  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aAgent->Window());
-  if (window && !window->IsInnerWindow()) {
-    window = window->GetCurrentInnerWindow();
-  }
-
-  if (window == data->mWindow) {
-    data->mAgents.AppendElement(aAgent);
-  }
-
-  return PL_DHASH_NEXT;
-}
 void
 AudioChannelService::RefreshAgentsVolume(nsPIDOMWindow* aWindow)
 {
-  RefreshAgentsVolumeData data(aWindow);
-  mAgents.EnumerateRead(RefreshAgentsVolumeEnumerator, &data);
-
-  for (uint32_t i = 0; i < data.mAgents.Length(); ++i) {
-    data.mAgents[i]->WindowVolumeChanged();
-  }
-}
-
-struct CountWindowData
-{
-  explicit CountWindowData(nsIDOMWindow* aWindow)
-    : mWindow(aWindow)
-    , mCount(0)
-  {}
+  nsTObserverArray<nsAutoPtr<AudioChannelAgentData>>::ForwardIterator iter(mAgents);
+  while (iter.HasMore()) {
+    AudioChannelAgentData* data = iter.GetNext();
 
-  nsIDOMWindow* mWindow;
-  uint32_t mCount;
-};
+    nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(data->mAgent->Window());
+    if (window && !window->IsInnerWindow()) {
+      window = window->GetCurrentInnerWindow();
+    }
 
-PLDHashOperator
-AudioChannelService::CountWindowEnumerator(AudioChannelAgent* aAgent,
-                                           AudioChannelAgentData* aUnused,
-                                           void* aPtr)
-{
-  CountWindowData* data = static_cast<CountWindowData*>(aPtr);
-  MOZ_ASSERT(aAgent);
-
-  if (aAgent->Window() == data->mWindow) {
-    ++data->mCount;
+    if (window == aWindow) {
+      data->mAgent->WindowVolumeChanged();
+    }
   }
-
-  return PL_DHASH_NEXT;
 }
 
 uint32_t
 AudioChannelService::CountWindow(nsIDOMWindow* aWindow)
 {
-  CountWindowData data(aWindow);
-  mAgents.EnumerateRead(CountWindowEnumerator, &data);
-  return data.mCount;
+  uint32_t count = 0;
+  nsTObserverArray<nsAutoPtr<AudioChannelAgentData>>::ForwardIterator iter(mAgents);
+  while (iter.HasMore()) {
+    AudioChannelAgentData* data = iter.GetNext();
+    if (data->mAgent->Window() == aWindow) {
+      ++count;
+    }
+  }
+
+  return count;
 }
 
 /* static */ const nsAttrValue::EnumTable*
 AudioChannelService::GetAudioChannelTable()
 {
   return kMozAudioChannelAttributeTable;
 }
 
@@ -1120,8 +1076,22 @@ AudioChannelService::UnregisterTelephony
       }
 
       return;
     }
   }
 
   MOZ_ASSERT(false, "This should not happen.");
 }
+
+AudioChannelService::AudioChannelAgentData*
+AudioChannelService::Find(AudioChannelAgent* aAgent)
+{
+  nsTObserverArray<nsAutoPtr<AudioChannelAgentData>>::ForwardIterator iter(mAgents);
+  while (iter.HasMore()) {
+    AudioChannelAgentData* data = iter.GetNext();
+    if (data->mAgent == aAgent) {
+      return data;
+    }
+  }
+
+  return nullptr;
+}
--- a/dom/audiochannel/AudioChannelService.h
+++ b/dom/audiochannel/AudioChannelService.h
@@ -10,17 +10,17 @@
 #include "nsAutoPtr.h"
 #include "nsIObserver.h"
 #include "nsTArray.h"
 #include "nsITimer.h"
 
 #include "AudioChannelCommon.h"
 #include "AudioChannelAgent.h"
 #include "nsAttrValue.h"
-#include "nsClassHashtable.h"
+#include "nsTObserverArray.h"
 #include "mozilla/dom/AudioChannelBinding.h"
 
 class nsIRunnable;
 class nsPIDOMWindow;
 
 namespace mozilla {
 namespace dom {
 #ifdef MOZ_WIDGET_GONK
@@ -184,57 +184,48 @@ protected:
   bool ChannelsActiveWithHigherPriorityThan(AudioChannelInternalType aType);
 
   bool CheckVolumeFadedCondition(AudioChannelInternalType aType,
                                  bool aElementHidden);
 
   AudioChannelInternalType GetInternalType(AudioChannel aChannel,
                                            bool aElementHidden);
 
-  class AudioChannelAgentData {
+  class AudioChannelAgentData
+  {
   public:
-    AudioChannelAgentData(AudioChannel aChannel,
+    AudioChannelAgentData(AudioChannelAgent* aAgent,
+                          AudioChannel aChannel,
                           bool aElementHidden,
                           AudioChannelState aState,
                           bool aWithVideo)
-    : mChannel(aChannel)
+    : mAgent(aAgent)
+    , mChannel(aChannel)
     , mElementHidden(aElementHidden)
     , mState(aState)
     , mWithVideo(aWithVideo)
-    {}
+    {
+      MOZ_ASSERT(mAgent);
+    }
 
+    // AudioChannelAgent will unregister itself in the DTOR.
+    AudioChannelAgent* mAgent;
     AudioChannel mChannel;
     bool mElementHidden;
     AudioChannelState mState;
     const bool mWithVideo;
   };
 
-  static PLDHashOperator
-  NotifyEnumerator(AudioChannelAgent* aAgent,
-                   AudioChannelAgentData* aData, void *aUnused);
-
-  static PLDHashOperator
-  RefreshAgentsVolumeEnumerator(AudioChannelAgent* aAgent,
-                                AudioChannelAgentData* aUnused,
-                                void *aPtr);
-
-  static PLDHashOperator
-  CountWindowEnumerator(AudioChannelAgent* aAgent,
-                        AudioChannelAgentData* aUnused,
-                        void *aPtr);
-
-  static PLDHashOperator
-  WindowDestroyedEnumerator(AudioChannelAgent* aAgent,
-                            nsAutoPtr<AudioChannelAgentData>& aData,
-                            void *aPtr);
+  AudioChannelAgentData* Find(AudioChannelAgent* aAgent);
 
   // This returns the number of agents from this aWindow.
   uint32_t CountWindow(nsIDOMWindow* aWindow);
 
-  nsClassHashtable< nsPtrHashKey<AudioChannelAgent>, AudioChannelAgentData > mAgents;
+  nsTObserverArray<nsAutoPtr<AudioChannelAgentData>> mAgents;
+
 #ifdef MOZ_WIDGET_GONK
   nsTArray<SpeakerManagerService*>  mSpeakerManager;
 #endif
   nsTArray<uint64_t> mChannelCounters[AUDIO_CHANNEL_INT_LAST];
 
   int32_t mCurrentHigherChannel;
   int32_t mCurrentVisibleHigherChannel;
 
--- a/dom/audiochannel/AudioChannelServiceChild.cpp
+++ b/dom/audiochannel/AudioChannelServiceChild.cpp
@@ -69,18 +69,18 @@ AudioChannelServiceChild::AudioChannelSe
 
 AudioChannelServiceChild::~AudioChannelServiceChild()
 {
 }
 
 AudioChannelState
 AudioChannelServiceChild::GetState(AudioChannelAgent* aAgent, bool aElementHidden)
 {
-  AudioChannelAgentData* data;
-  if (!mAgents.Get(aAgent, &data)) {
+  AudioChannelAgentData* data = Find(aAgent);
+  if (!data) {
     return AUDIO_CHANNEL_STATE_MUTED;
   }
 
   AudioChannelState state = AUDIO_CHANNEL_STATE_MUTED;
   bool oldElementHidden = data->mElementHidden;
 
   UpdateChannelType(data->mChannel, CONTENT_PROCESS_ID_MAIN, aElementHidden,
                     oldElementHidden);
@@ -126,18 +126,18 @@ AudioChannelServiceChild::RegisterAudioC
   if (obs) {
     obs->NotifyObservers(nullptr, "audio-channel-agent-changed", nullptr);
   }
 }
 
 void
 AudioChannelServiceChild::UnregisterAudioChannelAgent(AudioChannelAgent* aAgent)
 {
-  AudioChannelAgentData *pData;
-  if (!mAgents.Get(aAgent, &pData)) {
+  AudioChannelAgentData* pData = Find(aAgent);
+  if (!pData) {
     return;
   }
 
   // We need to keep a copy because unregister will remove the
   // AudioChannelAgentData object from the hashtable.
   AudioChannelAgentData data(*pData);
 
   AudioChannelService::UnregisterAudioChannelAgent(aAgent);
--- a/dom/audiochannel/AudioChannelServiceChild.h
+++ b/dom/audiochannel/AudioChannelServiceChild.h
@@ -54,9 +54,8 @@ protected:
   AudioChannelServiceChild();
   virtual ~AudioChannelServiceChild();
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif
-