Bug 1627305: Remove non-trivial macros from WebGL CommandQueue code r=jgilbert
authorDavid Parks <daparks@mozilla.com>
Thu, 30 Apr 2020 22:25:09 +0000
changeset 527408 29e888a9270c6d38ffaa30efd0d297f5163613f1
parent 527407 034f61c238aada80295bcc822cc8ea286232f599
child 527409 288b2b5e4a6b710f6097765eebd97a909826de51
push id114702
push userdaparks@mozilla.com
push dateFri, 01 May 2020 05:58:07 +0000
treeherderautoland@29e888a9270c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjgilbert
bugs1627305
milestone77.0a1
first release with
nightly linux32
29e888a9270c / 77.0a1 / 20200501094247 / files
nightly linux64
29e888a9270c / 77.0a1 / 20200501094247 / files
nightly mac
29e888a9270c / 77.0a1 / 20200501094247 / files
nightly win32
29e888a9270c / 77.0a1 / 20200501094247 / files
nightly win64
29e888a9270c / 77.0a1 / 20200501094247 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1627305: Remove non-trivial macros from WebGL CommandQueue code r=jgilbert Replaces DECLARE_METHOD_DISPATCHER and DEFINE_METHOD_DISPATCHER with generic classes. Differential Revision: https://phabricator.services.mozilla.com/D69676
dom/canvas/ClientWebGLContext.cpp
dom/canvas/ClientWebGLContext.h
dom/canvas/WebGLChild.cpp
dom/canvas/WebGLCommandQueue.h
dom/canvas/WebGLMethodDispatcher.h
--- a/dom/canvas/ClientWebGLContext.cpp
+++ b/dom/canvas/ClientWebGLContext.cpp
@@ -357,17 +357,17 @@ inline T DefaultOrVoid() {
 }
 
 template <>
 inline void DefaultOrVoid<void>() {
   return;
 }
 
 template <typename MethodType, MethodType method, typename ReturnType,
-          size_t Id, typename... Args>
+          typename... Args>
 ReturnType RunOn(const ClientWebGLContext& context, Args&&... aArgs) {
   const auto notLost =
       context.mNotLost;  // Hold a strong-ref to prevent LoseContext=>UAF.
   if (!notLost) return DefaultOrVoid<ReturnType>();
   const auto& inProcessContext = notLost->inProcess;
   if (inProcessContext) {
     return ((inProcessContext.get())->*method)(std::forward<Args>(aArgs)...);
   }
@@ -380,18 +380,17 @@ ReturnType RunOn(const ClientWebGLContex
 // method directly.  Otherwise, dispatch over IPC.
 template <typename MethodType, MethodType method, typename ReturnType,
           typename... Args>
 // template <
 //    typename MethodType, MethodType method,
 //    typename ReturnType, size_t Id,
 //    typename... Args>
 ReturnType ClientWebGLContext::Run(Args&&... aArgs) const {
-  return RunOn<MethodType, method, ReturnType,
-               WebGLMethodDispatcher::Id<MethodType, method>(), Args...>(
+  return RunOn<MethodType, method, ReturnType, Args...>(
       *this, std::forward<Args>(aArgs)...);
 }
 
 // -------------------------------------------------------------------------
 // Client-side helper methods.  Dispatch to a Host method.
 // -------------------------------------------------------------------------
 
 #define RPROC(_METHOD) \
--- a/dom/canvas/ClientWebGLContext.h
+++ b/dom/canvas/ClientWebGLContext.h
@@ -2133,17 +2133,17 @@ class ClientWebGLContext final : public 
      }
    }
    */
 
   template <typename ReturnType>
   friend struct WebGLClientDispatcher;
 
   template <typename MethodType, MethodType method, typename ReturnType,
-            size_t Id, typename... Args>
+            typename... Args>
   friend ReturnType RunOn(const ClientWebGLContext& context, Args&&... aArgs);
 
   // If we are running WebGL in this process then call the HostWebGLContext
   // method directly.  Otherwise, dispatch over IPC.
   // template <typename MethodType, MethodType method,
   //          typename ReturnType = typename
   //          FunctionTypeTraits<MethodType>::ReturnType, size_t Id =
   //          WebGLMethodDispatcher::Id<MethodType, method>(), typename... Args>
--- a/dom/canvas/WebGLChild.cpp
+++ b/dom/canvas/WebGLChild.cpp
@@ -24,13 +24,13 @@ mozilla::ipc::IPCResult WebGLChild::Recv
 mozilla::ipc::IPCResult WebGLChild::RecvOnContextLoss(
     const webgl::ContextLossReason reason) const {
   mContext.OnContextLoss(reason);
   return IPC_OK();
 }
 
 /* static */
 bool WebGLChild::ShouldSendSync(size_t aCmd, ...) {
-  return WebGLMethodDispatcher::SyncType(aCmd) == CommandSyncType::SYNC;
+  return WebGLMethodDispatcher<>::SyncType(aCmd) == CommandSyncType::SYNC;
 }
 
 }  // namespace dom
 }  // namespace mozilla
