Add IPC support for mozilla::Variant (bug 1371846); r=botond
authorJeff Hajewski <jeff.hajewski@gmail.com>
Fri, 21 Jul 2017 07:18:02 -0500
changeset 421772 4322e8f2e455cfe8c83bad13ca718a38e90bf456
parent 421771 6981ac43cc156f29b46e0486bd14850351753484
child 421773 ef7a9d523ce4442188a9325dcd681ed5f84720ee
push id1517
push userjlorenzo@mozilla.com
push dateThu, 14 Sep 2017 16:50:54 +0000
treeherdermozilla-release@3b41fd564418 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbotond
bugs1371846
milestone56.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
Add IPC support for mozilla::Variant (bug 1371846); r=botond Changes made: * Add IPC::ParamTraits as a friend to mozilla::Variant in Variant.h. This is required so that `tag` can be accessed in the IPC::ParamTraits specialization. * Add a IPC::ParamTraits specialization to IPCMessageUtils.h. MozReview-Commit-ID: B3pGrZE1z0O
ipc/glue/IPCMessageUtils.h
mfbt/Variant.h
--- a/ipc/glue/IPCMessageUtils.h
+++ b/ipc/glue/IPCMessageUtils.h
@@ -898,11 +898,87 @@ struct ParamTraits<mozilla::Maybe<T>>
       *result = mozilla::Some(mozilla::Move(tmp));
     } else {
       *result = mozilla::Nothing();
     }
     return true;
   }
 };
 
+template<class... Ts>
+struct ParamTraits<mozilla::Variant<Ts...>>
+{
+  typedef mozilla::Variant<Ts...> paramType;
+  using Tag = typename mozilla::detail::VariantTag<Ts...>::Type;
+
+  struct VariantWriter
+  {
+    Message* msg;
+
+    template<class T>
+    void match(const T& t) {
+      WriteParam(msg, t);
+    }
+  };
+
+  static void Write(Message* msg, const paramType& param)
+  {
+    WriteParam(msg, param.tag);
+    param.match(VariantWriter(msg));
+  }
+
+  // Because VariantReader is a nested struct, we need the dummy template
+  // parameter to avoid making VariantReader<0> an explicit specialization,
+  // which is not allowed for a nested class template
+  template<size_t N, typename dummy = void>
+  struct VariantReader
+  {
+    using Next = VariantReader<N-1>;
+
+    static bool Read(const Message* msg, PickleIterator* iter,
+        Tag tag, paramType* result)
+    {
+      // Since the VariantReader specializations start at N , we need to
+      // subtract one to look at N - 1, the first valid tag.  This means our
+      // comparisons are off by 1.  If we get to N = 0 then we have failed to
+      // find a match to the tag.
+      if (tag == N - 1) {
+        // Recall, even though the template parameter is N, we are
+        // actually interested in the N - 1 tag.
+        typename mozilla::detail::Nth<N - 1, Ts...>::Type val;
+        if (ReadParam(msg, iter, &val)) {
+          *result = paramType::AsVariant(val);
+          return true;
+        }
+        return false;
+      } else {
+        return Next::Read(msg, iter, tag);
+      }
+    }
+
+  }; // VariantReader<N>
+
+  // Since we are conditioning on tag = N - 1 in the preceding specialization,
+  // if we get to `VariantReader<0, dummy>` we have failed to find
+  // a matching tag.
+  template<typename dummy>
+  struct VariantReader<0, dummy>
+  {
+    static bool Read(const Message* msg, PickleIterator* iter,
+        Tag tag, paramType* result)
+    {
+      return false;
+    }
+  };
+
+  static bool Read(const Message* msg, PickleIterator* iter, paramType* result)
+  {
+    Tag tag;
+    if (ReadParam(msg, iter, &tag)) {
+      return VariantReader<sizeof...(Ts)>::Read(msg, iter, tag, result);
+    }
+    return false;
+  }
+};
+
 } /* namespace IPC */
 
 #endif /* __IPC_GLUE_IPCMESSAGEUTILS_H__ */
--- a/mfbt/Variant.h
+++ b/mfbt/Variant.h
@@ -13,16 +13,20 @@
 #include "mozilla/Move.h"
 #include "mozilla/OperatorNewExtensions.h"
 #include "mozilla/TemplateLib.h"
 #include "mozilla/TypeTraits.h"
 
 #ifndef mozilla_Variant_h
 #define mozilla_Variant_h
 
+namespace IPC {
+template <typename T> struct ParamTraits;
+} // namespace IPC
+
 namespace mozilla {
 
 template<typename... Ts>
 class Variant;
 
 namespace detail {
 
 // Nth<N, types...>::Type is the Nth type (0-based) in the list of types Ts.
@@ -479,16 +483,18 @@ template<size_t N> struct VariantIndex {
  * and because |alignas| requirements don't affect platform ABI with respect to
  * how parameters are laid out in memory, Variant can't be used as the type of a
  * function parameter.  Pass Variant to functions by pointer or reference
  * instead.
  */
 template<typename... Ts>
 class MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS MOZ_NON_PARAM Variant
 {
+  friend struct IPC::ParamTraits<mozilla::Variant<Ts...>>;
+
   using Tag = typename detail::VariantTag<Ts...>::Type;
   using Impl = detail::VariantImplementation<Tag, 0, Ts...>;
 
   static constexpr size_t RawDataAlignment = tl::Max<alignof(Ts)...>::value;
   static constexpr size_t RawDataSize = tl::Max<sizeof(Ts)...>::value;
 
   // Raw storage for the contained variant value.
   alignas(RawDataAlignment) unsigned char rawData[RawDataSize];