Bug 1397331 - Reduce the number of QI done in nsMultiplexInputStream using counters, r=smaug
authorAndrea Marchesini <amarchesini@mozilla.com>
Thu, 07 Sep 2017 18:39:10 +0200
changeset 429108 8338a5c1ef2126264c910cd9aa6c3a25776643c5
parent 429107 6e4988e39120b0a1f7a7eeeb872c4781f9d5d9ee
child 429109 e5333aad4139ff4e480078a4a5f064dfde475f4c
push id7761
push userjlund@mozilla.com
push dateFri, 15 Sep 2017 00:19:52 +0000
treeherdermozilla-beta@c38455951db4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1397331
milestone57.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 1397331 - Reduce the number of QI done in nsMultiplexInputStream using counters, r=smaug
xpcom/io/nsMultiplexInputStream.cpp
--- a/xpcom/io/nsMultiplexInputStream.cpp
+++ b/xpcom/io/nsMultiplexInputStream.cpp
@@ -55,62 +55,67 @@ public:
 
   void AsyncWaitCompleted();
 
 private:
   ~nsMultiplexInputStream()
   {
   }
 
-  // This method resets mIsSeekable, mIsIPCSerializable, mIsCloneable and
-  // mIsAsyncInputStream values.
-  void UpdateQIMap();
+  // This method updates mSeekableStreams, mIPCSerializableStreams,
+  // mCloneableStreams and mAsyncInputStreams values.
+  void UpdateQIMap(nsIInputStream* aStream, int32_t aCount);
 
   struct MOZ_STACK_CLASS ReadSegmentsState
   {
     nsCOMPtr<nsIInputStream> mThisStream;
     uint32_t mOffset;
     nsWriteSegmentFun mWriter;
     void* mClosure;
     bool mDone;
   };
 
   static nsresult ReadSegCb(nsIInputStream* aIn, void* aClosure,
                             const char* aFromRawSegment, uint32_t aToOffset,
                             uint32_t aCount, uint32_t* aWriteCount);
 
+  bool IsSeekable() const;
+  bool IsIPCSerializable() const;
+  bool IsCloneable() const;
+  bool IsAsyncInputStream() const;
+
   Mutex mLock; // Protects access to all data members.
   nsTArray<nsCOMPtr<nsIInputStream>> mStreams;
   uint32_t mCurrentStream;
   bool mStartedReadingCurrent;
   nsresult mStatus;
   nsCOMPtr<nsIInputStreamCallback> mAsyncWaitCallback;
 
-  bool mIsSeekable;
-  bool mIsIPCSerializable;
-  bool mIsCloneable;
-  bool mIsAsyncInputStream;
+  uint32_t mSeekableStreams;
+  uint32_t mIPCSerializableStreams;
+  uint32_t mCloneableStreams;
+  uint32_t mAsyncInputStreams;
 };
 
 NS_IMPL_ADDREF(nsMultiplexInputStream)
 NS_IMPL_RELEASE(nsMultiplexInputStream)
 
 NS_IMPL_CLASSINFO(nsMultiplexInputStream, nullptr, nsIClassInfo::THREADSAFE,
                   NS_MULTIPLEXINPUTSTREAM_CID)
 
 NS_INTERFACE_MAP_BEGIN(nsMultiplexInputStream)
   NS_INTERFACE_MAP_ENTRY(nsIMultiplexInputStream)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsIInputStream, nsIMultiplexInputStream)
-  NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsISeekableStream, mIsSeekable)
+  NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsISeekableStream, IsSeekable())
   NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIIPCSerializableInputStream,
-                                     mIsIPCSerializable)
+                                     IsIPCSerializable())
   NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsICloneableInputStream,
-                                     mIsCloneable)
+                                     IsCloneable())
   NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIAsyncInputStream,
-                                     mIsAsyncInputStream)
+                                     IsAsyncInputStream())
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIMultiplexInputStream)
   NS_IMPL_QUERY_CLASSINFO(nsMultiplexInputStream)
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CI_INTERFACE_GETTER(nsMultiplexInputStream,
                             nsIMultiplexInputStream,
                             nsIInputStream,
                             nsISeekableStream)
@@ -148,23 +153,25 @@ TellMaybeSeek(nsISeekableStream* aSeekab
     if (NS_SUCCEEDED(rvSeek)) {
       rv = aSeekable->Tell(aResult);
     }
   }
   return rv;
 }
 
 nsMultiplexInputStream::nsMultiplexInputStream()
-  : mLock("nsMultiplexInputStream lock"),
-    mCurrentStream(0),
-    mStartedReadingCurrent(false),
-    mStatus(NS_OK)
-{
-  UpdateQIMap();
-}
+  : mLock("nsMultiplexInputStream lock")
+  , mCurrentStream(0)
+  , mStartedReadingCurrent(false)
+  , mStatus(NS_OK)
+  , mSeekableStreams(0)
+  , mIPCSerializableStreams(0)
+  , mCloneableStreams(0)
+  , mAsyncInputStreams(0)
+{}
 
 NS_IMETHODIMP
 nsMultiplexInputStream::GetCount(uint32_t* aCount)
 {
   MutexAutoLock lock(mLock);
   *aCount = mStreams.Length();
   return NS_OK;
 }
