Bug 1409394 - Avoid extra buffer copy in FileReader, r=smaug
authorAndrea Marchesini <amarchesini@mozilla.com>
Tue, 17 Oct 2017 20:38:03 +0200
changeset 386970 1b7edd51196c233dc8abe81bc20cf4ef2b9207a6
parent 386969 ec62bdeaf15ab8fe363c9cd60b1e8de87123772d
child 386971 a8a1e8cc1980498ea030bd9285570236c4d95dc2
push id32705
push userryanvm@gmail.com
push dateThu, 19 Oct 2017 01:01:49 +0000
treeherdermozilla-central@a21099ce055f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1409394
milestone58.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 1409394 - Avoid extra buffer copy in FileReader, r=smaug
dom/file/FileReader.cpp
--- a/dom/file/FileReader.cpp
+++ b/dom/file/FileReader.cpp
@@ -259,16 +259,47 @@ FileReader::DoAsyncWait()
   if (NS_WARN_IF(NS_FAILED(rv))) {
     DecreaseBusyCounter();
     return rv;
   }
 
   return NS_OK;
 }
 
+namespace {
+
+void
+PopulateBufferForBinaryString(char16_t* aDest, const char* aSource,
+                              uint32_t aCount)
+{
+  const unsigned char* source = (const unsigned char*)aSource;
+  char16_t* end = aDest + aCount;
+  while (aDest != end) {
+    *aDest = *source;
+    ++aDest;
+    ++source;
+  }
+}
+
+nsresult
+ReadFuncBinaryString(nsIInputStream* aInputStream,
+                     void* aClosure,
+                     const char* aFromRawSegment,
+                     uint32_t aToOffset,
+                     uint32_t aCount,
+                     uint32_t* aWriteCount)
+{
+  char16_t* dest = static_cast<char16_t*>(aClosure) + aToOffset;
+  PopulateBufferForBinaryString(dest, aFromRawSegment, aCount);
+  *aWriteCount = aCount;
+  return NS_OK;
+}
+
+} // anonymous
+
 nsresult
 FileReader::DoReadData(uint64_t aCount)
 {
   MOZ_ASSERT(mAsyncStream);
 
   uint32_t bytesRead = 0;
 
   if (mDataFormat == FILE_AS_BINARY) {
@@ -286,44 +317,45 @@ FileReader::DoReadData(uint64_t aCount)
     MOZ_ASSERT(oldLen == mDataLen, "unexpected mResult length");
 
     char16_t* dest = nullptr;
     mResult.GetMutableData(&dest, size.value(), fallible);
     NS_ENSURE_TRUE(dest, NS_ERROR_OUT_OF_MEMORY);
 
     dest += oldLen;
 
-    while (aCount > 0) {
-      char tmpBuffer[4096];
-      uint32_t minCount =
-        XPCOM_MIN(aCount, static_cast<uint64_t>(sizeof(tmpBuffer)));
-      uint32_t read;
-
-      nsresult rv = mAsyncStream->Read(tmpBuffer, minCount, &read);
-      if (rv == NS_BASE_STREAM_CLOSED) {
-        rv = NS_OK;
-      }
-
+    if (NS_InputStreamIsBuffered(mAsyncStream)) {
+      nsresult rv = mAsyncStream->ReadSegments(ReadFuncBinaryString, dest,
+                                               aCount, &bytesRead);
       NS_ENSURE_SUCCESS(rv, rv);
+    } else {
+      while (aCount > 0) {
+        char tmpBuffer[4096];
+        uint32_t minCount =
+          XPCOM_MIN(aCount, static_cast<uint64_t>(sizeof(tmpBuffer)));
+        uint32_t read;
 
-      if (read == 0) {
-        // The stream finished too early.
-        return NS_ERROR_OUT_OF_MEMORY;
-      }
+        nsresult rv = mAsyncStream->Read(tmpBuffer, minCount, &read);
+        if (rv == NS_BASE_STREAM_CLOSED) {
+          rv = NS_OK;
+        }
+
+        NS_ENSURE_SUCCESS(rv, rv);
 
-      char16_t* end = dest + read;
-      const unsigned char* source = (const unsigned char*)tmpBuffer;
-      while (dest != end) {
-        *dest = *source;
-        ++dest;
-        ++source;
+        if (read == 0) {
+          // The stream finished too early.
+          return NS_ERROR_OUT_OF_MEMORY;
+        }
+
+        PopulateBufferForBinaryString(dest, tmpBuffer, read);
+
+        dest += read;
+        aCount -= read;
+        bytesRead += read;
       }
-
-      aCount -= read;
-      bytesRead += read;
     }
 
     MOZ_ASSERT(size.value() == oldLen + bytesRead);
     mResult.Truncate(size.value());
   }
   else {
     CheckedInt<uint64_t> size = mDataLen;
     size += aCount;