Bug 1464090 - Passing the length if known via IPCStream and use InputStreamLengthWrapper when deserialized, r=froydnj, r=mayhemer
authorAndrea Marchesini <amarchesini@mozilla.com>
Thu, 31 May 2018 18:12:25 +0200
changeset 420721 ab037c88ae18f7df8540517895fbf2ff6c8ff2ea
parent 420720 c36cbbfd103372b568727fd5083f0424722ca0ec
child 420722 a1ce34b0b183f55cc356b4330df8daa1531cc177
push id34077
push usernerli@mozilla.com
push dateThu, 31 May 2018 21:51:59 +0000
treeherdermozilla-central@42880a726964 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfroydnj, mayhemer
bugs1464090
milestone62.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 1464090 - Passing the length if known via IPCStream and use InputStreamLengthWrapper when deserialized, r=froydnj, r=mayhemer
ipc/glue/IPCStream.ipdlh
ipc/glue/IPCStreamDestination.cpp
ipc/glue/IPCStreamDestination.h
ipc/glue/IPCStreamUtils.cpp
--- a/ipc/glue/IPCStream.ipdlh
+++ b/ipc/glue/IPCStream.ipdlh
@@ -29,16 +29,18 @@ struct IPCRemoteStream
 {
   // If this is true, the stream will send data only when the first operation
   // is done on the destination side. The benefit of this is that we do not
   // send data if not needed. On the other hand, it could have a performance
   // issue.
   bool delayedStart;
 
   IPCRemoteStreamType stream;
+
+  int64_t length;
 };
 
 // Use IPCStream or OptionalIPCStream in your ipdl to represent serialized
 // nsIInputStreams.  Then use AutoIPCStream from IPCStreamUtils.h to perform
 // the serialization.
 union IPCStream
 {
   InputStreamParamsWithFds;
--- a/ipc/glue/IPCStreamDestination.cpp
+++ b/ipc/glue/IPCStreamDestination.cpp
@@ -1,15 +1,16 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "IPCStreamDestination.h"
+#include "mozilla/InputStreamLengthWrapper.h"
 #include "mozilla/Mutex.h"
 #include "nsIAsyncInputStream.h"
 #include "nsIAsyncOutputStream.h"
 #include "nsIBufferedStreams.h"
 #include "nsICloneableInputStream.h"
 #include "nsIPipe.h"
 
 namespace mozilla {
@@ -259,16 +260,19 @@ NS_INTERFACE_MAP_BEGIN(IPCStreamDestinat
 NS_INTERFACE_MAP_END
 
 // ----------------------------------------------------------------------------
 // IPCStreamDestination
 
 IPCStreamDestination::IPCStreamDestination()
   : mOwningThread(NS_GetCurrentThread())
   , mDelayedStart(false)
+#ifdef MOZ_DEBUG
+  , mLengthSet(false)
+#endif
 {
 }
 
 IPCStreamDestination::~IPCStreamDestination()
 {
 }
 
 nsresult
@@ -297,16 +301,34 @@ IPCStreamDestination::Initialize()
 }
 
 void
 IPCStreamDestination::SetDelayedStart(bool aDelayedStart)
 {
   mDelayedStart = aDelayedStart;
 }
 
+void
+IPCStreamDestination::SetLength(int64_t aLength)
+{
+  MOZ_ASSERT(mReader);
+  MOZ_ASSERT(!mLengthSet);
+
+#ifdef DEBUG
+  mLengthSet = true;
+#endif
+
+  if (aLength != -1) {
+    nsCOMPtr<nsIInputStream> finalStream;
+    finalStream = new InputStreamLengthWrapper(mReader.forget(), aLength);
+    mReader = do_QueryInterface(finalStream);
+    MOZ_ASSERT(mReader);
+  }
+}
+
 already_AddRefed<nsIInputStream>
 IPCStreamDestination::TakeReader()
 {
   MOZ_ASSERT(mReader);
   MOZ_ASSERT(!mDelayedStartInputStream);
 
   if (mDelayedStart) {
     mDelayedStartInputStream =
--- a/ipc/glue/IPCStreamDestination.h
+++ b/ipc/glue/IPCStreamDestination.h
@@ -34,16 +34,19 @@ public:
   Cast(PChildToParentStreamParent* aActor);
 
   static IPCStreamDestination*
   Cast(PParentToChildStreamChild* aActor);
 
   void
   SetDelayedStart(bool aDelayedStart);
 
+  void
+  SetLength(int64_t aLength);
+
   already_AddRefed<nsIInputStream>
   TakeReader();
 
   bool
   IsOnOwningThread() const;
 
   void
   DispatchRunnable(already_AddRefed<nsIRunnable>&& aRunnable);
@@ -91,14 +94,18 @@ private:
   // This is created by TakeReader() if we need to delay the reading of data.
   // We keep a reference to the stream in order to inform it when the actor goes
   // away. If that happens, the reading of data will not be possible anymore.
   class DelayedStartInputStream;
   RefPtr<DelayedStartInputStream> mDelayedStartInputStream;
 
   nsCOMPtr<nsIThread> mOwningThread;
   bool mDelayedStart;
+
+#ifdef MOZ_DEBUG
+  bool mLengthSet;
+#endif
 };
 
 } // namespace ipc
 } // namespace mozilla
 
 #endif // mozilla_ipc_IPCStreamDestination_h
--- a/ipc/glue/IPCStreamUtils.cpp
+++ b/ipc/glue/IPCStreamUtils.cpp
@@ -4,16 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "IPCStreamUtils.h"
 
 #include "nsIIPCSerializableInputStream.h"
 
 #include "mozilla/Assertions.h"
+#include "mozilla/InputStreamLengthHelper.h"
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/File.h"
 #include "mozilla/ipc/FileDescriptorSetChild.h"
 #include "mozilla/ipc/FileDescriptorSetParent.h"
 #include "mozilla/ipc/InputStreamUtils.h"
 #include "mozilla/ipc/IPCStreamDestination.h"
 #include "mozilla/ipc/IPCStreamSource.h"
@@ -132,16 +133,24 @@ SerializeInputStreamWithFdsParent(nsIIPC
 template<typename M>
 bool
 SerializeInputStream(nsIInputStream* aStream, IPCStream& aValue, M* aManager,
                      bool aDelayedStart)
 {
   MOZ_ASSERT(aStream);
   MOZ_ASSERT(aManager);
 
+  // Let's try to take the length using InputStreamLengthHelper. If the length
+  // cannot be taken synchronously, and its length is needed, the stream needs
+  // to be fully copied in memory on the deserialization side.
+  int64_t length;
+  if (!InputStreamLengthHelper::GetSyncLength(aStream, &length)) {
+    length = -1;
+  }
+
   // As a fallback, attempt to stream the data across using a IPCStream
   // actor. For blocking streams, create a nonblocking pipe instead,
   nsCOMPtr<nsIAsyncInputStream> asyncStream = do_QueryInterface(aStream);
   if (!asyncStream) {
     const uint32_t kBufferSize = 32768; // matches IPCStream buffer size.
     nsCOMPtr<nsIAsyncOutputStream> sink;
     nsresult rv = NS_NewPipe2(getter_AddRefs(asyncStream),
                               getter_AddRefs(sink),
@@ -163,16 +172,17 @@ SerializeInputStream(nsIInputStream* aSt
     }
   }
 
   MOZ_ASSERT(asyncStream);
 
   IPCRemoteStream remoteStream;
   remoteStream.delayedStart() = aDelayedStart;
   remoteStream.stream() = IPCStreamSource::Create(asyncStream, aManager);
+  remoteStream.length() = length;
   aValue = remoteStream;
 
   return true;
 }
 
 template<typename M>
 bool
 SerializeInputStreamChild(nsIInputStream* aStream, M* aManager,
@@ -374,16 +384,17 @@ DeserializeIPCStream(const IPCStream& aV
         IPCStreamDestination::Cast(remoteStreamType.get_PChildToParentStreamParent());
     } else {
       MOZ_ASSERT(remoteStreamType.type() == IPCRemoteStreamType::TPParentToChildStreamChild);
       destinationStream =
         IPCStreamDestination::Cast(remoteStreamType.get_PParentToChildStreamChild());
     }
 
     destinationStream->SetDelayedStart(remoteStream.delayedStart());
+    destinationStream->SetLength(remoteStream.length());
     return destinationStream->TakeReader();
   }
 
   // Note, we explicitly do not support deserializing the PChildToParentStream actor on
   // the child side nor the PParentToChildStream actor on the parent side.
   MOZ_ASSERT(aValue.type() == IPCStream::TInputStreamParamsWithFds);
 
   const InputStreamParamsWithFds& streamWithFds =