@@ -172,49 +179,54 @@ nsMultiplexInputStream::GetCount(uint32_
 NS_IMETHODIMP
 nsMultiplexInputStream::AppendStream(nsIInputStream* aStream)
 {
   MutexAutoLock lock(mLock);
   if (!mStreams.AppendElement(aStream)) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
-  UpdateQIMap();
+  UpdateQIMap(aStream, 1);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsMultiplexInputStream::InsertStream(nsIInputStream* aStream, uint32_t aIndex)
 {
   MutexAutoLock lock(mLock);
   if (!mStreams.InsertElementAt(aIndex, aStream)) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   if (mCurrentStream > aIndex ||
       (mCurrentStream == aIndex && mStartedReadingCurrent)) {
     ++mCurrentStream;
   }
 
-  UpdateQIMap();
+  UpdateQIMap(aStream, 1);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsMultiplexInputStream::RemoveStream(uint32_t aIndex)
 {
   MutexAutoLock lock(mLock);
+  if (aIndex >= mStreams.Length()) {
+    return NS_ERROR_FAILURE;
+  }
+
+  UpdateQIMap(mStreams[aIndex], -1);
+
   mStreams.RemoveElementAt(aIndex);
   if (mCurrentStream > aIndex) {
     --mCurrentStream;
   } else if (mCurrentStream == aIndex) {
     mStartedReadingCurrent = false;
   }
 
-  UpdateQIMap();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsMultiplexInputStream::GetStream(uint32_t aIndex, nsIInputStream** aResult)
 {
   MutexAutoLock lock(mLock);
   *aResult = mStreams.SafeElementAt(aIndex, nullptr);
@@ -1057,48 +1069,61 @@ nsMultiplexInputStream::Clone(nsIInputSt
       return rv;
     }
   }
 
   clone.forget(aClone);
   return NS_OK;
 }
 
-void
-nsMultiplexInputStream::UpdateQIMap()
-{
-  mIsSeekable = true;
-  mIsIPCSerializable = true;
-  mIsCloneable = true;
-  mIsAsyncInputStream = false;
+#define MAYBE_UPDATE_VALUE(x, y)                        \
+  {                                                     \
+    nsCOMPtr<y> substream = do_QueryInterface(aStream); \
+    if (substream) {                                    \
+      if (aCount == 1) {                                \
+        ++x;                                            \
+      } else if (x > 0) {                               \
+        --x;                                            \
+      } else {                                          \
+        MOZ_CRASH("A nsIInputStream changed QI map when stored in a nsMultiplexInputStream!"); \
+      }                                                 \
+    }                                                   \
+  }
 
-  for (uint32_t i = 0, len = mStreams.Length(); i < len; ++i) {
-    if (mIsSeekable) {
-      nsCOMPtr<nsISeekableStream> substream = do_QueryInterface(mStreams[i]);
-      if (!substream) {
-        mIsSeekable = false;
-      }
-    }
+void
+nsMultiplexInputStream::UpdateQIMap(nsIInputStream* aStream, int32_t aCount)
+{
+  MOZ_ASSERT(aStream);
+  MOZ_ASSERT(aCount == -1 || aCount == 1);
+
+  MAYBE_UPDATE_VALUE(mSeekableStreams, nsISeekableStream);
+  MAYBE_UPDATE_VALUE(mIPCSerializableStreams, nsIIPCSerializableInputStream);
+  MAYBE_UPDATE_VALUE(mCloneableStreams, nsICloneableInputStream);
+  MAYBE_UPDATE_VALUE(mAsyncInputStreams, nsIAsyncInputStream);
+}
 
-    if (mIsIPCSerializable) {
-      nsCOMPtr<nsIIPCSerializableInputStream> substream = do_QueryInterface(mStreams[i]);
-      if (!substream) {
-        mIsIPCSerializable = false;
-      }
-    }
+#undef MAYBE_UPDATE_VALUE
+
+bool
+nsMultiplexInputStream::IsSeekable() const
+{
+  return mStreams.Length() == mSeekableStreams;
+}
+
+bool
+nsMultiplexInputStream::IsIPCSerializable() const
+{
+  return mStreams.Length() == mIPCSerializableStreams;
+}
 
-    if (mIsCloneable) {
-      nsCOMPtr<nsICloneableInputStream> substream = do_QueryInterface(mStreams[i]);
-      if (!substream) {
-        mIsCloneable = false;
-      }
-    }
+bool
+nsMultiplexInputStream::IsCloneable() const
+{
+  return mStreams.Length() == mCloneableStreams;
+}
 
-    if (!mIsAsyncInputStream) {
-      // nsMultiplexInputStream is nsIAsyncInputStream if at least 1 of the
-      // substream implements that interface.
-      nsCOMPtr<nsIAsyncInputStream> substream = do_QueryInterface(mStreams[i]);
-      if (substream) {
-        mIsAsyncInputStream = true;
-      }
-    }
-  }
+bool
+nsMultiplexInputStream::IsAsyncInputStream() const
+{
+  // nsMultiplexInputStream is nsIAsyncInputStream if at least 1 of the
+  // substream implements that interface.
+  return !!mAsyncInputStreams;
 }