Bug 1088043 - read and write nsTArrays more intelligently in IPC serialization; r=bent
authorNathan Froyd <froydnj@mozilla.com>
Tue, 04 Nov 2014 08:57:25 -0500
changeset 214026 13d940a1c8a0953678ea05359d89ffbe22be7edd
parent 214025 5e6d8b6023e32f464ac8595969531f40b5113c05
child 214027 08cef10b6076c64ecbdc7b725ca4b1090185a6b7
push id27771
push userryanvm@gmail.com
push dateWed, 05 Nov 2014 19:04:24 +0000
treeherdermozilla-central@305b4fecce99 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbent
bugs1088043
milestone36.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 1088043 - read and write nsTArrays more intelligently in IPC serialization; r=bent
ipc/glue/IPCMessageUtils.h
--- a/ipc/glue/IPCMessageUtils.h
+++ b/ipc/glue/IPCMessageUtils.h
@@ -6,21 +6,23 @@
 
 #ifndef __IPC_GLUE_IPCMESSAGEUTILS_H__
 #define __IPC_GLUE_IPCMESSAGEUTILS_H__
 
 #include "base/process_util.h"
 #include "chrome/common/ipc_message_utils.h"
 
 #include "mozilla/ArrayUtils.h"
+#include "mozilla/DebugOnly.h"
 #include "mozilla/TimeStamp.h"
 #ifdef XP_WIN
 #include "mozilla/TimeStamp_windows.h"
 #endif
 #include "mozilla/TypedEnum.h"
+#include "mozilla/TypeTraits.h"
 #include "mozilla/IntegerTypeTraits.h"
 
 #include <stdint.h>
 
 #include "nsID.h"
 #include "nsMemory.h"
 #include "nsString.h"
 #include "nsTArray.h"
@@ -459,38 +461,100 @@ struct ParamTraits<nsLiteralString> : Pa
   typedef nsLiteralString paramType;
 };
 
 template <typename E>
 struct ParamTraits<FallibleTArray<E> >
 {
   typedef FallibleTArray<E> paramType;
 
+  // We write arrays of integer or floating-point data using a single pickling
+  // call, rather than writing each element individually.  We deliberately do
+  // not use mozilla::IsPod here because it is perfectly reasonable to have
+  // a data structure T for which IsPod<T>::value is true, yet also have a
+  // ParamTraits<T> specialization.
+  static const bool sUseWriteBytes = (mozilla::IsIntegral<E>::value ||
+                                      mozilla::IsFloatingPoint<E>::value);
+
+  // Compute the byte length for |aNumElements| of type E.  If that length
+  // would overflow an int, return false.  Otherwise, return true and place
+  // the byte length in |aTotalLength|.
+  //
+  // Pickle's ReadBytes/WriteBytes interface takes lengths in ints, hence this
+  // dance.
+  static bool ByteLengthIsValid(size_t aNumElements, int* aTotalLength) {
+    static_assert(sizeof(int) == sizeof(int32_t), "int is an unexpected size!");
+
+    // nsTArray only handles sizes up to INT32_MAX.
+    if (aNumElements > size_t(INT32_MAX)) {
+      return false;
+    }
+
+    int64_t numBytes = static_cast<int64_t>(aNumElements) * sizeof(E);
+    if (numBytes > int64_t(INT32_MAX)) {
+      return false;
+    }
+
+    *aTotalLength = static_cast<int>(numBytes);
+    return true;
+  }
+
   static void Write(Message* aMsg, const paramType& aParam)
   {
     uint32_t length = aParam.Length();
     WriteParam(aMsg, length);
-    for (uint32_t index = 0; index < length; index++) {
-      WriteParam(aMsg, aParam[index]);
+
+    if (sUseWriteBytes) {
+      int pickledLength = 0;
+      mozilla::DebugOnly<bool> valid = ByteLengthIsValid(length, &pickledLength);
+      MOZ_ASSERT(valid);
+      aMsg->WriteBytes(aParam.Elements(), pickledLength);
+    } else {
+      for (uint32_t index = 0; index < length; index++) {
+        WriteParam(aMsg, aParam[index]);
+      }
     }
   }
 
   static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
   {
     uint32_t length;
     if (!ReadParam(aMsg, aIter, &length)) {
       return false;
     }
 
-    aResult->SetCapacity(length);
-    for (uint32_t index = 0; index < length; index++) {
-      E* element = aResult->AppendElement();
-      if (!(element && ReadParam(aMsg, aIter, element))) {
+    if (sUseWriteBytes) {
+      int pickledLength = 0;
+      if (!ByteLengthIsValid(length, &pickledLength)) {
+        return false;
+      }
+
+      const char* outdata;
+      if (!aMsg->ReadBytes(aIter, &outdata, pickledLength)) {
+        return false;
+      }
+
+      E* elements = aResult->AppendElements(length);
+      if (!elements) {
         return false;
       }
+
+      memcpy(elements, outdata, pickledLength);
+    } else {
+      if (!aResult->SetCapacity(length)) {
+        return false;
+      }
+
+      for (uint32_t index = 0; index < length; index++) {
+        E* element = aResult->AppendElement();
+        MOZ_ASSERT(element);
+        if (!ReadParam(aMsg, aIter, element)) {
+          return false;
+        }
+      }
     }
 
     return true;
   }
 
   static void Log(const paramType& aParam, std::wstring* aLog)
   {
     for (uint32_t index = 0; index < aParam.Length(); index++) {