DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Mercurial (1aeaa33a64f9)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
#ifndef mozilla_ipc_IPDLParamTraits_h
#define mozilla_ipc_IPDLParamTraits_h

#include "chrome/common/ipc_message_utils.h"

namespace mozilla {
namespace ipc {

class IProtocol;

//
// IPDLParamTraits are an extended version of ParamTraits. Unlike ParamTraits,
// IPDLParamTraits supports passing an additional IProtocol* argument to the
// write and read methods.
//
// This is important for serializing and deserializing types which require
// knowledge of which protocol they're being sent over, such as actors and
// nsIInputStreams.
//
// All types which already implement ParamTraits also support IPDLParamTraits.
//
template <typename P>
struct IPDLParamTraits {
  // This is the default impl which discards the actor parameter and calls into
  // ParamTraits. Types which want to use the actor parameter must specialize
  // IPDLParamTraits.
  static inline void Write(IPC::Message* aMsg, IProtocol*, const P& aParam) {
    IPC::ParamTraits<P>::Write(aMsg, aParam);
  }
  // Some types which implement ParamTraits require non-const references, as
  // they move their data into the IPC layer. This overload supports these
  // types.
  static inline void Write(IPC::Message* aMsg, IProtocol*, P& aParam) {
    IPC::ParamTraits<P>::Write(aMsg, aParam);
  }

  static inline bool Read(const IPC::Message* aMsg, PickleIterator* aIter,
                          IProtocol*, P* aResult) {
    return IPC::ParamTraits<P>::Read(aMsg, aIter, aResult);
  }
};

//
// WriteIPDLParam and ReadIPDLParam are like IPC::WriteParam and IPC::ReadParam,
// however, they also accept an extra actor argument, and use IPDLParamTraits
// rather than ParamTraits.
//
// NOTE: WriteIPDLParam takes a universal reference, so that it can support
// whatever reference type is supported by the underlying IPDLParamTraits::Write
// implementation. See the comment on IPDLParamTraits<nsTArray<T>>::Write for
// more information.
//
template <typename P>
static inline void WriteIPDLParam(IPC::Message* aMsg, IProtocol* aActor,
                                  P&& aParam) {
  IPDLParamTraits<typename Decay<P>::Type>::Write(aMsg, aActor,
                                                  Forward<P>(aParam));
}

template <typename P>
static inline bool ReadIPDLParam(const IPC::Message* aMsg,
                                 PickleIterator* aIter, IProtocol* aActor,
                                 P* aResult) {
  return IPDLParamTraits<P>::Read(aMsg, aIter, aActor, aResult);
}

// nsTArray support for IPDLParamTraits
template <typename T>
struct IPDLParamTraits<nsTArray<T>> {
  static inline void Write(IPC::Message* aMsg, IProtocol* aActor,
                           const nsTArray<T>& aParam) {
    WriteInternal(aMsg, aActor, aParam);
  }

  // Some serializers need to take a mutable reference to their backing object,
  // such as Shmem segments and Byte Buffers. These serializers take the backing
  // data and move it into the IPC layer for efficiency. They currently take
  // these references as mutable lvalue references rather than rvalue
  // references, (bug 1441651). This overload of Write on nsTArray is needed, as
  // occasionally these types appear inside of IPDL arrays.
  static inline void Write(IPC::Message* aMsg, IProtocol* aActor,
                           nsTArray<T>& aParam) {
    WriteInternal(aMsg, aActor, aParam);
  }

  // This method uses infallible allocation so that an OOM failure will
  // show up as an OOM crash rather than an IPC FatalError.
  static bool Read(const IPC::Message* aMsg, PickleIterator* aIter,
                   IProtocol* aActor, nsTArray<T>* aResult) {
    uint32_t length;
    if (!ReadIPDLParam(aMsg, aIter, aActor, &length)) {
      return false;
    }

    if (sUseWriteBytes) {
      auto pickledLength = CheckedInt<int>(length) * sizeof(T);
      if (!pickledLength.isValid()) {
        return false;
      }

      T* elements = aResult->AppendElements(length);
      return aMsg->ReadBytesInto(aIter, elements, pickledLength.value());
    }

    aResult->SetCapacity(length);

    for (uint32_t index = 0; index < length; index++) {
      T* element = aResult->AppendElement();
      if (!ReadIPDLParam(aMsg, aIter, aActor, element)) {
        return false;
      }
    }
    return true;
  }

 private:
  template <typename U>
  static inline void WriteInternal(IPC::Message* aMsg, IProtocol* aActor,
                                   U&& aParam) {
    uint32_t length = aParam.Length();
    WriteIPDLParam(aMsg, aActor, length);

    if (sUseWriteBytes) {
      auto pickledLength = CheckedInt<int>(length) * sizeof(T);
      MOZ_RELEASE_ASSERT(pickledLength.isValid());
      aMsg->WriteBytes(aParam.Elements(), pickledLength.value());
    } else {
      for (uint32_t index = 0; index < length; index++) {
        WriteIPDLParam(aMsg, aActor, aParam.Elements()[index]);
      }
    }
  }

  // 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
  // {IPDL,}ParamTraits<T> specialization.
  static const bool sUseWriteBytes =
      (mozilla::IsIntegral<T>::value || mozilla::IsFloatingPoint<T>::value);
};

}  // namespace ipc
}  // namespace mozilla

#endif  // defined(mozilla_ipc_IPDLParamTraits_h)