Bug 1643156 - Cleanup nsMultiplexInputStream - part 1 - keep the original stream, r=smaug
authorAndrea Marchesini <amarchesini@mozilla.com>
Thu, 04 Jun 2020 12:23:17 +0000
changeset 533909 9a677aff41650ba450522c6f8699c426ba9d0cdc
parent 533908 e021e0294b0d4552816ad4741a92c37d8325f8a4
child 533910 5aeea4eedca4480e6cb30d312fea6557dbed031a
push id37480
push userncsoregi@mozilla.com
push dateThu, 04 Jun 2020 22:00:12 +0000
treeherdermozilla-central@e33aea19d0c5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1643156
milestone79.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 1643156 - Cleanup nsMultiplexInputStream - part 1 - keep the original stream, r=smaug Differential Revision: https://phabricator.services.mozilla.com/D76901
xpcom/io/nsMultiplexInputStream.cpp
--- a/xpcom/io/nsMultiplexInputStream.cpp
+++ b/xpcom/io/nsMultiplexInputStream.cpp
@@ -64,47 +64,59 @@ class nsMultiplexInputStream final : pub
 
   // This is used for nsIAsyncInputStream::AsyncWait
   void AsyncWaitCompleted();
 
   // This is used for nsIAsyncInputStreamLength::AsyncLengthWait
   void AsyncWaitCompleted(int64_t aLength, const MutexAutoLock& aProofOfLock);
 
   struct StreamData {
-    void Initialize(nsIInputStream* aStream, bool aBuffered) {
-      mStream = aStream;
-      mAsyncStream = do_QueryInterface(aStream);
-      mSeekableStream = do_QueryInterface(aStream);
-      mTellableStream = do_QueryInterface(aStream);
-      mBuffered = aBuffered;
+    nsresult Initialize(nsIInputStream* aOriginalStream) {
+      mOriginalStream = aOriginalStream;
+
+      mBufferedStream = aOriginalStream;
+      if (!NS_InputStreamIsBuffered(mBufferedStream)) {
+        nsCOMPtr<nsIInputStream> bufferedStream;
+        nsresult rv = NS_NewBufferedInputStream(getter_AddRefs(bufferedStream),
+                                                mBufferedStream.forget(), 4096);
+        NS_ENSURE_SUCCESS(rv, rv);
+        mBufferedStream = bufferedStream;
+      }
+
+      mAsyncStream = do_QueryInterface(mBufferedStream);
+      mSeekableStream = do_QueryInterface(mBufferedStream);
+      mTellableStream = do_QueryInterface(mBufferedStream);
+
+      return NS_OK;
     }
 
-    nsCOMPtr<nsIInputStream> mStream;
+    nsCOMPtr<nsIInputStream> mOriginalStream;
+
+    // Equal to mOriginalStream or a wrap around the original stream to make it
+    // buffered.
+    nsCOMPtr<nsIInputStream> mBufferedStream;
 
     // This can be null.
     nsCOMPtr<nsIAsyncInputStream> mAsyncStream;
     // This can be null.
     nsCOMPtr<nsISeekableStream> mSeekableStream;
     // This can be null.
     nsCOMPtr<nsITellableStream> mTellableStream;
-
-    // True if the stream is wrapped with nsIBufferedInputStream.
-    bool mBuffered;
   };
 
   Mutex& GetLock() { return mLock; }
 
  private:
   ~nsMultiplexInputStream() = default;
 
   nsresult AsyncWaitInternal();
 
   // This method updates mSeekableStreams, mTellableStreams,
-  // mIPCSerializableStreams, mCloneableStreams and mAsyncInputStreams values.
-  void UpdateQIMap(StreamData& aStream, int32_t aCount);
+  // mIPCSerializableStreams and mCloneableStreams values.
+  void UpdateQIMap(StreamData& aStream);
 
   struct MOZ_STACK_CLASS ReadSegmentsState {
     nsCOMPtr<nsIInputStream> mThisStream;
     uint32_t mOffset;
     nsWriteSegmentFun mWriter;
     void* mClosure;
     bool mDone;
   };
@@ -178,27 +190,27 @@ NS_INTERFACE_MAP_BEGIN(nsMultiplexInputS
 NS_INTERFACE_MAP_END
 
 NS_IMPL_CI_INTERFACE_GETTER(nsMultiplexInputStream, nsIMultiplexInputStream,
                             nsIInputStream, nsISeekableStream,
                             nsITellableStream)
 
 static nsresult AvailableMaybeSeek(nsMultiplexInputStream::StreamData& aStream,
                                    uint64_t* aResult) {
-  nsresult rv = aStream.mStream->Available(aResult);
+  nsresult rv = aStream.mBufferedStream->Available(aResult);
   if (rv == NS_BASE_STREAM_CLOSED) {
     // Blindly seek to the current position if Available() returns
     // NS_BASE_STREAM_CLOSED.
     // If nsIFileInputStream is closed in Read() due to CLOSE_ON_EOF flag,
     // Seek() could reopen the file if REOPEN_ON_REWIND flag is set.
     if (aStream.mSeekableStream) {
       nsresult rvSeek =
           aStream.mSeekableStream->Seek(nsISeekableStream::NS_SEEK_CUR, 0);
       if (NS_SUCCEEDED(rvSeek)) {
-        rv = aStream.mStream->Available(aResult);
+        rv = aStream.mBufferedStream->Available(aResult);
       }
     }
   }
   return rv;
 }
 
 static nsresult TellMaybeSeek(nsITellableStream* aTellable,
                               nsISeekableStream* aSeekable, int64_t* aResult) {
@@ -235,38 +247,27 @@ NS_IMETHODIMP
 nsMultiplexInputStream::GetCount(uint32_t* aCount) {
   MutexAutoLock lock(mLock);
   *aCount = mStreams.Length();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsMultiplexInputStream::AppendStream(nsIInputStream* aStream) {
-  nsCOMPtr<nsIInputStream> stream = aStream;
-
-  bool buffered = false;
-  if (!NS_InputStreamIsBuffered(stream)) {
-    nsCOMPtr<nsIInputStream> bufferedStream;
-    nsresult rv = NS_NewBufferedInputStream(getter_AddRefs(bufferedStream),
-                                            stream.forget(), 4096);
-    NS_ENSURE_SUCCESS(rv, rv);
-    stream = std::move(bufferedStream);
-    buffered = true;
-  }
-
   MutexAutoLock lock(mLock);
 
   StreamData* streamData = mStreams.AppendElement(fallible);
   if (NS_WARN_IF(!streamData)) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
-  streamData->Initialize(stream, buffered);
+  nsresult rv = streamData->Initialize(aStream);
+  NS_ENSURE_SUCCESS(rv, rv);
 
-  UpdateQIMap(*streamData, 1);
+  UpdateQIMap(*streamData);
 
   if (mStatus == NS_BASE_STREAM_CLOSED) {
     // We were closed, but now we have more data to read.
     mStatus = NS_OK;
   }
 
   return NS_OK;
 }
@@ -275,45 +276,34 @@ NS_IMETHODIMP
 nsMultiplexInputStream::GetStream(uint32_t aIndex, nsIInputStream** aResult) {
   MutexAutoLock lock(mLock);
 
   if (aIndex >= mStreams.Length()) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   StreamData& streamData = mStreams.ElementAt(aIndex);
-
-  nsCOMPtr<nsIInputStream> stream = streamData.mStream;
-
-  if (streamData.mBuffered) {
-    nsCOMPtr<nsIBufferedInputStream> bufferedStream = do_QueryInterface(stream);
-    MOZ_ASSERT(bufferedStream);
-
-    nsresult rv = bufferedStream->GetData(getter_AddRefs(stream));
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return rv;
-    }
-  }
-
+  nsCOMPtr<nsIInputStream> stream = streamData.mOriginalStream;
   stream.forget(aResult);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsMultiplexInputStream::Close() {
   nsTArray<nsCOMPtr<nsIInputStream>> streams;
 
   // Let's take a copy of the streams becuase, calling close() it could trigger
   // a nsIInputStreamCallback immediately and we don't want to create a deadlock
   // with mutex.
   {
     MutexAutoLock lock(mLock);
     uint32_t len = mStreams.Length();
     for (uint32_t i = 0; i < len; ++i) {
-      if (NS_WARN_IF(!streams.AppendElement(mStreams[i].mStream, fallible))) {
+      if (NS_WARN_IF(
+              !streams.AppendElement(mStreams[i].mBufferedStream, fallible))) {
         mStatus = NS_BASE_STREAM_CLOSED;
         return NS_ERROR_OUT_OF_MEMORY;
       }
     }
     mStatus = NS_BASE_STREAM_CLOSED;
   }
 
   nsresult rv = NS_OK;
@@ -406,17 +396,17 @@ nsMultiplexInputStream::Read(char* aBuf,
     return mStatus;
   }
 
   nsresult rv = NS_OK;
 
   uint32_t len = mStreams.Length();
   while (mCurrentStream < len && aCount) {
     uint32_t read;
-    rv = mStreams[mCurrentStream].mStream->Read(aBuf, aCount, &read);
+    rv = mStreams[mCurrentStream].mBufferedStream->Read(aBuf, aCount, &read);
 
     // XXX some streams return NS_BASE_STREAM_CLOSED to indicate EOF.
     // (This is a bug in those stream implementations)
     if (rv == NS_BASE_STREAM_CLOSED) {
       MOZ_ASSERT_UNREACHABLE(
           "Input stream's Read method returned "
           "NS_BASE_STREAM_CLOSED");
       rv = NS_OK;
@@ -460,18 +450,18 @@ nsMultiplexInputStream::ReadSegments(nsW
   state.mOffset = 0;
   state.mWriter = aWriter;
   state.mClosure = aClosure;
   state.mDone = false;
 
   uint32_t len = mStreams.Length();
   while (mCurrentStream < len && aCount) {
     uint32_t read;
-    rv = mStreams[mCurrentStream].mStream->ReadSegments(ReadSegCb, &state,
-                                                        aCount, &read);
+    rv = mStreams[mCurrentStream].mBufferedStream->ReadSegments(
+        ReadSegCb, &state, aCount, &read);
 
     // XXX some streams return NS_BASE_STREAM_CLOSED to indicate EOF.
     // (This is a bug in those stream implementations)
     if (rv == NS_BASE_STREAM_CLOSED) {
       MOZ_ASSERT_UNREACHABLE(
           "Input stream's Read method returned "
           "NS_BASE_STREAM_CLOSED");
       rv = NS_OK;
@@ -519,26 +509,28 @@ nsMultiplexInputStream::IsNonBlocking(bo
   MutexAutoLock lock(mLock);
 
   uint32_t len = mStreams.Length();
   if (len == 0) {
     // Claim to be non-blocking, since we won't block the caller.
     *aNonBlocking = true;
     return NS_OK;
   }
+
   for (uint32_t i = 0; i < len; ++i) {
-    nsresult rv = mStreams[i].mStream->IsNonBlocking(aNonBlocking);
+    nsresult rv = mStreams[i].mBufferedStream->IsNonBlocking(aNonBlocking);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
     // If one is blocking the entire stream becomes blocking.
     if (!*aNonBlocking) {
       return NS_OK;
     }
   }
+
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsMultiplexInputStream::Seek(int32_t aWhence, int64_t aOffset) {
   MutexAutoLock lock(mLock);
 
   if (NS_FAILED(mStatus)) {
@@ -1020,17 +1012,17 @@ void nsMultiplexInputStream::SerializeIn
   if (streamCount) {
     nsTArray<InputStreamParams>& streams = params.streams();
 
     streams.SetCapacity(streamCount);
     for (uint32_t index = 0; index < streamCount; index++) {
       uint32_t sizeUsed = 0;
       InputStreamParams childStreamParams;
       InputStreamHelper::SerializeInputStream(
-          mStreams[index].mStream, childStreamParams, aFileDescriptors,
+          mStreams[index].mOriginalStream, childStreamParams, aFileDescriptors,
           aDelayedStart, maxSize.value(), &sizeUsed, aManager);
       streams.AppendElement(childStreamParams);
 
       MOZ_ASSERT(maxSize.value() >= sizeUsed);
 
       maxSize -= sizeUsed;
       MOZ_DIAGNOSTIC_ASSERT(maxSize.isValid());
 
@@ -1092,17 +1084,17 @@ nsMultiplexInputStream::GetCloneable(boo
   if (mCurrentStream > 0 || mStartedReadingCurrent) {
     *aCloneable = false;
     return NS_OK;
   }
 
   uint32_t len = mStreams.Length();
   for (uint32_t i = 0; i < len; ++i) {
     nsCOMPtr<nsICloneableInputStream> cis =
-        do_QueryInterface(mStreams[i].mStream);
+        do_QueryInterface(mStreams[i].mBufferedStream);
     if (!cis || !cis->GetCloneable()) {
       *aCloneable = false;
       return NS_OK;
     }
   }
 
   *aCloneable = true;
   return NS_OK;
@@ -1119,17 +1111,17 @@ nsMultiplexInputStream::Clone(nsIInputSt
   }
 
   RefPtr<nsMultiplexInputStream> clone = new nsMultiplexInputStream();
 
   nsresult rv;
   uint32_t len = mStreams.Length();
   for (uint32_t i = 0; i < len; ++i) {
     nsCOMPtr<nsICloneableInputStream> substream =
-        do_QueryInterface(mStreams[i].mStream);
+        do_QueryInterface(mStreams[i].mBufferedStream);
     if (NS_WARN_IF(!substream)) {
       return NS_ERROR_FAILURE;
     }
 
     nsCOMPtr<nsIInputStream> clonedSubstream;
     rv = substream->Clone(getter_AddRefs(clonedSubstream));
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
@@ -1153,17 +1145,17 @@ nsMultiplexInputStream::Length(int64_t* 
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   CheckedInt64 length = 0;
   nsresult retval = NS_OK;
 
   for (uint32_t i = 0, len = mStreams.Length(); i < len; ++i) {
     nsCOMPtr<nsIInputStreamLength> substream =
-        do_QueryInterface(mStreams[i].mStream);
+        do_QueryInterface(mStreams[i].mBufferedStream);
     if (!substream) {
       // Let's use available as fallback.
       uint64_t streamAvail = 0;
       nsresult rv = AvailableMaybeSeek(mStreams[i], &streamAvail);
       if (rv == NS_BASE_STREAM_CLOSED) {
         continue;
       }
 
@@ -1355,26 +1347,26 @@ nsMultiplexInputStream::AsyncLengthWait(
     mAsyncWaitLengthCallback = aCallback;
     return NS_OK;
   }
 
   RefPtr<AsyncWaitLengthHelper> helper = new AsyncWaitLengthHelper();
 
   for (uint32_t i = 0, len = mStreams.Length(); i < len; ++i) {
     nsCOMPtr<nsIAsyncInputStreamLength> asyncStream =
-        do_QueryInterface(mStreams[i].mStream);
+        do_QueryInterface(mStreams[i].mBufferedStream);
     if (asyncStream) {
       if (NS_WARN_IF(!helper->AddStream(asyncStream))) {
         return NS_ERROR_OUT_OF_MEMORY;
       }
       continue;
     }
 
     nsCOMPtr<nsIInputStreamLength> stream =
-        do_QueryInterface(mStreams[i].mStream);
+        do_QueryInterface(mStreams[i].mBufferedStream);
     if (!stream) {
       // Let's use available as fallback.
       uint64_t streamAvail = 0;
       nsresult rv = AvailableMaybeSeek(mStreams[i], &streamAvail);
       if (rv == NS_BASE_STREAM_CLOSED) {
         continue;
       }
 
@@ -1435,38 +1427,28 @@ void nsMultiplexInputStream::AsyncWaitCo
   if (!callback) {
     return;
   }
 
   MutexAutoUnlock unlock(mLock);
   callback->OnInputStreamLengthReady(this, aLength);
 }
 
-#define MAYBE_UPDATE_VALUE_REAL(x, y)                         \
-  if (y) {                                                    \
-    if (aCount == 1) {                                        \
-      ++x;                                                    \
-    } else if (x > 0) {                                       \
-      --x;                                                    \
-    } else {                                                  \
-      MOZ_CRASH(                                              \
-          "A nsIInputStream changed QI map when stored in a " \
-          "nsMultiplexInputStream!");                         \
-    }                                                         \
+#define MAYBE_UPDATE_VALUE_REAL(x, y) \
+  if (y) {                            \
+    ++x;                              \
   }
 
-#define MAYBE_UPDATE_VALUE(x, y)                                \
-  {                                                             \
-    nsCOMPtr<y> substream = do_QueryInterface(aStream.mStream); \
-    MAYBE_UPDATE_VALUE_REAL(x, substream)                       \
+#define MAYBE_UPDATE_VALUE(x, y)                                        \
+  {                                                                     \
+    nsCOMPtr<y> substream = do_QueryInterface(aStream.mBufferedStream); \
+    MAYBE_UPDATE_VALUE_REAL(x, substream)                               \
   }
 
-void nsMultiplexInputStream::UpdateQIMap(StreamData& aStream, int32_t aCount) {
-  MOZ_ASSERT(aCount == -1 || aCount == 1);
-
+void nsMultiplexInputStream::UpdateQIMap(StreamData& aStream) {
   MAYBE_UPDATE_VALUE_REAL(mSeekableStreams, aStream.mSeekableStream)
   MAYBE_UPDATE_VALUE_REAL(mTellableStreams, aStream.mTellableStream)
   MAYBE_UPDATE_VALUE(mIPCSerializableStreams, nsIIPCSerializableInputStream)
   MAYBE_UPDATE_VALUE(mCloneableStreams, nsICloneableInputStream)
   MAYBE_UPDATE_VALUE_REAL(mAsyncInputStreams, aStream.mAsyncStream)
   MAYBE_UPDATE_VALUE(mInputStreamLengths, nsIInputStreamLength)
   MAYBE_UPDATE_VALUE(mAsyncInputStreamLengths, nsIAsyncInputStreamLength)
 }