Bug 1262671 - Use BufferList for Pickle (r=froydnj)
authorBill McCloskey <billm@mozilla.com>
Mon, 16 May 2016 15:09:51 -0700
changeset 340381 b6fd41905d10140c620d3ee794cec0e3a3994c89
parent 340380 010987e0dc81f5021cf3b200ceab78d742783d21
child 340382 fcedd1b3ef255d38681ab5e2745e45eaea926fb6
push id1183
push userraliiev@mozilla.com
push dateMon, 05 Sep 2016 20:01:49 +0000
treeherdermozilla-release@3148731bed45 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfroydnj
bugs1262671
milestone49.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 1262671 - Use BufferList for Pickle (r=froydnj)
gfx/ipc/D3DMessageUtils.cpp
ipc/chromium/moz.build
ipc/chromium/src/base/buffer.cc
ipc/chromium/src/base/buffer.h
ipc/chromium/src/base/pickle.cc
ipc/chromium/src/base/pickle.h
ipc/chromium/src/chrome/common/ipc_channel_posix.cc
ipc/chromium/src/chrome/common/ipc_channel_posix.h
ipc/chromium/src/chrome/common/ipc_channel_win.cc
ipc/chromium/src/chrome/common/ipc_channel_win.h
ipc/chromium/src/chrome/common/ipc_message.cc
ipc/chromium/src/chrome/common/ipc_message.h
ipc/glue/IPCMessageUtils.h
ipc/glue/MessageChannel.cpp
ipc/ipdl/test/cxx/TestActorPunning.cpp
--- a/gfx/ipc/D3DMessageUtils.cpp
+++ b/gfx/ipc/D3DMessageUtils.cpp
@@ -51,21 +51,19 @@ ParamTraits<DxgiAdapterDesc>::Write(Mess
   MOZ_ASSERT_UNREACHABLE("DxgiAdapterDesc is Windows-only");
 #endif
 }
 
 bool
 ParamTraits<DxgiAdapterDesc>::Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
 {
 #if defined(XP_WIN)
-  const char* description = nullptr;
-  if (!aMsg->ReadBytes(aIter, &description, sizeof(aResult->Description))) {
+  if (!aMsg->ReadBytesInto(aIter, aResult->Description, sizeof(aResult->Description))) {
     return false;
   }
-  memcpy(aResult->Description, description, sizeof(aResult->Description));
 
   if (ReadParam(aMsg, aIter, &aResult->VendorId) &&
       ReadParam(aMsg, aIter, &aResult->DeviceId) &&
       ReadParam(aMsg, aIter, &aResult->SubSysId) &&
       ReadParam(aMsg, aIter, &aResult->Revision) &&
       ReadParam(aMsg, aIter, &aResult->DedicatedVideoMemory) &&
       ReadParam(aMsg, aIter, &aResult->DedicatedSystemMemory) &&
       ReadParam(aMsg, aIter, &aResult->SharedSystemMemory) &&
--- a/ipc/chromium/moz.build
+++ b/ipc/chromium/moz.build
@@ -4,17 +4,16 @@
 # 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/.
 
 libevent_path_prefix = 'src/third_party'
 include(libevent_path_prefix + '/libeventcommon.mozbuild')
 
 UNIFIED_SOURCES += [
     'src/base/at_exit.cc',
-    'src/base/buffer.cc',
     'src/base/command_line.cc',
     'src/base/file_path.cc',
     'src/base/file_util.cc',
     'src/base/histogram.cc',
     'src/base/lock.cc',
     'src/base/logging.cc',
     'src/base/message_loop.cc',
     'src/base/message_pump_default.cc',
deleted file mode 100644
--- a/ipc/chromium/src/base/buffer.cc
+++ /dev/null
@@ -1,130 +0,0 @@
-/* -*- 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 "buffer.h"
-#include "nsDebug.h"
-
-Buffer::Buffer()
- : mBuffer(nullptr),
-   mSize(0),
-   mReserved(0)
-{
-}
-
-Buffer::~Buffer()
-{
-  if (mBuffer) {
-    free(mBuffer);
-  }
-}
-
-bool
-Buffer::empty() const
-{
-  return mSize == 0;
-}
-
-size_t
-Buffer::size() const
-{
-  return mSize;
-}
-
-const char*
-Buffer::data() const
-{
-  return mBuffer;
-}
-
-void
-Buffer::clear()
-{
-  free(mBuffer);
-  mBuffer = nullptr;
-  mSize = 0;
-  mReserved = 0;
-}
-
-void
-Buffer::try_realloc(size_t newlength)
-{
-  char* buffer = (char*)realloc(mBuffer, newlength);
-  if (buffer || !newlength) {
-    mBuffer = buffer;
-    mReserved = newlength;
-    return;
-  }
-
-  // If we're growing the buffer, crash. If we're shrinking, then we continue to
-  // use the old (larger) buffer.
-  if (newlength > mReserved) {
-    NS_ABORT_OOM(newlength);
-  }
-}
-
-void
-Buffer::append(const char* bytes, size_t length)
-{
-  if (mSize + length > mReserved) {
-    try_realloc(mSize + length);
-  }
-
-  memcpy(mBuffer + mSize, bytes, length);
-  mSize += length;
-}
-
-void
-Buffer::assign(const char* bytes, size_t length)
-{
-  if (bytes >= mBuffer && bytes < mBuffer + mReserved) {
-    MOZ_RELEASE_ASSERT(bytes + length <= mBuffer + mSize);
-    memmove(mBuffer, bytes, length);
-    mSize = length;
-    try_realloc(length);
-  } else {
-    try_realloc(length);
-    mSize = length;
-    memcpy(mBuffer, bytes, length);
-  }
-}
-
-void
-Buffer::erase(size_t start, size_t count)
-{
-  mSize -= count;
-  memmove(mBuffer + start, mBuffer + start + count, mSize - start);
-  try_realloc(mSize);
-}
-
-void
-Buffer::reserve(size_t size)
-{
-  if (mReserved < size) {
-    try_realloc(size);
-  }
-}
-
-char*
-Buffer::trade_bytes(size_t count)
-{
-  MOZ_RELEASE_ASSERT(count);
-
-  char* result = mBuffer;
-  mSize = mReserved = mSize - count;
-  mBuffer = mReserved ? (char*)malloc(mReserved) : nullptr;
-  MOZ_RELEASE_ASSERT(!mReserved || mBuffer);
-  if (mSize) {
-    memcpy(mBuffer, result + count, mSize);
-  }
-
-  // Try to resize the buffer down, but ignore failure. This can cause extra
-  // copies, but so be it.
-  char* resized = (char*)realloc(result, count);
-  if (resized) {
-    return resized;
-  }
-  return result;
-}
deleted file mode 100644
--- a/ipc/chromium/src/base/buffer.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/* -*- 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/. */
-
-#ifndef CHROME_BASE_BUFFER_H_
-#define CHROME_BASE_BUFFER_H_
-
-// Buffer is a simple std::string-like class for buffering up IPC messages. Its
-// main distinguishing characteristic is the trade_bytes function.
-class Buffer {
-public:
-  Buffer();
-  ~Buffer();
-
-  bool empty() const;
-  const char* data() const;
-  size_t size() const;
-
-  void clear();
-  void append(const char* bytes, size_t length);
-  void assign(const char* bytes, size_t length);
-  void erase(size_t start, size_t count);
-
-  void reserve(size_t size);
-
-  // This function should be used by a caller who wants to extract the first
-  // |count| bytes from the buffer. Rather than copying the bytes out, this
-  // function returns the entire buffer. The bytes in range [count, size()) are
-  // copied out to a new buffer which becomes the current buffer. The
-  // presumption is that |count| is very large and approximately equal to size()
-  // so not much needs to be copied.
-  char* trade_bytes(size_t count);
-
-private:
-  void try_realloc(size_t newlength);
-
-  char* mBuffer;
-  size_t mSize;
-  size_t mReserved;
-};
-
-#endif // CHROME_BASE_BUFFER_H_
--- a/ipc/chromium/src/base/pickle.cc
+++ b/ipc/chromium/src/base/pickle.cc
@@ -2,16 +2,17 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #include "base/pickle.h"
 
 #include "mozilla/Alignment.h"
+#include "mozilla/CheckedInt.h"
 #include "mozilla/Endian.h"
 #include "mozilla/TypeTraits.h"
 
 #include <stdlib.h>
 
 #include <limits>
 #include <string>
 #include <algorithm>
@@ -22,23 +23,19 @@
 #define SENTINEL_CHECKING
 #endif
 
 //------------------------------------------------------------------------------
 
 static_assert(MOZ_ALIGNOF(Pickle::memberAlignmentType) >= MOZ_ALIGNOF(uint32_t),
               "Insufficient alignment");
 
-// static
-const int Pickle::kPayloadUnit = 64;
+static const uint32_t kHeaderSegmentCapacity = 64;
 
-const uint32_t kFastGrowthCap = 128 * 1024;
-
-// We mark a read only pickle with a special capacity_.
-static const uint32_t kCapacityReadOnly = (uint32_t) -1;
+static const uint32_t kDefaultSegmentCapacity = 4096;
 
 static const char kBytePaddingMarker = char(0xbf);
 
 namespace {
 
 // We want to copy data to our payload as efficiently as possible.
 // memcpy fits the bill for copying, but not all compilers or
 // architectures support inlining memcpy from void*, which has unknown
@@ -47,138 +44,123 @@ namespace {
 // therefore use that knowledge to construct a copier that will copy
 // efficiently (via standard C++ assignment mechanisms) if the datatype
 // needs that alignment or less, and memcpy otherwise.  (The compiler
 // may still inline memcpy, of course.)
 
 template<typename T, size_t size, bool hasSufficientAlignment>
 struct Copier
 {
-  static void Copy(T* dest, void** iter) {
-    memcpy(dest, *iter, sizeof(T));
+  static void Copy(T* dest, const char* iter) {
+    memcpy(dest, iter, sizeof(T));
   }
 };
 
 // Copying 64-bit quantities happens often enough and can easily be made
 // worthwhile on 32-bit platforms, so handle it specially.  Only do it
 // if 64-bit types aren't sufficiently aligned; the alignment
 // requirements for them vary between 32-bit platforms.
 #ifndef HAVE_64BIT_BUILD
 template<typename T>
 struct Copier<T, sizeof(uint64_t), false>
 {
-  static void Copy(T* dest, void** iter) {
+  static void Copy(T* dest, const char* iter) {
 #if MOZ_LITTLE_ENDIAN
     static const int loIndex = 0, hiIndex = 1;
 #else
     static const int loIndex = 1, hiIndex = 0;
 #endif
     static_assert(MOZ_ALIGNOF(uint32_t*) == MOZ_ALIGNOF(void*),
                   "Pointers have different alignments");
-    uint32_t* src = *reinterpret_cast<uint32_t**>(iter);
+    const uint32_t* src = reinterpret_cast<const uint32_t*>(iter);
     uint32_t* uint32dest = reinterpret_cast<uint32_t*>(dest);
     uint32dest[loIndex] = src[loIndex];
     uint32dest[hiIndex] = src[hiIndex];
   }
 };
 #endif
 
 template<typename T, size_t size>
 struct Copier<T, size, true>
 {
-  static void Copy(T* dest, void** iter) {
-    // The reinterpret_cast is only safe if two conditions hold:
-    // (1) If the alignment of T* is the same as void*;
-    // (2) The alignment of the data in *iter is at least as
-    //     big as MOZ_ALIGNOF(T).
-    // Check the first condition, as the second condition is already
-    // known to be true, or we wouldn't be here.
-    static_assert(MOZ_ALIGNOF(T*) == MOZ_ALIGNOF(void*),
-                  "Pointers have different alignments");
-    *dest = *(*reinterpret_cast<T**>(iter));
+  static void Copy(T* dest, const char* iter) {
+    *dest = *reinterpret_cast<const T*>(iter);
   }
 };
 
 } // anonymous namespace
 
+PickleIterator::PickleIterator(const Pickle& pickle)
+   : iter_(pickle.buffers_.Iter()) {
+  iter_.Advance(pickle.buffers_, pickle.header_size_);
+}
+
 template<typename T>
 void
-PickleIterator::CopyFrom(T* dest) {
+PickleIterator::CopyInto(T* dest) {
   static_assert(mozilla::IsPod<T>::value, "Copied type must be a POD type");
-  Copier<T, sizeof(T), (MOZ_ALIGNOF(T) <= sizeof(Pickle::memberAlignmentType))>::Copy(dest, &iter_);
+  Copier<T, sizeof(T), (MOZ_ALIGNOF(T) <= sizeof(Pickle::memberAlignmentType))>::Copy(dest, iter_.Data());
 }
 
-PickleIterator::PickleIterator(const Pickle& pickle)
-   : iter_(const_cast<char*>(pickle.payload())) {
+bool Pickle::IteratorHasRoomFor(const PickleIterator& iter, uint32_t len) const {
+  // Make sure we don't get into trouble where AlignInt(len) == 0.
+  MOZ_RELEASE_ASSERT(len < 64);
+
+  return iter.iter_.HasRoomFor(AlignInt(len));
+}
+
+void Pickle::UpdateIter(PickleIterator* iter, uint32_t bytes) const {
+  // Make sure we don't get into trouble where AlignInt(bytes) == 0.
+  MOZ_RELEASE_ASSERT(bytes < 64);
+
+  iter->iter_.Advance(buffers_, AlignInt(bytes));
 }
 
 // Payload is sizeof(Pickle::memberAlignmentType) aligned.
 
-Pickle::Pickle()
-    : header_(NULL),
-      header_size_(sizeof(Header)),
-      capacity_(0),
-      variable_buffer_offset_(0) {
-  Resize(kPayloadUnit);
-  header_->payload_size = 0;
-}
-
-Pickle::Pickle(int header_size)
-    : header_(NULL),
-      header_size_(AlignInt(header_size)),
-      capacity_(0),
-      variable_buffer_offset_(0) {
+Pickle::Pickle(uint32_t header_size)
+    : buffers_(AlignInt(header_size), kHeaderSegmentCapacity, kDefaultSegmentCapacity),
+      header_(nullptr),
+      header_size_(AlignInt(header_size)) {
   DCHECK(static_cast<memberAlignmentType>(header_size) >= sizeof(Header));
-  DCHECK(header_size <= kPayloadUnit);
-  Resize(kPayloadUnit);
-  if (!header_) {
-    NS_ABORT_OOM(kPayloadUnit);
-  }
+  DCHECK(header_size_ <= kHeaderSegmentCapacity);
+  header_ = reinterpret_cast<Header*>(buffers_.Start());
   header_->payload_size = 0;
 }
 
-Pickle::Pickle(const char* data, int data_len, Ownership ownership)
-    : header_(reinterpret_cast<Header*>(const_cast<char*>(data))),
-      header_size_(0),
-      capacity_(ownership == BORROWS ? kCapacityReadOnly : data_len),
-      variable_buffer_offset_(0) {
-  if (data_len >= static_cast<int>(sizeof(Header)))
-    header_size_ = data_len - header_->payload_size;
+Pickle::Pickle(uint32_t header_size, const char* data, uint32_t length)
+    : buffers_(length, AlignCapacity(length), kDefaultSegmentCapacity),
+      header_(nullptr),
+      header_size_(AlignInt(header_size)) {
+  DCHECK(static_cast<memberAlignmentType>(header_size) >= sizeof(Header));
+  DCHECK(header_size <= kHeaderSegmentCapacity);
+  MOZ_RELEASE_ASSERT(header_size <= length);
 
-  if (header_size_ > static_cast<unsigned int>(data_len))
-    header_size_ = 0;
-
-  if (header_size_ != AlignInt(header_size_))
-    header_size_ = 0;
-
-  // If there is anything wrong with the data, we're not going to use it.
-  if (!header_size_)
-    header_ = nullptr;
+  header_ = reinterpret_cast<Header*>(buffers_.Start());
+  memcpy(header_, data, length);
 }
 
 Pickle::Pickle(Pickle&& other)
-  : header_(other.header_),
-    header_size_(other.header_size_),
-    capacity_(other.capacity_),
-    variable_buffer_offset_(other.variable_buffer_offset_) {
-  other.header_ = NULL;
-  other.capacity_ = 0;
-  other.variable_buffer_offset_ = 0;
+   : buffers_(mozilla::Move(other.buffers_)),
+     header_(other.header_),
+     header_size_(other.header_size_) {
+  other.header_ = nullptr;
 }
 
 Pickle::~Pickle() {
-  if (capacity_ != kCapacityReadOnly)
-    free(header_);
 }
 
 Pickle& Pickle::operator=(Pickle&& other) {
+  BufferList tmp = mozilla::Move(other.buffers_);
+  other.buffers_ = mozilla::Move(buffers_);
+  buffers_ = mozilla::Move(tmp);
+
+  //std::swap(buffers_, other.buffers_);
   std::swap(header_, other.header_);
   std::swap(header_size_, other.header_size_);
-  std::swap(capacity_, other.capacity_);
-  std::swap(variable_buffer_offset_, other.variable_buffer_offset_);
   return *this;
 }
 
 bool Pickle::ReadBool(PickleIterator* iter, bool* result) const {
   DCHECK(iter);
 
   int tmp;
   if (!ReadInt(iter, &tmp))
@@ -187,271 +169,277 @@ bool Pickle::ReadBool(PickleIterator* it
   *result = tmp ? true : false;
   return true;
 }
 
 bool Pickle::ReadInt16(PickleIterator* iter, int16_t* result) const {
   DCHECK(iter);
 
   if (!IteratorHasRoomFor(*iter, sizeof(*result)))
-    return false;
+    return ReadBytesInto(iter, result, sizeof(*result));
 
-  iter->CopyFrom(result);
+  iter->CopyInto(result);
 
   UpdateIter(iter, sizeof(*result));
   return true;
 }
 
 bool Pickle::ReadUInt16(PickleIterator* iter, uint16_t* result) const {
   DCHECK(iter);
 
   if (!IteratorHasRoomFor(*iter, sizeof(*result)))
-    return false;
+    return ReadBytesInto(iter, result, sizeof(*result));
 
-  iter->CopyFrom(result);
+  iter->CopyInto(result);
 
   UpdateIter(iter, sizeof(*result));
   return true;
 }
 
 bool Pickle::ReadInt(PickleIterator* iter, int* result) const {
   DCHECK(iter);
 
   if (!IteratorHasRoomFor(*iter, sizeof(*result)))
-    return false;
+    return ReadBytesInto(iter, result, sizeof(*result));
 
-  iter->CopyFrom(result);
+  iter->CopyInto(result);
 
   UpdateIter(iter, sizeof(*result));
   return true;
 }
 
 // Always written as a 64-bit value since the size for this type can
 // differ between architectures.
 bool Pickle::ReadLong(PickleIterator* iter, long* result) const {
   DCHECK(iter);
 
-  int64_t bigResult = 0;
-  if (!IteratorHasRoomFor(*iter, sizeof(bigResult)))
-    return false;
+  int64_t big_result = 0;
+  if (IteratorHasRoomFor(*iter, sizeof(big_result))) {
+    iter->CopyInto(&big_result);
+    UpdateIter(iter, sizeof(big_result));
+  } else {
+    if (!ReadBytesInto(iter, &big_result, sizeof(big_result))) {
+      return false;
+    }
+  }
+  DCHECK(big_result <= LONG_MAX && big_result >= LONG_MIN);
+  *result = static_cast<long>(big_result);
 
-  iter->CopyFrom(&bigResult);
-  DCHECK(bigResult <= LONG_MAX && bigResult >= LONG_MIN);
-  *result = static_cast<long>(bigResult);
-
-  UpdateIter(iter, sizeof(bigResult));
   return true;
 }
 
 // Always written as a 64-bit value since the size for this type can
 // differ between architectures.
 bool Pickle::ReadULong(PickleIterator* iter, unsigned long* result) const {
   DCHECK(iter);
 
-  uint64_t bigResult = 0;
-  if (!IteratorHasRoomFor(*iter, sizeof(bigResult)))
-    return false;
+  uint64_t big_result = 0;
+  if (IteratorHasRoomFor(*iter, sizeof(big_result))) {
+    iter->CopyInto(&big_result);
+    UpdateIter(iter, sizeof(big_result));
+  } else {
+    if (!ReadBytesInto(iter, &big_result, sizeof(big_result))) {
+      return false;
+    }
+  }
+  DCHECK(big_result <= ULONG_MAX);
+  *result = static_cast<unsigned long>(big_result);
 
-  iter->CopyFrom(&bigResult);
-  DCHECK(bigResult <= ULONG_MAX);
-  *result = static_cast<unsigned long>(bigResult);
-
-  UpdateIter(iter, sizeof(bigResult));
   return true;
 }
 
 bool Pickle::ReadLength(PickleIterator* iter, int* result) const {
   if (!ReadInt(iter, result))
     return false;
   return ((*result) >= 0);
 }
 
 // Always written as a 64-bit value since the size for this type can
 // differ between architectures.
 bool Pickle::ReadSize(PickleIterator* iter, size_t* result) const {
   DCHECK(iter);
 
-  uint64_t bigResult = 0;
-  if (!IteratorHasRoomFor(*iter, sizeof(bigResult)))
-    return false;
+  uint64_t big_result = 0;
+  if (IteratorHasRoomFor(*iter, sizeof(big_result))) {
+    iter->CopyInto(&big_result);
+    UpdateIter(iter, sizeof(big_result));
+  } else {
+    if (!ReadBytesInto(iter, &big_result, sizeof(big_result))) {
+      return false;
+    }
+  }
+  DCHECK(big_result <= std::numeric_limits<size_t>::max());
+  *result = static_cast<size_t>(big_result);
 
-  iter->CopyFrom(&bigResult);
-  DCHECK(bigResult <= std::numeric_limits<size_t>::max());
-  *result = static_cast<size_t>(bigResult);
-
-  UpdateIter(iter, sizeof(bigResult));
   return true;
 }
 
 bool Pickle::ReadInt32(PickleIterator* iter, int32_t* result) const {
   DCHECK(iter);
 
   if (!IteratorHasRoomFor(*iter, sizeof(*result)))
-    return false;
+    return ReadBytesInto(iter, result, sizeof(*result));
 
-  iter->CopyFrom(result);
+  iter->CopyInto(result);
 
   UpdateIter(iter, sizeof(*result));
   return true;
 }
 
 bool Pickle::ReadUInt32(PickleIterator* iter, uint32_t* result) const {
   DCHECK(iter);
 
   if (!IteratorHasRoomFor(*iter, sizeof(*result)))
-    return false;
+    return ReadBytesInto(iter, result, sizeof(*result));
 
-  iter->CopyFrom(result);
+  iter->CopyInto(result);
 
   UpdateIter(iter, sizeof(*result));
   return true;
 }
 
 bool Pickle::ReadInt64(PickleIterator* iter, int64_t* result) const {
   DCHECK(iter);
 
   if (!IteratorHasRoomFor(*iter, sizeof(*result)))
-    return false;
+    return ReadBytesInto(iter, result, sizeof(*result));
 
-  iter->CopyFrom(result);
+  iter->CopyInto(result);
 
   UpdateIter(iter, sizeof(*result));
   return true;
 }
 
 bool Pickle::ReadUInt64(PickleIterator* iter, uint64_t* result) const {
   DCHECK(iter);
 
   if (!IteratorHasRoomFor(*iter, sizeof(*result)))
-    return false;
+    return ReadBytesInto(iter, result, sizeof(*result));
 
-  iter->CopyFrom(result);
+  iter->CopyInto(result);
 
   UpdateIter(iter, sizeof(*result));
   return true;
 }
 
 bool Pickle::ReadDouble(PickleIterator* iter, double* result) const {
   DCHECK(iter);
 
   if (!IteratorHasRoomFor(*iter, sizeof(*result)))
-    return false;
+    return ReadBytesInto(iter, result, sizeof(*result));
 
-  iter->CopyFrom(result);
+  iter->CopyInto(result);
 
   UpdateIter(iter, sizeof(*result));
   return true;
 }
 
 // Always written as a 64-bit value since the size for this type can
 // differ between architectures.
 bool Pickle::ReadIntPtr(PickleIterator* iter, intptr_t* result) const {
   DCHECK(iter);
 
-  int64_t bigResult = 0;
-  if (!IteratorHasRoomFor(*iter, sizeof(bigResult)))
-    return false;
+  int64_t big_result = 0;
+  if (IteratorHasRoomFor(*iter, sizeof(big_result))) {
+    iter->CopyInto(&big_result);
+    UpdateIter(iter, sizeof(big_result));
+  } else {
+    if (!ReadBytesInto(iter, &big_result, sizeof(big_result))) {
+      return false;
+    }
+  }
 
-  iter->CopyFrom(&bigResult);
-  DCHECK(bigResult <= std::numeric_limits<intptr_t>::max() && bigResult >= std::numeric_limits<intptr_t>::min());
-  *result = static_cast<intptr_t>(bigResult);
+  DCHECK(big_result <= std::numeric_limits<intptr_t>::max() && big_result >= std::numeric_limits<intptr_t>::min());
+  *result = static_cast<intptr_t>(big_result);
 
-  UpdateIter(iter, sizeof(bigResult));
   return true;
 }
 
 bool Pickle::ReadUnsignedChar(PickleIterator* iter, unsigned char* result) const {
   DCHECK(iter);
 
   if (!IteratorHasRoomFor(*iter, sizeof(*result)))
-    return false;
+    return ReadBytesInto(iter, result, sizeof(*result));
 
-  iter->CopyFrom(result);
+  iter->CopyInto(result);
 
   UpdateIter(iter, sizeof(*result));
   return true;
 }
 
 bool Pickle::ReadString(PickleIterator* iter, std::string* result) const {
   DCHECK(iter);
 
   int len;
   if (!ReadLength(iter, &len))
     return false;
-  if (!IteratorHasRoomFor(*iter, len))
-    return false;
 
-  char* chars = reinterpret_cast<char*>(iter->iter_);
-  result->assign(chars, len);
+  auto chars = mozilla::MakeUnique<char[]>(len);
+  if (!ReadBytesInto(iter, chars.get(), len)) {
+    return false;
+  }
+  result->assign(chars.get(), len);
 
-  UpdateIter(iter, len);
   return true;
 }
 
 bool Pickle::ReadWString(PickleIterator* iter, std::wstring* result) const {
   DCHECK(iter);
 
   int len;
   if (!ReadLength(iter, &len))
     return false;
   // Avoid integer multiplication overflow.
   if (len > INT_MAX / static_cast<int>(sizeof(wchar_t)))
     return false;
-  if (!IteratorHasRoomFor(*iter, len * sizeof(wchar_t)))
-    return false;
 
-  wchar_t* chars = reinterpret_cast<wchar_t*>(iter->iter_);
-  result->assign(chars, len);
+  auto chars = mozilla::MakeUnique<wchar_t[]>(len);
+  if (!ReadBytesInto(iter, chars.get(), len * sizeof(wchar_t))) {
+    return false;
+  }
+  result->assign(chars.get(), len);
 
-  UpdateIter(iter, len * sizeof(wchar_t));
   return true;
 }
 
-bool Pickle::ReadBytes(PickleIterator* iter, const char** data, int length,
-                       uint32_t alignment) const {
+bool Pickle::FlattenBytes(PickleIterator* iter, const char** data, uint32_t length,
+                          uint32_t alignment) {
   DCHECK(iter);
   DCHECK(data);
   DCHECK(alignment == 4 || alignment == 8);
   DCHECK(intptr_t(header_) % alignment == 0);
 
-  uint32_t paddingLen = intptr_t(iter->iter_) % alignment;
-  if (paddingLen) {
-#ifdef DEBUG
-    {
-      const char* padding = static_cast<const char*>(iter->iter_);
-      for (uint32_t i = 0; i < paddingLen; i++) {
-        DCHECK(*(padding + i) == kBytePaddingMarker);
-      }
-    }
-#endif
-    length += paddingLen;
+  if (AlignInt(length) < length) {
+    return false;
+  }
+
+  uint32_t padding_len = intptr_t(iter->iter_.Data()) % alignment;
+  if (!iter->iter_.AdvanceAcrossSegments(buffers_, padding_len)) {
+    return false;
+  }
+
+  if (!buffers_.FlattenBytes(iter->iter_, data, length)) {
+    return false;
   }
 
-  if (!IteratorHasRoomFor(*iter, length))
-    return false;
+  header_ = reinterpret_cast<Header*>(buffers_.Start());
 
-  *data = static_cast<const char*>(iter->iter_) + paddingLen;
-  DCHECK(intptr_t(*data) % alignment == 0);
-
-  UpdateIter(iter, length);
-  return true;
+  return iter->iter_.AdvanceAcrossSegments(buffers_, AlignInt(length) - length);
 }
 
-bool Pickle::FlattenBytes(PickleIterator* iter, const char** data, int length,
-                           uint32_t alignment) const {
-  return ReadBytes(iter, data, length, alignment);
-}
-
-bool Pickle::ReadBytesInto(PickleIterator* iter, void* data, int length) const {
-  const char* outp;
-  if (!ReadBytes(iter, &outp, length)) {
+bool Pickle::ReadBytesInto(PickleIterator* iter, void* data, uint32_t length) const {
+  if (AlignInt(length) < length) {
     return false;
   }
-  memcpy(data, outp, length);
-  return true;
+
+  if (!buffers_.ReadBytes(iter->iter_, reinterpret_cast<char*>(data), length)) {
+    return false;
+  }
+
+  return iter->iter_.AdvanceAcrossSegments(buffers_, AlignInt(length) - length);
 }
 
 bool Pickle::ReadSentinel(PickleIterator* iter, uint32_t sentinel) const {
 #ifdef SENTINEL_CHECKING
   uint32_t found;
   if (!ReadUInt32(iter, &found)) {
     return false;
   }
@@ -464,79 +452,71 @@ bool Pickle::ReadSentinel(PickleIterator
 bool Pickle::WriteSentinel(uint32_t sentinel) {
 #ifdef SENTINEL_CHECKING
   return WriteUInt32(sentinel);
 #else
   return true;
 #endif
 }
 
-char* Pickle::BeginWrite(uint32_t length, uint32_t alignment) {
+void Pickle::EndRead(PickleIterator& iter) const {
+  DCHECK(iter.iter_.Done());
+}
+
+void Pickle::BeginWrite(uint32_t length, uint32_t alignment) {
   DCHECK(alignment % 4 == 0) << "Must be at least 32-bit aligned!";
 
   // write at an alignment-aligned offset from the beginning of the header
   uint32_t offset = AlignInt(header_->payload_size);
-  uint32_t padding = (header_size_ + offset) %  alignment;
+  uint32_t padding = (header_size_ + offset) % alignment;
   uint32_t new_size = offset + padding + AlignInt(length);
-  uint32_t needed_size = header_size_ + new_size;
-
-  if (needed_size > capacity_) {
-    double growth_rate = capacity_ < kFastGrowthCap ? 2.0 : 1.4;
-    Resize(std::max(static_cast<uint32_t>(capacity_ * growth_rate), needed_size));
-  }
+  MOZ_RELEASE_ASSERT(new_size >= header_->payload_size);
 
   DCHECK(intptr_t(header_) % alignment == 0);
 
 #ifdef ARCH_CPU_64_BITS
   DCHECK_LE(length, std::numeric_limits<uint32_t>::max());
 #endif
 
-  char* buffer = payload() + offset;
-
   if (padding) {
-    memset(buffer, kBytePaddingMarker, padding);
-    buffer += padding;
+    MOZ_RELEASE_ASSERT(padding <= 8);
+    static const char padding_data[8] = {
+      kBytePaddingMarker, kBytePaddingMarker, kBytePaddingMarker, kBytePaddingMarker,
+      kBytePaddingMarker, kBytePaddingMarker, kBytePaddingMarker, kBytePaddingMarker,
+    };
+    buffers_.WriteBytes(padding_data, padding);
   }
 
-  DCHECK(intptr_t(buffer) % alignment == 0);
+  DCHECK((header_size_ + header_->payload_size + padding) % alignment == 0);
 
   header_->payload_size = new_size;
-
-#ifdef MOZ_VALGRIND
-  // pad the trailing end as well, so that valgrind
-  // doesn't complain when we write the buffer
-  padding = AlignInt(length) - length;
-  if (padding) {
-    memset(buffer + length, kBytePaddingMarker, padding);
-  }
-#endif
-
-  return buffer;
 }
 
-void Pickle::EndWrite(char* dest, int length) {
+void Pickle::EndWrite(uint32_t length) {
   // Zero-pad to keep tools like purify from complaining about uninitialized
   // memory.
-  if (length % sizeof(memberAlignmentType))
-    memset(dest + length, 0,
-           sizeof(memberAlignmentType) - (length % sizeof(memberAlignmentType)));
+  uint32_t padding = AlignInt(length) - length;
+  if (padding) {
+    MOZ_RELEASE_ASSERT(padding <= 4);
+    static const char padding_data[4] = {
+      kBytePaddingMarker, kBytePaddingMarker, kBytePaddingMarker, kBytePaddingMarker,
+    };
+    buffers_.WriteBytes(padding_data, padding);
+  }
 }
 
-bool Pickle::WriteBytes(const void* data, int data_len, uint32_t alignment) {
-  DCHECK(capacity_ != kCapacityReadOnly) << "oops: pickle is readonly";
+bool Pickle::WriteBytes(const void* data, uint32_t data_len, uint32_t alignment) {
   DCHECK(alignment == 4 || alignment == 8);
   DCHECK(intptr_t(header_) % alignment == 0);
 
-  char* dest = BeginWrite(data_len, alignment);
-  if (!dest)
-    return false;
+  BeginWrite(data_len, alignment);
 
-  memcpy(dest, data, data_len);
+  buffers_.WriteBytes(reinterpret_cast<const char*>(data), data_len);
 
-  EndWrite(dest, data_len);
+  EndWrite(data_len);
   return true;
 }
 
 bool Pickle::WriteString(const std::string& value) {
   if (!WriteInt(static_cast<int>(value.size())))
     return false;
 
   return WriteBytes(value.data(), static_cast<int>(value.size()));
@@ -545,80 +525,48 @@ bool Pickle::WriteString(const std::stri
 bool Pickle::WriteWString(const std::wstring& value) {
   if (!WriteInt(static_cast<int>(value.size())))
     return false;
 
   return WriteBytes(value.data(),
                     static_cast<int>(value.size() * sizeof(wchar_t)));
 }
 
-bool Pickle::WriteData(const char* data, int length) {
+bool Pickle::WriteData(const char* data, uint32_t length) {
   return WriteInt(length) && WriteBytes(data, length);
 }
 
-char* Pickle::BeginWriteData(int length) {
-  DCHECK_EQ(variable_buffer_offset_, 0U) <<
-    "There can only be one variable buffer in a Pickle";
-
-  if (!WriteInt(length))
-    return NULL;
-
-  char *data_ptr = BeginWrite(length, sizeof(memberAlignmentType));
-  if (!data_ptr)
-    return NULL;
-
-  variable_buffer_offset_ =
-      data_ptr - reinterpret_cast<char*>(header_) - sizeof(int);
-
-  // EndWrite doesn't necessarily have to be called after the write operation,
-  // so we call it here to pad out what the caller will eventually write.
-  EndWrite(data_ptr, length);
-  return data_ptr;
+void Pickle::InputBytes(const char* data, uint32_t length) {
+  buffers_.WriteBytes(data, length);
 }
 
-void Pickle::Resize(uint32_t new_capacity) {
-  new_capacity = ConstantAligner<kPayloadUnit>::align(new_capacity);
-
-  void* p = moz_xrealloc(header_, new_capacity);
-
-  header_ = reinterpret_cast<Header*>(p);
-  capacity_ = new_capacity;
+int32_t* Pickle::GetInt32PtrForTest(uint32_t offset) {
+  size_t pos = buffers_.Size() - offset;
+  BufferList::IterImpl iter(buffers_);
+  MOZ_RELEASE_ASSERT(iter.AdvanceAcrossSegments(buffers_, pos));
+  return reinterpret_cast<int32_t*>(iter.Data());
 }
 
 // static
-const char* Pickle::FindNext(uint32_t header_size,
+uint32_t Pickle::MessageSize(uint32_t header_size,
                              const char* start,
                              const char* end) {
   DCHECK(header_size == AlignInt(header_size));
-  DCHECK(header_size <= static_cast<memberAlignmentType>(kPayloadUnit));
-
-  if (end < start)
-    return nullptr;
-  size_t length = static_cast<size_t>(end - start);
-  if (length < sizeof(Header))
-    return nullptr;
-
-  const Header* hdr = reinterpret_cast<const Header*>(start);
-  if (length < header_size || length - header_size < hdr->payload_size)
-    return nullptr;
-
-  return start + header_size + hdr->payload_size;
-}
-
-// static
-uint32_t Pickle::GetLength(uint32_t header_size,
-                           const char* start,
-                           const char* end) {
-  DCHECK(header_size == AlignInt(header_size));
-  DCHECK(header_size <= static_cast<memberAlignmentType>(kPayloadUnit));
+  DCHECK(header_size <= static_cast<memberAlignmentType>(kHeaderSegmentCapacity));
 
   if (end < start)
     return 0;
   size_t length = static_cast<size_t>(end - start);
   if (length < sizeof(Header))
     return 0;
 
   const Header* hdr = reinterpret_cast<const Header*>(start);
   if (length < header_size)
     return 0;
 
-  return header_size + hdr->payload_size;
+  mozilla::CheckedInt<uint32_t> sum(header_size);
+  sum += hdr->payload_size;
+
+  if (!sum.isValid())
+    return 0;
+
+  return sum.value();
 }
--- a/ipc/chromium/src/base/pickle.h
+++ b/ipc/chromium/src/base/pickle.h
@@ -9,30 +9,32 @@
 
 #include <string>
 
 #include "base/basictypes.h"
 #include "base/logging.h"
 #include "base/string16.h"
 
 #include "mozilla/Attributes.h"
+#include "mozilla/BufferList.h"
+#include "mozilla/mozalloc.h"
 
 class Pickle;
 
 class PickleIterator {
 public:
   explicit PickleIterator(const Pickle& pickle);
 
 private:
   friend class Pickle;
 
+  mozilla::BufferList<InfallibleAllocPolicy>::IterImpl iter_;
+
   template<typename T>
-  void CopyFrom(T* dest);
-
-  void* iter_;
+  void CopyInto(T* dest);
 };
 
 // This class provides facilities for basic binary value packing and unpacking.
 //
 // The Pickle class supports appending primitive values (ints, strings, etc.)
 // to a pickle instance.  The Pickle instance grows its internal memory buffer
 // dynamically to hold the sequence of primitive values.   The internal memory
 // buffer is exposed as the "data" of the Pickle.  This "data" can be passed
@@ -44,59 +46,44 @@ private:
 //
 // The Pickle's data has a header which contains the size of the Pickle's
 // payload.  It can optionally support additional space in the header.  That
 // space is controlled by the header_size parameter passed to the Pickle
 // constructor.
 //
 class Pickle {
  public:
-  enum Ownership {
-    BORROWS,
-    OWNS,
-  };
-
   ~Pickle();
 
-  // Initialize a Pickle object using the default header size.
-  Pickle();
+  Pickle() = delete;
 
   // Initialize a Pickle object with the specified header size in bytes, which
   // must be greater-than-or-equal-to sizeof(Pickle::Header).  The header size
   // will be rounded up to ensure that the header size is 32bit-aligned.
-  explicit Pickle(int header_size);
+  explicit Pickle(uint32_t header_size);
 
-  // Initializes a Pickle from a const block of data. If ownership == BORROWS,
-  // the data is not copied; instead the data is merely referenced by this
-  // Pickle. Only const methods should be used on the Pickle when initialized
-  // this way. The header padding size is deduced from the data length.  If
-  // ownership == OWNS, then again no copying takes place. However, the buffer
-  // is writable and will be freed when this Pickle is destroyed.
-  Pickle(const char* data, int data_len, Ownership ownership = BORROWS);
+  Pickle(uint32_t header_size, const char* data, uint32_t length);
 
   Pickle(const Pickle& other) = delete;
 
   Pickle(Pickle&& other);
 
   // Performs a deep copy.
   Pickle& operator=(const Pickle& other) = delete;
 
   Pickle& operator=(Pickle&& other);
 
   // Returns the size of the Pickle's data.
-  int size() const { return static_cast<int>(header_size_ +
-                                             header_->payload_size); }
+  uint32_t size() const { return header_size_ + header_->payload_size; }
+
+  typedef mozilla::BufferList<InfallibleAllocPolicy> BufferList;
 
-  // Return the full size of the memory allocated for this Pickle's data.
-  uint32_t capacity() const {
-    return capacity_;
-  }
+  const BufferList& Buffers() const { return buffers_; }
 
-  // Returns the data for this Pickle.
-  const void* data() const { return header_; }
+  uint32_t CurrentSize() const { return buffers_.Size(); }
 
   // Methods for reading the payload of the Pickle.  To read from the start of
   // the Pickle, initialize *iter to NULL.  If successful, these methods return
   // true.  Otherwise, false is returned to indicate that the result could not
   // be extracted.
   MOZ_MUST_USE bool ReadBool(PickleIterator* iter, bool* result) const;
   MOZ_MUST_USE bool ReadInt16(PickleIterator* iter, int16_t* result) const;
   MOZ_MUST_USE bool ReadUInt16(PickleIterator* iter, uint16_t* result) const;
@@ -109,29 +96,27 @@ class Pickle {
   MOZ_MUST_USE bool ReadUInt32(PickleIterator* iter, uint32_t* result) const;
   MOZ_MUST_USE bool ReadInt64(PickleIterator* iter, int64_t* result) const;
   MOZ_MUST_USE bool ReadUInt64(PickleIterator* iter, uint64_t* result) const;
   MOZ_MUST_USE bool ReadDouble(PickleIterator* iter, double* result) const;
   MOZ_MUST_USE bool ReadIntPtr(PickleIterator* iter, intptr_t* result) const;
   MOZ_MUST_USE bool ReadUnsignedChar(PickleIterator* iter, unsigned char* result) const;
   MOZ_MUST_USE bool ReadString(PickleIterator* iter, std::string* result) const;
   MOZ_MUST_USE bool ReadWString(PickleIterator* iter, std::wstring* result) const;
-  MOZ_MUST_USE bool ReadBytesInto(PickleIterator* iter, void* data, int length) const;
-  MOZ_MUST_USE bool FlattenBytes(PickleIterator* iter, const char** data, int length,
-                                 uint32_t alignment = sizeof(memberAlignmentType)) const;
+  MOZ_MUST_USE bool ReadBytesInto(PickleIterator* iter, void* data, uint32_t length) const;
+  MOZ_MUST_USE bool FlattenBytes(PickleIterator* iter, const char** data, uint32_t length,
+                                 uint32_t alignment = sizeof(memberAlignmentType));
 
   // Safer version of ReadInt() checks for the result not being negative.
   // Use it for reading the object sizes.
   MOZ_MUST_USE bool ReadLength(PickleIterator* iter, int* result) const;
 
   MOZ_MUST_USE bool ReadSentinel(PickleIterator* iter, uint32_t sentinel) const;
 
-  void EndRead(PickleIterator& iter) const {
-    DCHECK(iter.iter_ == end_of_payload());
-  }
+  void EndRead(PickleIterator& iter) const;
 
   // Methods for adding to the payload of the Pickle.  These values are
   // appended to the end of the Pickle's payload.  When reading values from a
   // Pickle, it is important to read them in the order in which they were added
   // to the Pickle.
   bool WriteBool(bool value) {
     return WriteInt(value ? 1 : 0);
   }
@@ -179,31 +164,25 @@ class Pickle {
     // differ between architectures.
     return WriteInt64(int64_t(value));
   }
   bool WriteUnsignedChar(unsigned char value) {
     return WriteBytes(&value, sizeof(value));
   }
   bool WriteString(const std::string& value);
   bool WriteWString(const std::wstring& value);
-  bool WriteData(const char* data, int length);
-  bool WriteBytes(const void* data, int data_len,
+  bool WriteData(const char* data, uint32_t length);
+  bool WriteBytes(const void* data, uint32_t data_len,
                   uint32_t alignment = sizeof(memberAlignmentType));
 
   bool WriteSentinel(uint32_t sentinel);
 
-  // Same as WriteData, but allows the caller to write directly into the
-  // Pickle. This saves a copy in cases where the data is not already
-  // available in a buffer. The caller should take care to not write more
-  // than the length it declares it will. Use ReadData to get the data.
-  // Returns NULL on failure.
-  //
-  // The returned pointer will only be valid until the next write operation
-  // on this Pickle.
-  char* BeginWriteData(int length);
+  int32_t* GetInt32PtrForTest(uint32_t offset);
+
+  void InputBytes(const char* data, uint32_t length);
 
   // Payload follows after allocation of Header (header size is customizable).
   struct Header {
     uint32_t payload_size;  // Specifies the size of the payload.
   };
 
   // Returns the header, cast to a user-specified type T.  The type T must be a
   // subclass of Header and its size must correspond to the header_size passed
@@ -214,108 +193,72 @@ class Pickle {
     return static_cast<T*>(header_);
   }
   template <class T>
   const T* headerT() const {
     DCHECK(sizeof(T) == header_size_);
     return static_cast<const T*>(header_);
   }
 
-  // Returns true if the given iterator could point to data with the given
-  // length. If there is no room for the given data before the end of the
-  // payload, returns false.
-  bool IteratorHasRoomFor(const PickleIterator& iter, int len) const {
-    if ((len < 0) || (iter.iter_ < header_) || iter.iter_ > end_of_payload())
-      return false;
-    const char* end_of_region = reinterpret_cast<const char*>(iter.iter_) + len;
-    // Watch out for overflow in pointer calculation, which wraps.
-    return (iter.iter_ <= end_of_region) && (end_of_region <= end_of_payload());
-  }
-
   typedef uint32_t memberAlignmentType;
 
  protected:
-  MOZ_MUST_USE bool ReadBytes(PickleIterator* iter, const char** data, int length,
-                              uint32_t alignment = sizeof(memberAlignmentType)) const;
-
   uint32_t payload_size() const { return header_->payload_size; }
 
-  char* payload() {
-    return reinterpret_cast<char*>(header_) + header_size_;
-  }
-  const char* payload() const {
-    return reinterpret_cast<const char*>(header_) + header_size_;
-  }
-
-  // Returns the address of the byte immediately following the currently valid
-  // header + payload.
-  char* end_of_payload() {
-    // We must have a valid header_.
-    return payload() + payload_size();
-  }
-  const char* end_of_payload() const {
-    // This object may be invalid.
-    return header_ ? payload() + payload_size() : nullptr;
-  }
-
   // Resizes the buffer for use when writing the specified amount of data. The
   // location that the data should be written at is returned, or NULL if there
   // was an error. Call EndWrite with the returned offset and the given length
   // to pad out for the next write.
-  char* BeginWrite(uint32_t length, uint32_t alignment);
+  void BeginWrite(uint32_t length, uint32_t alignment);
 
   // Completes the write operation by padding the data with NULL bytes until it
   // is padded. Should be paired with BeginWrite, but it does not necessarily
   // have to be called after the data is written.
-  void EndWrite(char* dest, int length);
-
-  // Resize the capacity, note that the input value should include the size of
-  // the header: new_capacity = sizeof(Header) + desired_payload_capacity.
-  // A realloc() failure will cause a Resize failure... and caller should check
-  // the return result for true (i.e., successful resizing).
-  void Resize(uint32_t new_capacity);
+  void EndWrite(uint32_t length);
 
   // Round 'bytes' up to the next multiple of 'alignment'.  'alignment' must be
   // a power of 2.
   template<uint32_t alignment> struct ConstantAligner {
     static uint32_t align(int bytes) {
       static_assert((alignment & (alignment - 1)) == 0,
                     "alignment must be a power of two");
       return (bytes + (alignment - 1)) & ~static_cast<uint32_t>(alignment - 1);
     }
   };
 
   static uint32_t AlignInt(int bytes) {
     return ConstantAligner<sizeof(memberAlignmentType)>::align(bytes);
   }
 
+  static uint32_t AlignCapacity(int bytes) {
+    return ConstantAligner<kSegmentAlignment>::align(bytes);
+  }
+
+  // Returns true if the given iterator could point to data with the given
+  // length. If there is no room for the given data before the end of the
+  // payload, returns false.
+  bool IteratorHasRoomFor(const PickleIterator& iter, uint32_t len) const;
+
   // Moves the iterator by the given number of bytes, making sure it is aligned.
   // Pointer (iterator) is NOT aligned, but the change in the pointer
   // is guaranteed to be a multiple of sizeof(memberAlignmentType).
-  static void UpdateIter(PickleIterator* iter, int bytes) {
-    iter->iter_ = static_cast<char*>(iter->iter_) + AlignInt(bytes);
-  }
+  void UpdateIter(PickleIterator* iter, uint32_t bytes) const;
 
-  // Find the end of the pickled data that starts at range_start.  Returns NULL
-  // if the entire Pickle is not found in the given data range.
-  static const char* FindNext(uint32_t header_size,
+  // Figure out how big the message starting at range_start is. Returns 0 if
+  // there's no enough data to determine (i.e., if [range_start, range_end) does
+  // not contain enough of the message header to know the size).
+  static uint32_t MessageSize(uint32_t header_size,
                               const char* range_start,
                               const char* range_end);
 
-  // If the given range contains at least header_size bytes, return the length
-  // of the pickled data including the header.
-  static uint32_t GetLength(uint32_t header_size,
-                            const char* range_start,
-                            const char* range_end);
-
-  // The allocation granularity of the payload.
-  static const int kPayloadUnit;
+  // Segments capacities are aligned to 8 bytes to ensure that all reads/writes
+  // at 8-byte aligned offsets will be on 8-byte aligned pointers.
+  static const uint32_t kSegmentAlignment = 8;
 
  private:
   friend class PickleIterator;
 
+  BufferList buffers_;
   Header* header_;
   uint32_t header_size_;
-  uint32_t capacity_;
-  uint32_t variable_buffer_offset_;
 };
 
 #endif  // BASE_PICKLE_H__
--- a/ipc/chromium/src/chrome/common/ipc_channel_posix.cc
+++ b/ipc/chromium/src/chrome/common/ipc_channel_posix.cc
@@ -30,16 +30,19 @@
 #include "base/string_util.h"
 #include "base/singleton.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/file_descriptor_set_posix.h"
 #include "chrome/common/ipc_message_utils.h"
 #include "mozilla/ipc/ProtocolUtils.h"
 #include "mozilla/UniquePtr.h"
 
+// Work around possible OS limitations.
+static const size_t kMaxIOVecSize = 256;
+
 #ifdef MOZ_TASK_TRACER
 #include "GeckoTaskTracerImpl.h"
 using namespace mozilla::tasktracer;
 #endif
 
 namespace IPC {
 
 // IPC channels on Windows use named pipes (CreateNamedPipe()) with
@@ -180,17 +183,18 @@ Channel::ChannelImpl::ChannelImpl(int fd
   EnqueueHelloMessage();
 }
 
 void Channel::ChannelImpl::Init(Mode mode, Listener* listener) {
   DCHECK(kControlBufferSlopBytes >= CMSG_SPACE(0));
 
   mode_ = mode;
   is_blocked_on_write_ = false;
-  message_send_bytes_written_ = 0;
+  partial_write_iter_.reset();
+  input_buf_offset_ = 0;
   server_listen_pipe_ = -1;
   pipe_ = -1;
   client_pipe_ = -1;
   listener_ = listener;
   waiting_connect_ = true;
   processing_incoming_ = false;
   closed_ = false;
 #if defined(OS_MACOSX)
@@ -258,21 +262,16 @@ bool Channel::ChannelImpl::EnqueueHelloM
     Close();
     return false;
   }
 
   OutputQueuePush(msg.release());
   return true;
 }
 
-void Channel::ChannelImpl::ClearAndShrinkInputOverflowBuf()
-{
-  input_overflow_buf_.clear();
-}
-
 bool Channel::ChannelImpl::Connect() {
   if (pipe_ == -1) {
     return false;
   }
 
   MessageLoopForIO::current()->WatchFileDescriptor(
       pipe_,
       true,
@@ -282,49 +281,50 @@ bool Channel::ChannelImpl::Connect() {
   waiting_connect_ = false;
 
   if (!waiting_connect_)
     return ProcessOutgoingMessages();
   return true;
 }
 
 bool Channel::ChannelImpl::ProcessIncomingMessages() {
-  ssize_t bytes_read = 0;
-
   struct msghdr msg = {0};
-  struct iovec iov = {input_buf_, Channel::kReadBufferSize};
+  struct iovec iov;
 
   msg.msg_iov = &iov;
   msg.msg_iovlen = 1;
   msg.msg_control = input_cmsg_buf_;
 
   for (;;) {
     msg.msg_controllen = sizeof(input_cmsg_buf_);
 
-    if (bytes_read == 0) {
-      if (pipe_ == -1)
-        return false;
+    if (pipe_ == -1)
+      return false;
 
-      // Read from pipe.
-      // recvmsg() returns 0 if the connection has closed or EAGAIN if no data
-      // is waiting on the pipe.
-      bytes_read = HANDLE_EINTR(recvmsg(pipe_, &msg, MSG_DONTWAIT));
+    // In some cases the beginning of a message will be stored in input_buf_. We
+    // don't want to overwrite that, so we store the new data after it.
+    iov.iov_base = input_buf_ + input_buf_offset_;
+    iov.iov_len = Channel::kReadBufferSize - input_buf_offset_;
 
-      if (bytes_read < 0) {
-        if (errno == EAGAIN) {
-          return true;
-        } else {
-          CHROMIUM_LOG(ERROR) << "pipe error (" << pipe_ << "): " << strerror(errno);
-          return false;
-        }
-      } else if (bytes_read == 0) {
-        // The pipe has closed...
-        Close();
+    // Read from pipe.
+    // recvmsg() returns 0 if the connection has closed or EAGAIN if no data
+    // is waiting on the pipe.
+    ssize_t bytes_read = HANDLE_EINTR(recvmsg(pipe_, &msg, MSG_DONTWAIT));
+
+    if (bytes_read < 0) {
+      if (errno == EAGAIN) {
+        return true;
+      } else {
+        CHROMIUM_LOG(ERROR) << "pipe error (" << pipe_ << "): " << strerror(errno);
         return false;
       }
+    } else if (bytes_read == 0) {
+      // The pipe has closed...
+      Close();
+      return false;
     }
     DCHECK(bytes_read);
 
     if (client_pipe_ != -1) {
       Singleton<PipeMap>()->Remove(pipe_name_);
       HANDLE_EINTR(close(client_pipe_));
       client_pipe_ = -1;
     }
@@ -368,54 +368,18 @@ bool Channel::ChannelImpl::ProcessIncomi
             return false;
           }
           break;
         }
       }
     }
 
     // Process messages from input buffer.
-    const char *p;
-    const char *overflowp;
-    const char *end;
-    if (input_overflow_buf_.empty()) {
-      overflowp = NULL;
-      p = input_buf_;
-      end = p + bytes_read;
-    } else {
-      if (input_overflow_buf_.size() >
-         static_cast<size_t>(kMaximumMessageSize - bytes_read)) {
-        ClearAndShrinkInputOverflowBuf();
-        CHROMIUM_LOG(ERROR) << "IPC message is too big";
-        return false;
-      }
-
-      input_overflow_buf_.append(input_buf_, bytes_read);
-      overflowp = p = input_overflow_buf_.data();
-      end = p + input_overflow_buf_.size();
-
-      // If we've received the entire header, then we know the message
-      // length. In that case, reserve enough space to hold the entire
-      // message. This is more efficient than repeatedly enlarging the buffer as
-      // more data comes in.
-      uint32_t length = Message::GetLength(p, end);
-      if (length) {
-        if (length > kMaximumMessageSize) {
-          ClearAndShrinkInputOverflowBuf();
-          CHROMIUM_LOG(ERROR) << "IPC message is too big";
-          return false;
-        }
-
-        input_overflow_buf_.reserve(length + kReadBufferSize);
-
-        // Recompute these pointers in case the buffer moved.
-        overflowp = p = input_overflow_buf_.data();
-        end = p + input_overflow_buf_.size();
-      }
-    }
+    const char *p = input_buf_;
+    const char *end = input_buf_ + input_buf_offset_ + bytes_read;
 
     // A pointer to an array of |num_fds| file descriptors which includes any
     // fds that have spilled over from a previous read.
     const int* fds;
     unsigned num_fds;
     unsigned fds_i = 0;  // the index of the first unused descriptor
 
     if (input_overflow_fds_.empty()) {
@@ -425,141 +389,164 @@ bool Channel::ChannelImpl::ProcessIncomi
       const size_t prev_size = input_overflow_fds_.size();
       input_overflow_fds_.resize(prev_size + num_wire_fds);
       memcpy(&input_overflow_fds_[prev_size], wire_fds,
              num_wire_fds * sizeof(int));
       fds = &input_overflow_fds_[0];
       num_fds = input_overflow_fds_.size();
     }
 
+    // The data for the message we're currently reading consists of any data
+    // stored in incoming_message_ followed by data in input_buf_ (followed by
+    // other messages).
+
     while (p < end) {
-      const char* message_tail = Message::FindNext(p, end);
-      if (message_tail) {
-        int len = static_cast<int>(message_tail - p);
-        char* buf;
+      // Try to figure out how big the message is. Size is 0 if we haven't read
+      // enough of the header to know the size.
+      uint32_t message_length = 0;
+      if (incoming_message_.isSome()) {
+        message_length = incoming_message_.ref().size();
+      } else {
+        message_length = Message::MessageSize(p, end);
+      }
+
+      if (!message_length) {
+        // We haven't seen the full message header.
+        MOZ_ASSERT(incoming_message_.isNothing());
+
+        // Move everything we have to the start of the buffer. We'll finish
+        // reading this message when we get more data. For now we leave it in
+        // input_buf_.
+        memmove(input_buf_, p, end - p);
+        input_buf_offset_ = end - p;
+
+        break;
+      }
+
+      input_buf_offset_ = 0;
+
+      bool partial;
+      if (incoming_message_.isSome()) {
+        // We already have some data for this message stored in
+        // incoming_message_. We want to append the new data there.
+        Message& m = incoming_message_.ref();
 
-        // The Message |m| allocated below needs to own its data. We can either
-        // copy the data out of the buffer or else steal the buffer and move the
-        // remaining data elsewhere. If len is large enough, we steal. Otherwise
-        // we copy.
-        if (len > kMaxCopySize) {
-          // Since len > kMaxCopySize > kReadBufferSize, we know that we must be
-          // using the overflow buffer. And since we always shift everything to
-          // the left at the end of a read, we must be at the start of the
-          // overflow buffer.
-          MOZ_RELEASE_ASSERT(p == overflowp);
-          buf = input_overflow_buf_.trade_bytes(len);
+        // How much data from this message remains to be added to
+        // incoming_message_?
+        MOZ_ASSERT(message_length > m.CurrentSize());
+        uint32_t remaining = message_length - m.CurrentSize();
+
+        // How much data from this message is stored in input_buf_?
+        uint32_t in_buf = std::min(remaining, uint32_t(end - p));
+
+        m.InputBytes(p, in_buf);
+        p += in_buf;
+
+        // Are we done reading this message?
+        partial = in_buf != remaining;
+      } else {
+        // How much data from this message is stored in input_buf_?
+        uint32_t in_buf = std::min(message_length, uint32_t(end - p));
 
-          // At this point the remaining data is at the front of
-          // input_overflow_buf_. p will get fixed up at the end of the
-          // loop. Set it to null here to make sure no one uses it.
-          p = nullptr;
-          overflowp = message_tail = input_overflow_buf_.data();
-          end = overflowp + input_overflow_buf_.size();
-        } else {
-          buf = (char*)moz_xmalloc(len);
-          memcpy(buf, p, len);
+        incoming_message_.emplace(p, in_buf);
+        p += in_buf;
+
+        // Are we done reading this message?
+        partial = in_buf != message_length;
+      }
+
+      if (partial) {
+        break;
+      }
+
+      Message& m = incoming_message_.ref();
+
+      if (m.header()->num_fds) {
+        // the message has file descriptors
+        const char* error = NULL;
+        if (m.header()->num_fds > num_fds - fds_i) {
+          // the message has been completely received, but we didn't get
+          // enough file descriptors.
+          error = "Message needs unreceived descriptors";
         }
-        Message m(buf, len, Message::OWNS);
-        if (m.header()->num_fds) {
-          // the message has file descriptors
-          const char* error = NULL;
-          if (m.header()->num_fds > num_fds - fds_i) {
-            // the message has been completely received, but we didn't get
-            // enough file descriptors.
-            error = "Message needs unreceived descriptors";
-          }
+
+        if (m.header()->num_fds >
+            FileDescriptorSet::MAX_DESCRIPTORS_PER_MESSAGE) {
+          // There are too many descriptors in this message
+          error = "Message requires an excessive number of descriptors";
+        }
 
-          if (m.header()->num_fds >
-              FileDescriptorSet::MAX_DESCRIPTORS_PER_MESSAGE) {
-            // There are too many descriptors in this message
-            error = "Message requires an excessive number of descriptors";
-          }
-
-          if (error) {
-            CHROMIUM_LOG(WARNING) << error
-                                  << " channel:" << this
-                                  << " message-type:" << m.type()
-                                  << " header()->num_fds:" << m.header()->num_fds
-                                  << " num_fds:" << num_fds
-                                  << " fds_i:" << fds_i;
-            // close the existing file descriptors so that we don't leak them
-            for (unsigned i = fds_i; i < num_fds; ++i)
-              HANDLE_EINTR(close(fds[i]));
-            input_overflow_fds_.clear();
-            // abort the connection
-            return false;
-          }
+        if (error) {
+          CHROMIUM_LOG(WARNING) << error
+                                << " channel:" << this
+                                << " message-type:" << m.type()
+                                << " header()->num_fds:" << m.header()->num_fds
+                                << " num_fds:" << num_fds
+                                << " fds_i:" << fds_i;
+          // close the existing file descriptors so that we don't leak them
+          for (unsigned i = fds_i; i < num_fds; ++i)
+            HANDLE_EINTR(close(fds[i]));
+          input_overflow_fds_.clear();
+          // abort the connection
+          return false;
+        }
 
 #if defined(OS_MACOSX)
-          // Send a message to the other side, indicating that we are now
-          // responsible for closing the descriptor.
-          Message *fdAck = new Message(MSG_ROUTING_NONE,
-                                       RECEIVED_FDS_MESSAGE_TYPE,
-                                       IPC::Message::PRIORITY_NORMAL);
-          DCHECK(m.fd_cookie() != 0);
-          fdAck->set_fd_cookie(m.fd_cookie());
-          OutputQueuePush(fdAck);
+        // Send a message to the other side, indicating that we are now
+        // responsible for closing the descriptor.
+        Message *fdAck = new Message(MSG_ROUTING_NONE,
+                                     RECEIVED_FDS_MESSAGE_TYPE,
+                                     IPC::Message::PRIORITY_NORMAL);
+        DCHECK(m.fd_cookie() != 0);
+        fdAck->set_fd_cookie(m.fd_cookie());
+        OutputQueuePush(fdAck);
 #endif
 
-          m.file_descriptor_set()->SetDescriptors(
-              &fds[fds_i], m.header()->num_fds);
-          fds_i += m.header()->num_fds;
-        }
+        m.file_descriptor_set()->SetDescriptors(
+                                                &fds[fds_i], m.header()->num_fds);
+        fds_i += m.header()->num_fds;
+      }
 #ifdef IPC_MESSAGE_DEBUG_EXTRA
-        DLOG(INFO) << "received message on channel @" << this <<
-                      " with type " << m.type();
+      DLOG(INFO) << "received message on channel @" << this <<
+        " with type " << m.type();
 #endif
 
 #ifdef MOZ_TASK_TRACER
-        AutoSaveCurTraceInfo saveCurTraceInfo;
-        SetCurTraceInfo(m.header()->source_event_id,
-                        m.header()->parent_task_id,
-                        m.header()->source_event_type);
+      AutoSaveCurTraceInfo saveCurTraceInfo;
+      SetCurTraceInfo(m.header()->source_event_id,
+                      m.header()->parent_task_id,
+                      m.header()->source_event_type);
 #endif
 
-        if (m.routing_id() == MSG_ROUTING_NONE &&
-            m.type() == HELLO_MESSAGE_TYPE) {
-          // The Hello message contains only the process id.
-          listener_->OnChannelConnected(MessageIterator(m).NextInt());
+      if (m.routing_id() == MSG_ROUTING_NONE &&
+          m.type() == HELLO_MESSAGE_TYPE) {
+        // The Hello message contains only the process id.
+        listener_->OnChannelConnected(MessageIterator(m).NextInt());
 #if defined(OS_MACOSX)
-        } else if (m.routing_id() == MSG_ROUTING_NONE &&
-                   m.type() == RECEIVED_FDS_MESSAGE_TYPE) {
-          DCHECK(m.fd_cookie() != 0);
-          CloseDescriptors(m.fd_cookie());
+      } else if (m.routing_id() == MSG_ROUTING_NONE &&
+                 m.type() == RECEIVED_FDS_MESSAGE_TYPE) {
+        DCHECK(m.fd_cookie() != 0);
+        CloseDescriptors(m.fd_cookie());
 #endif
-        } else {
-          listener_->OnMessageReceived(mozilla::Move(m));
-        }
-        p = message_tail;
       } else {
-        // Last message is partial.
-        break;
+        listener_->OnMessageReceived(mozilla::Move(m));
       }
+
+      incoming_message_.reset();
     }
-    if (end == p) {
-      ClearAndShrinkInputOverflowBuf();
-    } else if (!overflowp) {
-      // p is from input_buf_
-      input_overflow_buf_.assign(p, end - p);
-    } else if (p > overflowp) {
-      // p is from input_overflow_buf_
-      input_overflow_buf_.erase(0, p - overflowp);
-    }
+
     input_overflow_fds_ = std::vector<int>(&fds[fds_i], &fds[num_fds]);
 
     // When the input data buffer is empty, the overflow fds should be too. If
     // this is not the case, we probably have a rogue renderer which is trying
     // to fill our descriptor table.
-    if (input_overflow_buf_.empty() && !input_overflow_fds_.empty()) {
+    if (incoming_message_.isNothing() && input_buf_offset_ == 0 && !input_overflow_fds_.empty()) {
       // We close these descriptors in Close()
       return false;
     }
-
-    bytes_read = 0;  // Get more data.
   }
 
   return true;
 }
 
 bool Channel::ChannelImpl::ProcessOutgoingMessages() {
   DCHECK(!waiting_connect_);  // Why are we trying to send messages if there's
                               // no connection?
@@ -577,17 +564,17 @@ bool Channel::ChannelImpl::ProcessOutgoi
     Message* msg = output_queue_.front();
 
     struct msghdr msgh = {0};
 
     static const int tmp = CMSG_SPACE(sizeof(
         int[FileDescriptorSet::MAX_DESCRIPTORS_PER_MESSAGE]));
     char buf[tmp];
 
-    if (message_send_bytes_written_ == 0 &&
+    if (partial_write_iter_.isNothing() &&
         !msg->file_descriptor_set()->empty()) {
       // This is the first chunk of a message which has descriptors to send
       struct cmsghdr *cmsg;
       const unsigned num_fds = msg->file_descriptor_set()->size();
 
       if (num_fds > FileDescriptorSet::MAX_DESCRIPTORS_PER_MESSAGE) {
         CHROMIUM_LOG(FATAL) << "Too many file descriptors!";
         // This should not be reached.
@@ -605,26 +592,56 @@ bool Channel::ChannelImpl::ProcessOutgoi
       msgh.msg_controllen = cmsg->cmsg_len;
 
       msg->header()->num_fds = num_fds;
 #if defined(OS_MACOSX)
       msg->set_fd_cookie(++last_pending_fd_id_);
 #endif
     }
 
-    size_t amt_to_write = msg->size() - message_send_bytes_written_;
-    DCHECK(amt_to_write != 0);
-    const char *out_bytes = reinterpret_cast<const char*>(msg->data()) +
-        message_send_bytes_written_;
+    struct iovec iov[kMaxIOVecSize];
+    size_t iov_count = 0;
+    size_t amt_to_write = 0;
+
+    if (partial_write_iter_.isNothing()) {
+      Pickle::BufferList::IterImpl iter(msg->Buffers());
+      partial_write_iter_.emplace(iter);
+    }
+
+    // How much of this message have we written so far?
+    Pickle::BufferList::IterImpl iter = partial_write_iter_.value();
+
+    // Store the unwritten part of the first segment to write into the iovec.
+    iov[0].iov_base = const_cast<char*>(iter.Data());
+    iov[0].iov_len = iter.RemainingInSegment();
+    amt_to_write += iov[0].iov_len;
+    iter.Advance(msg->Buffers(), iov[0].iov_len);
+    iov_count++;
 
-    struct iovec iov = {const_cast<char*>(out_bytes), amt_to_write};
-    msgh.msg_iov = &iov;
-    msgh.msg_iovlen = 1;
+    // Store remaining segments to write into iovec.
+    while (!iter.Done()) {
+      char* data = iter.Data();
+      size_t size = iter.RemainingInSegment();
+
+      // Don't add more than kMaxIOVecSize to the iovec so that we avoid
+      // OS-dependent limits.
+      if (iov_count < kMaxIOVecSize) {
+        iov[iov_count].iov_base = data;
+        iov[iov_count].iov_len = size;
+        iov_count++;
+      }
+      amt_to_write += size;
+      iter.Advance(msg->Buffers(), size);
+    }
+
+    msgh.msg_iov = iov;
+    msgh.msg_iovlen = iov_count;
 
     ssize_t bytes_written = HANDLE_EINTR(sendmsg(pipe_, &msgh, MSG_DONTWAIT));
+
 #if !defined(OS_MACOSX)
     // On OSX CommitAll gets called later, once we get the RECEIVED_FDS_MESSAGE_TYPE
     // message.
     if (bytes_written > 0)
       msg->file_descriptor_set()->CommitAll();
 #endif
 
     if (bytes_written < 0) {
@@ -658,32 +675,32 @@ bool Channel::ChannelImpl::ProcessOutgoi
 #endif
       default:
         CHROMIUM_LOG(ERROR) << "pipe error: " << strerror(errno);
         return false;
       }
     }
 
     if (static_cast<size_t>(bytes_written) != amt_to_write) {
+      // If write() fails with EAGAIN then bytes_written will be -1.
       if (bytes_written > 0) {
-        // If write() fails with EAGAIN then bytes_written will be -1.
-        message_send_bytes_written_ += bytes_written;
+        partial_write_iter_.ref().AdvanceAcrossSegments(msg->Buffers(), bytes_written);
       }
 
       // Tell libevent to call us back once things are unblocked.
       is_blocked_on_write_ = true;
       MessageLoopForIO::current()->WatchFileDescriptor(
           pipe_,
           false,  // One shot
           MessageLoopForIO::WATCH_WRITE,
           &write_watcher_,
           this);
       return true;
     } else {
-      message_send_bytes_written_ = 0;
+      partial_write_iter_.reset();
 
 #if defined(OS_MACOSX)
       if (!msg->file_descriptor_set()->empty())
         pending_fds_.push_back(PendingDescriptors(msg->fd_cookie(),
                                                   msg->file_descriptor_set()));
 #endif
 
       // Message sent OK!
--- a/ipc/chromium/src/chrome/common/ipc_channel_posix.h
+++ b/ipc/chromium/src/chrome/common/ipc_channel_posix.h
@@ -11,23 +11,24 @@
 
 #include <sys/socket.h>  // for CMSG macros
 
 #include <queue>
 #include <string>
 #include <vector>
 #include <list>
 
-#include "base/buffer.h"
 #include "base/message_loop.h"
 #include "base/task.h"
 #include "chrome/common/file_descriptor_set_posix.h"
 
 #include "nsAutoPtr.h"
 
+#include "mozilla/Maybe.h"
+
 namespace IPC {
 
 // An implementation of ChannelImpl for POSIX systems that works via
 // socketpairs.  See the .cc file for an overview of the implementation.
 class Channel::ChannelImpl : public MessageLoopForIO::Watcher {
  public:
   // Mirror methods of Channel, see ipc_channel.h for description.
   ChannelImpl(const std::wstring& channel_id, Mode mode, Listener* listener);
@@ -58,18 +59,16 @@ class Channel::ChannelImpl : public Mess
  private:
   void Init(Mode mode, Listener* listener);
   bool CreatePipe(const std::wstring& channel_id, Mode mode);
   bool EnqueueHelloMessage();
 
   bool ProcessIncomingMessages();
   bool ProcessOutgoingMessages();
 
-  void ClearAndShrinkInputOverflowBuf();
-
   // MessageLoopForIO::Watcher implementation.
   virtual void OnFileCanReadWithoutBlocking(int fd);
   virtual void OnFileCanWriteWithoutBlocking(int fd);
 
 #if defined(OS_MACOSX)
   void CloseDescriptors(uint32_t pending_fd_id);
 #endif
 
@@ -82,35 +81,37 @@ class Channel::ChannelImpl : public Mess
   // stop listening.
   MessageLoopForIO::FileDescriptorWatcher server_listen_connection_watcher_;
   MessageLoopForIO::FileDescriptorWatcher read_watcher_;
   MessageLoopForIO::FileDescriptorWatcher write_watcher_;
 
   // Indicates whether we're currently blocked waiting for a write to complete.
   bool is_blocked_on_write_;
 
-  // If sending a message blocks then we use this variable
-  // to keep track of where we are.
-  size_t message_send_bytes_written_;
+  // If sending a message blocks then we use this iterator to keep track of
+  // where in the message we are. It gets reset when the message is finished
+  // sending.
+  mozilla::Maybe<Pickle::BufferList::IterImpl> partial_write_iter_;
 
   int server_listen_pipe_;
   int pipe_;
   int client_pipe_;  // The client end of our socketpair().
 
   // The "name" of our pipe.  On Windows this is the global identifier for
   // the pipe.  On POSIX it's used as a key in a local map of file descriptors.
   std::string pipe_name_;
 
   Listener* listener_;
 
   // Messages to be sent are queued here.
   std::queue<Message*> output_queue_;
 
   // We read from the pipe into this buffer
   char input_buf_[Channel::kReadBufferSize];
+  size_t input_buf_offset_;
 
   // We want input_cmsg_buf_ to be big enough to hold
   // CMSG_SPACE(Channel::kReadBufferSize) bytes (see the comment below for an
   // explanation of where Channel::kReadBufferSize comes from). However,
   // CMSG_SPACE is apparently not a constant on Macs, so we can't use it in the
   // array size. Consequently, we pick a number here that is at least
   // CMSG_SPACE(0) on all platforms. And we assert at runtime, in
   // Channel::ChannelImpl::Init, that it's big enough.
@@ -124,19 +125,19 @@ class Channel::ChannelImpl : public Mess
   // data for every file descriptor added to the message, so kReadBufferSize
   // bytes of data can never be accompanied by more than
   // kReadBufferSize / sizeof(int) file descriptors. Since a file descriptor
   // takes sizeof(int) bytes, the control buffer must be
   // Channel::kReadBufferSize bytes. We add kControlBufferSlopBytes bytes
   // for the control header.
   char input_cmsg_buf_[Channel::kReadBufferSize + kControlBufferSlopBytes];
 
-  // Large messages that span multiple pipe buffers, get built-up using
-  // this buffer.
-  Buffer input_overflow_buf_;
+  // Large incoming messages that span multiple pipe buffers get built-up in the
+  // buffers of this message.
+  mozilla::Maybe<Message> incoming_message_;
   std::vector<int> input_overflow_fds_;
 
   // In server-mode, we have to wait for the client to connect before we
   // can begin reading.  We make use of the input_state_ when performing
   // the connect operation in overlapped mode.
   bool waiting_connect_;
 
   // This flag is set when processing incoming messages.  It is used to
--- a/ipc/chromium/src/chrome/common/ipc_channel_win.cc
+++ b/ipc/chromium/src/chrome/common/ipc_channel_win.cc
@@ -83,16 +83,17 @@ Channel::ChannelImpl::ChannelImpl(const 
 
 void Channel::ChannelImpl::Init(Mode mode, Listener* listener) {
   pipe_ = INVALID_HANDLE_VALUE;
   listener_ = listener;
   waiting_connect_ = (mode == MODE_SERVER);
   processing_incoming_ = false;
   closed_ = false;
   output_queue_length_ = 0;
+  input_buf_offset_ = 0;
 }
 
 void Channel::ChannelImpl::OutputQueuePush(Message* msg)
 {
   output_queue_.push(msg);
   output_queue_length_++;
 }
 
@@ -327,18 +328,18 @@ bool Channel::ChannelImpl::ProcessIncomi
 
   for (;;) {
     if (bytes_read == 0) {
       if (INVALID_HANDLE_VALUE == pipe_)
         return false;
 
       // Read from pipe...
       BOOL ok = ReadFile(pipe_,
-                         input_buf_,
-                         Channel::kReadBufferSize,
+                         input_buf_ + input_buf_offset_,
+                         Channel::kReadBufferSize - input_buf_offset_,
                          &bytes_read,
                          &input_state_.context.overlapped);
       if (!ok) {
         DWORD err = GetLastError();
         if (err == ERROR_IO_PENDING) {
           input_state_.is_pending = true;
           return true;
         }
@@ -347,111 +348,104 @@ bool Channel::ChannelImpl::ProcessIncomi
       }
       input_state_.is_pending = true;
       return true;
     }
     DCHECK(bytes_read);
 
     // Process messages from input buffer.
 
-    const char* p, *end;
-    if (input_overflow_buf_.empty()) {
-      p = input_buf_;
-      end = p + bytes_read;
-    } else {
-      if (input_overflow_buf_.size() > (kMaximumMessageSize - bytes_read)) {
-        input_overflow_buf_.clear();
-        CHROMIUM_LOG(ERROR) << "IPC message is too big";
-        return false;
-      }
-
-      input_overflow_buf_.append(input_buf_, bytes_read);
-      p = input_overflow_buf_.data();
-      end = p + input_overflow_buf_.size();
-
-      // If we've received the entire header, then we know the message
-      // length. In that case, reserve enough space to hold the entire
-      // message. This is more efficient than repeatedly enlarging the buffer as
-      // more data comes in.
-      uint32_t length = Message::GetLength(p, end);
-      if (length) {
-        if (length > kMaximumMessageSize) {
-          input_overflow_buf_.clear();
-          CHROMIUM_LOG(ERROR) << "IPC message is too big";
-          return false;
-        }
-
-        input_overflow_buf_.reserve(length + kReadBufferSize);
-
-        // Recompute these pointers in case the buffer moved.
-        p = input_overflow_buf_.data();
-        end = p + input_overflow_buf_.size();
-      }
-    }
+    const char *p = input_buf_;
+    const char *end = input_buf_ + input_buf_offset_ + bytes_read;
 
     while (p < end) {
-      const char* message_tail = Message::FindNext(p, end);
-      if (message_tail) {
-        int len = static_cast<int>(message_tail - p);
-        char* buf;
-
-        // The Message |m| allocated below needs to own its data. We can either
-        // copy the data out of the buffer or else steal the buffer and move the
-        // remaining data elsewhere. If len is large enough, we steal. Otherwise
-        // we copy.
-        if (len > kMaxCopySize) {
-          // Since len > kMaxCopySize > kReadBufferSize, we know that we must be
-          // using the overflow buffer. And since we always shift everything to
-          // the left at the end of a read, we must be at the start of the
-          // overflow buffer.
-          buf = input_overflow_buf_.trade_bytes(len);
+      // Try to figure out how big the message is. Size is 0 if we haven't read
+      // enough of the header to know the size.
+      uint32_t message_length = 0;
+      if (incoming_message_.isSome()) {
+        message_length = incoming_message_.ref().size();
+      } else {
+        message_length = Message::MessageSize(p, end);
+      }
 
-          // At this point the remaining data is at the front of
-          // input_overflow_buf_. p will get fixed up at the end of the
-          // loop. Set it to null here to make sure no one uses it.
-          p = nullptr;
-          message_tail = input_overflow_buf_.data();
-          end = message_tail + input_overflow_buf_.size();
-        } else {
-          buf = (char*)moz_xmalloc(len);
-          memcpy(buf, p, len);
-        }
-        Message m(buf, len, Message::OWNS);
-#ifdef IPC_MESSAGE_DEBUG_EXTRA
-        DLOG(INFO) << "received message on channel @" << this <<
-                      " with type " << m.type();
-#endif
-        if (m.routing_id() == MSG_ROUTING_NONE &&
-            m.type() == HELLO_MESSAGE_TYPE) {
-          // The Hello message contains the process id and must include the
-          // shared secret, if we are waiting for it.
-          MessageIterator it = MessageIterator(m);
-          int32_t claimed_pid = it.NextInt();
-          if (waiting_for_shared_secret_ && (it.NextInt() != shared_secret_)) {
-            NOTREACHED();
-            // Something went wrong. Abort connection.
-            Close();
-            listener_->OnChannelError();
-            return false;
-          }
-          waiting_for_shared_secret_ = false;
-          listener_->OnChannelConnected(claimed_pid);
-        } else {
-          listener_->OnMessageReceived(mozilla::Move(m));
-        }
-        p = message_tail;
-      } else {
-        // Last message is partial.
+      if (!message_length) {
+        // We haven't seen the full message header.
+        MOZ_ASSERT(incoming_message_.isNothing());
+
+        // Move everything we have to the start of the buffer. We'll finish
+        // reading this message when we get more data. For now we leave it in
+        // input_buf_.
+        memmove(input_buf_, p, end - p);
+        input_buf_offset_ = end - p;
+
         break;
       }
-    }
-    if (p != input_overflow_buf_.data()) {
-      // Don't assign unless we have to since this will throw away any memory we
-      // might have reserved.
-      input_overflow_buf_.assign(p, end - p);
+
+      input_buf_offset_ = 0;
+
+      bool partial;
+      if (incoming_message_.isSome()) {
+        // We already have some data for this message stored in
+        // incoming_message_. We want to append the new data there.
+        Message& m = incoming_message_.ref();
+
+        // How much data from this message remains to be added to
+        // incoming_message_?
+        MOZ_ASSERT(message_length > m.CurrentSize());
+        uint32_t remaining = message_length - m.CurrentSize();
+
+        // How much data from this message is stored in input_buf_?
+        uint32_t in_buf = std::min(remaining, uint32_t(end - p));
+
+        m.InputBytes(p, in_buf);
+        p += in_buf;
+
+        // Are we done reading this message?
+        partial = in_buf != remaining;
+      } else {
+        // How much data from this message is stored in input_buf_?
+        uint32_t in_buf = std::min(message_length, uint32_t(end - p));
+
+        incoming_message_.emplace(p, in_buf);
+        p += in_buf;
+
+        // Are we done reading this message?
+        partial = in_buf != message_length;
+      }
+
+      if (partial) {
+        break;
+      }
+
+      Message& m = incoming_message_.ref();
+
+#ifdef IPC_MESSAGE_DEBUG_EXTRA
+      DLOG(INFO) << "received message on channel @" << this <<
+                    " with type " << m.type();
+#endif
+      if (m.routing_id() == MSG_ROUTING_NONE &&
+	  m.type() == HELLO_MESSAGE_TYPE) {
+	// The Hello message contains the process id and must include the
+	// shared secret, if we are waiting for it.
+	MessageIterator it = MessageIterator(m);
+	int32_t claimed_pid = it.NextInt();
+	if (waiting_for_shared_secret_ && (it.NextInt() != shared_secret_)) {
+	  NOTREACHED();
+	  // Something went wrong. Abort connection.
+	  Close();
+	  listener_->OnChannelError();
+	  return false;
+	}
+	waiting_for_shared_secret_ = false;
+	listener_->OnChannelConnected(claimed_pid);
+      } else {
+	listener_->OnMessageReceived(mozilla::Move(m));
+      }
+
+      incoming_message_.reset();
     }
 
     bytes_read = 0;  // Get more data.
   }
 
   return true;
 }
 
@@ -468,31 +462,45 @@ bool Channel::ChannelImpl::ProcessOutgoi
     if (!context || bytes_written == 0) {
       DWORD err = GetLastError();
       CHROMIUM_LOG(ERROR) << "pipe error: " << err;
       return false;
     }
     // Message was sent.
     DCHECK(!output_queue_.empty());
     Message* m = output_queue_.front();
-    OutputQueuePop();
-    delete m;
+
+    MOZ_RELEASE_ASSERT(partial_write_iter_.isSome());
+    Pickle::BufferList::IterImpl& iter = partial_write_iter_.ref();
+    iter.Advance(m->Buffers(), bytes_written);
+    if (iter.Done()) {
+      partial_write_iter_.reset();
+      OutputQueuePop();
+      delete m;
+    }
   }
 
   if (output_queue_.empty())
     return true;
 
   if (INVALID_HANDLE_VALUE == pipe_)
     return false;
 
   // Write to pipe...
   Message* m = output_queue_.front();
+
+  if (partial_write_iter_.isNothing()) {
+    Pickle::BufferList::IterImpl iter(m->Buffers());
+    partial_write_iter_.emplace(iter);
+  }
+
+  Pickle::BufferList::IterImpl& iter = partial_write_iter_.ref();
   BOOL ok = WriteFile(pipe_,
-                      m->data(),
-                      m->size(),
+                      iter.Data(),
+                      iter.RemainingInSegment(),
                       &bytes_written,
                       &output_state_.context.overlapped);
   if (!ok) {
     DWORD err = GetLastError();
     if (err == ERROR_IO_PENDING) {
       output_state_.is_pending = true;
 
 #ifdef IPC_MESSAGE_DEBUG_EXTRA
--- a/ipc/chromium/src/chrome/common/ipc_channel_win.h
+++ b/ipc/chromium/src/chrome/common/ipc_channel_win.h
@@ -7,21 +7,22 @@
 #ifndef CHROME_COMMON_IPC_CHANNEL_WIN_H_
 #define CHROME_COMMON_IPC_CHANNEL_WIN_H_
 
 #include "chrome/common/ipc_channel.h"
 
 #include <queue>
 #include <string>
 
-#include "base/buffer.h"
 #include "base/message_loop.h"
 #include "base/task.h"
 #include "nsISupportsImpl.h"
 
+#include "mozilla/Maybe.h"
+
 namespace IPC {
 
 class Channel::ChannelImpl : public MessageLoopForIO::IOHandler {
  public:
   // Mirror methods of Channel, see ipc_channel.h for description.
   ChannelImpl(const std::wstring& channel_id, Mode mode, Listener* listener);
   ChannelImpl(const std::wstring& channel_id, HANDLE server_pipe,
               Mode mode, Listener* listener);
@@ -78,22 +79,28 @@ class Channel::ChannelImpl : public Mess
 
   HANDLE pipe_;
 
   Listener* listener_;
 
   // Messages to be sent are queued here.
   std::queue<Message*> output_queue_;
 
+  // If sending a message blocks then we use this iterator to keep track of
+  // where in the message we are. It gets reset when the message is finished
+  // sending.
+  mozilla::Maybe<Pickle::BufferList::IterImpl> partial_write_iter_;
+
   // We read from the pipe into this buffer
   char input_buf_[Channel::kReadBufferSize];
+  size_t input_buf_offset_;
 
-  // Large messages that span multiple pipe buffers, get built-up using
-  // this buffer.
-  Buffer input_overflow_buf_;
+  // Large incoming messages that span multiple pipe buffers get built-up in the
+  // buffers of this message.
+  mozilla::Maybe<Message> incoming_message_;
 
   // In server-mode, we have to wait for the client to connect before we
   // can begin reading.  We make use of the input_state_ when performing
   // the connect operation in overlapped mode.
   bool waiting_connect_;
 
   // This flag is set when processing incoming messages.  It is used to
   // avoid recursing through ProcessIncomingMessages, which could cause
--- a/ipc/chromium/src/chrome/common/ipc_message.cc
+++ b/ipc/chromium/src/chrome/common/ipc_message.cc
@@ -68,18 +68,18 @@ Message::Message(int32_t routing_id, msg
 #ifdef MOZ_TASK_TRACER
   header()->source_event_id = 0;
   header()->parent_task_id = 0;
   header()->source_event_type = SourceEventType::Unknown;
 #endif
   InitLoggingVariables(aName);
 }
 
-Message::Message(const char* data, int data_len, Ownership ownership)
-  : Pickle(data, data_len, ownership)
+Message::Message(const char* data, int data_len)
+  : Pickle(sizeof(Header), data, data_len)
 {
   MOZ_COUNT_CTOR(IPC::Message);
   InitLoggingVariables();
 }
 
 Message::Message(Message&& other) : Pickle(mozilla::Move(other)) {
   MOZ_COUNT_CTOR(IPC::Message);
   InitLoggingVariables(other.name_);
--- a/ipc/chromium/src/chrome/common/ipc_message.h
+++ b/ipc/chromium/src/chrome/common/ipc_message.h
@@ -67,22 +67,17 @@ class Message : public Pickle {
   Message();
 
   // Initialize a message with a user-defined type, priority value, and
   // destination WebView ID.
   Message(int32_t routing_id, msgid_t type, PriorityValue priority,
           MessageCompression compression = COMPRESSION_NONE,
           const char* const name="???");
 
-  // Initializes a message from a const block of data. If ownership == BORROWS,
-  // the data is not copied; instead the data is merely referenced by this
-  // message. Only const methods should be used on the message when initialized
-  // this way. If ownership == OWNS, then again no copying takes place. However,
-  // the buffer is writable and will be freed when the message is destroyed.
-  Message(const char* data, int data_len, Ownership ownership = BORROWS);
+  Message(const char* data, int data_len);
 
   Message(const Message& other) = delete;
   Message(Message&& other);
   Message& operator=(const Message& other) = delete;
   Message& operator=(Message&& other);
 
   PriorityValue priority() const {
     return static_cast<PriorityValue>(header()->flags & PRIORITY_MASK);
@@ -235,26 +230,21 @@ class Message : public Pickle {
     (obj->*func)(*msg);
     return true;
   }
 
   // Used for async messages with no parameters.
   static void Log(const Message* msg, std::wstring* l) {
   }
 
-  // Find the end of the message data that starts at range_start.  Returns NULL
-  // if the entire message is not found in the given data range.
-  static const char* FindNext(const char* range_start, const char* range_end) {
-    return Pickle::FindNext(sizeof(Header), range_start, range_end);
-  }
-
-  // If the given range contains at least header_size bytes, return the length
-  // of the message including the header.
-  static uint32_t GetLength(const char* range_start, const char* range_end) {
-    return Pickle::GetLength(sizeof(Header), range_start, range_end);
+  // Figure out how big the message starting at range_start is. Returns 0 if
+  // there's no enough data to determine (i.e., if [range_start, range_end) does
+  // not contain enough of the message header to know the size).
+  static uint32_t MessageSize(const char* range_start, const char* range_end) {
+    return Pickle::MessageSize(sizeof(Header), range_start, range_end);
   }
 
 #if defined(OS_POSIX)
   // On POSIX, a message supports reading / writing FileDescriptor objects.
   // This is used to pass a file descriptor to the peer of an IPC channel.
 
   // Add a descriptor to the end of the set. Returns false iff the set is full.
   bool WriteFileDescriptor(const base::FileDescriptor& descriptor);
--- a/ipc/glue/IPCMessageUtils.h
+++ b/ipc/glue/IPCMessageUtils.h
@@ -726,18 +726,18 @@ struct ParamTraits<mozilla::SerializedSt
     if (!aResult->dataLength) {
       aResult->data = nullptr;
       return true;
     }
 
     const char** buffer =
       const_cast<const char**>(reinterpret_cast<char**>(&aResult->data));
     // Structured clone data must be 64-bit aligned.
-    if (!aMsg->FlattenBytes(aIter, buffer, aResult->dataLength,
-                            sizeof(uint64_t))) {
+    if (!const_cast<Message*>(aMsg)->FlattenBytes(aIter, buffer, aResult->dataLength,
+                                                  sizeof(uint64_t))) {
       return false;
     }
 
     return true;
   }
 
   static void Log(const paramType& aParam, std::wstring* aLog)
   {
--- a/ipc/glue/MessageChannel.cpp
+++ b/ipc/glue/MessageChannel.cpp
@@ -754,19 +754,19 @@ MessageChannel::Echo(Message* aMsg)
 
     mLink->EchoMessage(msg.forget());
     return true;
 }
 
 bool
 MessageChannel::Send(Message* aMsg)
 {
-    if (aMsg->capacity() >= kMinTelemetryMessageSize) {
+    if (aMsg->size() >= kMinTelemetryMessageSize) {
         Telemetry::Accumulate(Telemetry::IPC_MESSAGE_SIZE,
-                              nsDependentCString(aMsg->name()), aMsg->capacity());
+                              nsDependentCString(aMsg->name()), aMsg->size());
     }
 
     CxxStackFrame frame(*this, OUT_MESSAGE, aMsg);
 
     nsAutoPtr<Message> msg(aMsg);
     AssertWorkerThread();
     mMonitor->AssertNotCurrentThreadOwns();
     if (MSG_ROUTING_NONE == msg->routing_id()) {
@@ -1055,19 +1055,19 @@ MessageChannel::ProcessPendingRequests(A
             ProcessPendingRequest(Move(*it));
         }
     }
 }
 
 bool
 MessageChannel::Send(Message* aMsg, Message* aReply)
 {
-    if (aMsg->capacity() >= kMinTelemetryMessageSize) {
+    if (aMsg->size() >= kMinTelemetryMessageSize) {
         Telemetry::Accumulate(Telemetry::IPC_MESSAGE_SIZE,
-                              nsDependentCString(aMsg->name()), aMsg->capacity());
+                              nsDependentCString(aMsg->name()), aMsg->size());
     }
 
     nsAutoPtr<Message> msg(aMsg);
 
     // Sanity checks.
     AssertWorkerThread();
     mMonitor->AssertNotCurrentThreadOwns();
 
@@ -1245,19 +1245,19 @@ MessageChannel::Send(Message* aMsg, Mess
     MOZ_RELEASE_ASSERT(reply);
     MOZ_RELEASE_ASSERT(reply->is_reply(), "expected reply");
     MOZ_RELEASE_ASSERT(!reply->is_reply_error());
     MOZ_RELEASE_ASSERT(reply->seqno() == seqno);
     MOZ_RELEASE_ASSERT(reply->type() == replyType, "wrong reply type");
     MOZ_RELEASE_ASSERT(reply->is_sync());
 
     *aReply = Move(*reply);
-    if (aReply->capacity() >= kMinTelemetryMessageSize) {
+    if (aReply->size() >= kMinTelemetryMessageSize) {
         Telemetry::Accumulate(Telemetry::IPC_REPLY_SIZE,
-                              nsDependentCString(msgName), aReply->capacity());
+                              nsDependentCString(msgName), aReply->size());
     }
     return true;
 }
 
 bool
 MessageChannel::Call(Message* aMsg, Message* aReply)
 {
     nsAutoPtr<Message> msg(aMsg);
--- a/ipc/ipdl/test/cxx/TestActorPunning.cpp
+++ b/ipc/ipdl/test/cxx/TestActorPunning.cpp
@@ -105,28 +105,24 @@ TestActorPunningSubChild::RecvBad()
 
 namespace IPC {
 using namespace mozilla::_ipdltest;
 using namespace mozilla::ipc;
 
 /*static*/ void
 ParamTraits<Bad>::Write(Message* aMsg, const paramType& aParam)
 {
-    char* ptr = aMsg->BeginWriteData(4);
-    ptr -= intptr_t(sizeof(int));
-    ptr -= intptr_t(sizeof(ActorHandle));
+    // Skip past the sentinel for the actor as well as the actor.
+    int32_t* ptr = aMsg->GetInt32PtrForTest(2 * sizeof(int32_t));
     ActorHandle* ah = reinterpret_cast<ActorHandle*>(ptr);
     if (ah->mId != -3)
         fail("guessed wrong offset (value is %d, should be -3)", ah->mId);
     ah->mId = -2;
 }
 
 /*static*/ bool
 ParamTraits<Bad>::Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
 {
-    const char* ptr;
-    int len;
-    mozilla::Unused << aMsg->ReadData(aIter, &ptr, &len);
     return true;
 }
 
 } // namespace IPC