Bug 1384328: Marshal proxies destined for parent main thread with MSHLFLAGS_NOPING; r=jimm
authorAaron Klotz <aklotz@mozilla.com>
Mon, 31 Jul 2017 16:11:19 -0600
changeset 423331 71df96e65afad583532ff8351b1c1022324507c6
parent 423330 7e5964aaf1179a1054ad7c8b7c4f5e33a02f28f1
child 423332 20344f0dbff988eddcec3387de3d1d575fbc9e89
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)
reviewersjimm
bugs1384328
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
Bug 1384328: Marshal proxies destined for parent main thread with MSHLFLAGS_NOPING; r=jimm MozReview-Commit-ID: Jfd4reMNYU0
ipc/mscom/Interceptor.cpp
ipc/mscom/Interceptor.h
--- a/ipc/mscom/Interceptor.cpp
+++ b/ipc/mscom/Interceptor.cpp
@@ -187,32 +187,71 @@ Interceptor::GetClassForHandler(DWORD aD
       aDestContext == MSHCTX_DIFFERENTMACHINE) {
     return E_INVALIDARG;
   }
 
   MOZ_ASSERT(mEventSink);
   return mEventSink->GetHandler(WrapNotNull(aHandlerClsid));
 }
 
+/**
+ * When we are marshaling to the parent process main thread, we want to turn
+ * off COM's ping functionality. That functionality is designed to free
+ * strong references held by defunct client processes. Since our content
+ * processes cannot outlive our parent process, we turn off pings when we know
+ * that the COM client is going to be our parent process. This provides a
+ * significant performance boost in a11y code due to large numbers of remote
+ * objects being created and destroyed within a short period of time.
+ */
+DWORD
+Interceptor::GetMarshalFlags(DWORD aDestContext, DWORD aMarshalFlags)
+{
+  // Only worry about local contexts.
+  if (aDestContext != MSHCTX_LOCAL) {
+    return aMarshalFlags;
+  }
+
+  // Get the caller TID. We check for S_FALSE to ensure that the caller is a
+  // different process from ours, which is the only scenario we care about.
+  DWORD callerTid;
+  if (::CoGetCallerTID(&callerTid) != S_FALSE) {
+    return aMarshalFlags;
+  }
+
+  // Now we compare the caller TID to our parent main thread TID.
+  const DWORD chromeMainTid =
+    dom::ContentChild::GetSingleton()->GetChromeMainThreadId();
+  if (callerTid != chromeMainTid) {
+    return aMarshalFlags;
+  }
+
+  // The caller is our parent main thread. Disable ping functionality.
+  return aMarshalFlags | MSHLFLAGS_NOPING;
+}
+
 HRESULT
 Interceptor::GetUnmarshalClass(REFIID riid, void* pv, DWORD dwDestContext,
                                void* pvDestContext, DWORD mshlflags,
                                CLSID* pCid)
 {
   return mStdMarshal->GetUnmarshalClass(riid, pv, dwDestContext, pvDestContext,
-                                        mshlflags, pCid);
+                                        GetMarshalFlags(dwDestContext,
+                                                        mshlflags), pCid);
 }
 
 HRESULT
 Interceptor::GetMarshalSizeMax(REFIID riid, void* pv, DWORD dwDestContext,
                                void* pvDestContext, DWORD mshlflags,
                                DWORD* pSize)
 {
   HRESULT hr = mStdMarshal->GetMarshalSizeMax(riid, pv, dwDestContext,
-                                              pvDestContext, mshlflags, pSize);
+                                              pvDestContext,
+                                              GetMarshalFlags(dwDestContext,
+                                                              mshlflags),
+                                              pSize);
   if (FAILED(hr)) {
     return hr;
   }
 
   DWORD payloadSize = 0;
   hr = mEventSink->GetHandlerPayloadSize(WrapNotNull(&payloadSize));
   *pSize += payloadSize;
   return hr;
@@ -235,17 +274,18 @@ Interceptor::MarshalInterface(IStream* p
   hr = pStm->Seek(seekTo, STREAM_SEEK_CUR, &objrefPos);
   if (FAILED(hr)) {
     return hr;
   }
 
 #endif // defined(MOZ_MSCOM_REMARSHAL_NO_HANDLER)
 
   hr = mStdMarshal->MarshalInterface(pStm, riid, pv, dwDestContext,
-                                     pvDestContext, mshlflags);
+                                     pvDestContext,
+                                     GetMarshalFlags(dwDestContext, mshlflags));
   if (FAILED(hr)) {
     return hr;
   }
 
 #if defined(MOZ_MSCOM_REMARSHAL_NO_HANDLER)
   if (XRE_IsContentProcess()) {
     const DWORD chromeMainTid =
       dom::ContentChild::GetSingleton()->GetChromeMainThreadId();
@@ -589,24 +629,16 @@ Interceptor::ThreadSafeQueryInterface(RE
     }
 
     RefPtr<IStdMarshalInfo> std(this);
     std.forget(aOutInterface);
     return S_OK;
   }
 
   if (aIid == IID_IMarshal) {
-    // Do not indicate that this interface is available unless we actually
-    // support it. We'll check that by looking for a successful call to
-    // IInterceptorSink::GetHandler()
-    CLSID dummy;
-    if (FAILED(mEventSink->GetHandler(WrapNotNull(&dummy)))) {
-      return E_NOINTERFACE;
-    }
-
     if (!mStdMarshalUnk) {
       HRESULT hr = ::CoGetStdMarshalEx(static_cast<IWeakReferenceSource*>(this),
                                        SMEXF_SERVER,
                                        getter_AddRefs(mStdMarshalUnk));
       if (FAILED(hr)) {
         return hr;
       }
     }
--- a/ipc/mscom/Interceptor.h
+++ b/ipc/mscom/Interceptor.h
@@ -125,16 +125,18 @@ private:
                                       STAUniquePtr<IUnknown> aTarget,
                                       void** aOutInterface);
   MapEntry* Lookup(REFIID aIid);
   HRESULT QueryInterfaceTarget(REFIID aIid, void** aOutput);
   HRESULT ThreadSafeQueryInterface(REFIID aIid,
                                    IUnknown** aOutInterface) override;
   HRESULT CreateInterceptor(REFIID aIid, IUnknown* aOuter, IUnknown** aOutput);
 
+  static DWORD GetMarshalFlags(DWORD aDestContext, DWORD aMarshalFlags);
+
 private:
   InterceptorTargetPtr<IUnknown>  mTarget;
   RefPtr<IInterceptorSink>  mEventSink;
   mozilla::Mutex            mMutex; // Guards mInterceptorMap
   // Using a nsTArray since the # of interfaces is not going to be very high
   nsTArray<MapEntry>        mInterceptorMap;
   RefPtr<IUnknown>          mStdMarshalUnk;
   IMarshal*                 mStdMarshal; // WEAK