--- a/dom/canvas/WebGLCommandQueue.h
+++ b/dom/canvas/WebGLCommandQueue.h
@@ -494,114 +494,82 @@ class SyncCommandSink : public CommandSi
   bool WriteNAK() {
     SyncResponse nak = RESPONSE_NAK;
     return WriteArgs(nak);
   }
 
   UniquePtr<ResponseSource> mResponseSource;
 };
 
-/**
- * This CommandDispatcher provides helper methods that subclasses can
- * use to dispatch sync/async commands to a method via a CommandSink.
- * See DECLARE_METHOD_DISPATCHER and DEFINE_METHOD_DISPATCHER.
- */
-template <typename Derived>
-struct MethodDispatcher {
-  template <CommandSyncType syncType, int = 0>
-  struct DispatchMethod;
+// The MethodDispatcher setup uses a CommandSink to read parameters, call the
+// given method using the given synchronization protocol, and provide
+// compile-time lookup of the ID by class method.
+// To use this system, first define a dispatcher subclass of
+// EmptyMethodDispatcher.  This class must be parameterized by command ID.
+//
+// Example:
+// template <size_t id=0> class MyDispatcher
+//    : public EmptyMethodDispatcher<MyDispatcher> {};
+//
+// Then, for each command handled, specialize this to subclass MethodDispatcher.
+// The subclass must define the Method.  It may optionally define isSync for
+// synchronous methods.
+//
+// Example:
+// template <>
+// class MyDispatcher<0>
+//    : public MethodDispatcher<MyDispatcher, 0,
+//        decltype(&MyClass::MyMethod), MyClass::MyMethod,
+//        CommandSyncType::ASYNC> {};
+//
+// The method may then be called from the source and run on the sink.
+//
+// Example:
+// int result = Run<MyClass::MyMethod>(param1, std::move(param2));
 
-  // Specialization for dispatching asynchronous methods
-  template <int dummy>
-  struct DispatchMethod<CommandSyncType::ASYNC, dummy> {
-    template <typename MethodType, typename ObjectType, typename SinkType>
-    static MOZ_ALWAYS_INLINE bool Run(SinkType& aSink, MethodType mMethod,
-                                      ObjectType& aObj) {
-      return aSink.DispatchAsyncMethod(aObj, mMethod);
-    }
-  };
-
-  // Specialization for dispatching synchronous methods
-  template <int dummy>
-  struct DispatchMethod<CommandSyncType::SYNC, dummy> {
-    template <typename MethodType, typename ObjectType, typename SinkType>
-    static MOZ_ALWAYS_INLINE bool Run(SinkType& aSink, MethodType aMethod,
-                                      ObjectType& aObj) {
-      return aSink.DispatchSyncMethod(aObj, aMethod);
-    }
-  };
+template <template <size_t> typename Derived>
+class EmptyMethodDispatcher {
+ public:
+  template <typename SinkType, typename ObjectType>
+  static MOZ_ALWAYS_INLINE bool DispatchCommand(size_t aId, SinkType& aSink,
+                                                ObjectType& aObj) {
+    MOZ_CRASH("Illegal ID in DispatchCommand");
+  }
+  static MOZ_ALWAYS_INLINE CommandSyncType SyncType(size_t aId) {
+    MOZ_CRASH("Illegal ID in SyncType");
+  }
 };
 
-// Declares a MethodDispatcher with the given name and CommandSink type.
-// The ObjectType is the type of the object this class will dispatch methods to.
-#define DECLARE_METHOD_DISPATCHER(_DISPATCHER, _OBJECTTYPE)                    \
-  struct _DISPATCHER : public MethodDispatcher<_DISPATCHER> {                  \
-    using ObjectType = _OBJECTTYPE;                                            \
-    template <size_t commandId>                                                \
-    struct IdDispatcher {                                                      \
-      template <typename SinkType>                                             \
-      static MOZ_ALWAYS_INLINE bool DispatchCommand(size_t aId,                \
-                                                    SinkType& aSink,           \
-                                                    ObjectType& aObj) {        \
-        MOZ_CRASH("Impossible -- Unhandled command ID");                       \
-        return false;                                                          \
-      }                                                                        \
-      static MOZ_ALWAYS_INLINE CommandSyncType SyncType(size_t aId) {          \
-        MOZ_ASSERT_UNREACHABLE("Impossible -- Unhandled command ID");          \
-        return CommandSyncType::ASYNC;                                         \
-      }                                                                        \
-    };                                                                         \
-    template <typename SinkType, size_t commandId = 0>                         \
-    static MOZ_ALWAYS_INLINE bool DispatchCommand(size_t aId, SinkType& aSink, \
-                                                  ObjectType& aObj) {          \
-      return IdDispatcher<commandId>::DispatchCommand(aId, aSink, aObj);       \
-    }                                                                          \
-    template <size_t commandId = 0>                                            \
-    static MOZ_ALWAYS_INLINE CommandSyncType SyncType(size_t aId) {            \
-      return IdDispatcher<commandId>::SyncType(aId);                           \
-    }                                                                          \
-    template <size_t commandId>                                                \
-    struct MethodInfo;                                                         \
-    template <size_t commandId>                                                \
-    static constexpr CommandSyncType SyncType();                               \
-    template <typename MethodType, MethodType method>                          \
-    static constexpr size_t Id();                                              \
-  };
+// Derived type must be parameterized by the ID.
+template <template <size_t> typename Derived, size_t id, typename MethodType,
+          MethodType method, CommandSyncType syncType>
+class MethodDispatcher {
+  using DerivedType = Derived<id>;
+  using NextDispatcher = Derived<id + 1>;
 
-// Defines a handler in the given dispatcher for the command with the given
-// id.  The handler uses a CommandSink to read parameters, call the
-// given method using the given synchronization protocol, and provide
-// compile-time lookup of the ID by class method.
-#define DEFINE_METHOD_DISPATCHER(_DISPATCHER, _ID, _METHOD, _SYNC)             \
-  template <>                                                                  \
-  struct _DISPATCHER::MethodInfo<_ID> {                                        \
-    using MethodType = decltype(&_METHOD);                                     \
-  };                                                                           \
-  template <>                                                                  \
-  constexpr CommandSyncType _DISPATCHER::SyncType<_ID>() {                     \
-    return _SYNC;                                                              \
-  }                                                                            \
-  template <>                                                                  \
-  constexpr size_t _DISPATCHER::Id<decltype(&_METHOD), &_METHOD>() {           \
-    return _ID;                                                                \
-  }                                                                            \
-  template <>                                                                  \
-  struct _DISPATCHER::IdDispatcher<_ID> {                                      \
-    template <typename SinkType>                                               \
-    static MOZ_ALWAYS_INLINE bool DispatchCommand(size_t aId, SinkType& aSink, \
-                                                  ObjectType& aObj) {          \
-      return (_ID == aId) ? DispatchMethod<_SYNC>::Run(aSink, &_METHOD, aObj)  \
-                          : _DISPATCHER::DispatchCommand<SinkType, _ID + 1>(   \
-                                aId, aSink, aObj);                             \
-    }                                                                          \
-    static MOZ_ALWAYS_INLINE CommandSyncType SyncType(size_t aId) {            \
-      return (_ID == aId) ? _DISPATCHER::SyncType<_ID>()                       \
-                          : _DISPATCHER::SyncType<_ID + 1>(aId);               \
-    }                                                                          \
-  };
+ public:
+  template <typename SinkType, typename ObjectType>
+  static MOZ_ALWAYS_INLINE bool DispatchCommand(size_t aId, SinkType& aSink,
+                                                ObjectType& aObj) {
+    if (aId == id) {
+      return (syncType == CommandSyncType::ASYNC)
+                 ? aSink.DispatchAsyncMethod(aObj, Method())
+                 : aSink.DispatchSyncMethod(aObj, Method());
+    }
+    return NextDispatcher::DispatchCommand(aId, aSink, aObj);
+  }
+
+  static MOZ_ALWAYS_INLINE CommandSyncType SyncType(size_t aId) {
+    return (aId == id) ? syncType : NextDispatcher::SyncType(aId);
+  }
+
+  static constexpr CommandSyncType SyncType() { return syncType; }
+  static constexpr size_t Id() { return id; }
+  static constexpr MethodType Method() { return method; }
+};
 
 namespace ipc {
 template <typename T>
 struct IPDLParamTraits;
 
 template <typename Command, typename Source>
 struct IPDLParamTraits<mozilla::CommandSource<Command, Source>> {
  public:
--- a/dom/canvas/WebGLMethodDispatcher.h
+++ b/dom/canvas/WebGLMethodDispatcher.h
@@ -10,22 +10,30 @@
 #include "WebGLCrossProcessCommandQueue.h"
 #include "HostWebGLContext.h"
 #include "WebGLQueueParamTraits.h"
 
 namespace mozilla {
 
 // The WebGLMethodDispatcher will dispatch commands read from the
 // HostWebGLCommandSink and issue them to a given HostWebGLContext.
-DECLARE_METHOD_DISPATCHER(WebGLMethodDispatcher, HostWebGLContext)
+template <size_t id = 0>
+class WebGLMethodDispatcher
+    : public EmptyMethodDispatcher<WebGLMethodDispatcher> {};
+
+#define DEFINE_METHOD_DISPATCHER(_ID, _METHOD, _SYNC)       \
+  template <>                                               \
+  class WebGLMethodDispatcher<_ID>                          \
+      : public MethodDispatcher<WebGLMethodDispatcher, _ID, \
+                                decltype(&_METHOD), &_METHOD, _SYNC> {};
 
 // Defines each method the WebGLMethodDispatcher handles.  The COUNTER value
 // is used as a cross-process ID for each of the methods.
 #define DEFINE_METHOD_HELPER(_METHOD, _SYNC) \
-  DEFINE_METHOD_DISPATCHER(WebGLMethodDispatcher, __COUNTER__, _METHOD, _SYNC)
+  DEFINE_METHOD_DISPATCHER(__COUNTER__, _METHOD, _SYNC)
 #define DEFINE_ASYNC(_METHOD) \
   DEFINE_METHOD_HELPER(_METHOD, CommandSyncType::ASYNC)
 #define DEFINE_SYNC(_METHOD) \
   DEFINE_METHOD_HELPER(_METHOD, CommandSyncType::SYNC)
 
 DEFINE_ASYNC(HostWebGLContext::CreateBuffer)
 DEFINE_ASYNC(HostWebGLContext::CreateFramebuffer)
 DEFINE_SYNC(HostWebGLContext::CreateOpaqueFramebuffer)
@@ -165,12 +173,13 @@ DEFINE_ASYNC(HostWebGLContext::BeginQuer
 DEFINE_ASYNC(HostWebGLContext::EndQuery)
 DEFINE_ASYNC(HostWebGLContext::QueryCounter)
 DEFINE_SYNC(HostWebGLContext::GetQueryParameter)
 DEFINE_ASYNC(HostWebGLContext::SetFramebufferIsInOpaqueRAF)
 
 #undef DEFINE_METHOD_HELPER
 #undef DEFINE_ASYNC
 #undef DEFINE_SYNC
+#undef DEFINE_METHOD_DISPATCHER
 
 }  // namespace mozilla
 
 #endif  // WEBGLMETHODDISPATCHER_H_