Bug 1208059: Make nsNPAPIPluginInstance support WeakPtr and modify PluginAsyncSurrogate to use it; r=jimm a=ritu
authorAaron Klotz <aklotz@mozilla.com>
Mon, 19 Oct 2015 14:34:27 -0400
changeset 305532 ff8b0e45058281d44f6bd1086077bdf030682c12
parent 305531 c9f3f25d86caaf2682eb8f8072e79fe10079c500
child 305533 c9902056c1842019b9ad58f6aaf6c0f0cc7b8756
push id1001
push userraliiev@mozilla.com
push dateMon, 18 Jan 2016 19:06:03 +0000
treeherdermozilla-release@8b89261f3ac4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjimm, ritu
bugs1208059
milestone44.0a2
Bug 1208059: Make nsNPAPIPluginInstance support WeakPtr and modify PluginAsyncSurrogate to use it; r=jimm a=ritu
dom/plugins/base/nsNPAPIPluginInstance.h
dom/plugins/ipc/PluginAsyncSurrogate.cpp
dom/plugins/ipc/PluginAsyncSurrogate.h
--- a/dom/plugins/base/nsNPAPIPluginInstance.h
+++ b/dom/plugins/base/nsNPAPIPluginInstance.h
@@ -26,16 +26,17 @@
 #include "AndroidBridge.h"
 #include <map>
 class PluginEventRunnable;
 class SharedPluginTexture;
 #endif
 
 #include "mozilla/TimeStamp.h"
 #include "mozilla/PluginLibrary.h"
+#include "mozilla/WeakPtr.h"
 
 class nsPluginStreamListenerPeer; // browser-initiated stream class
 class nsNPAPIPluginStreamListener; // plugin-initiated stream class
 class nsIPluginInstanceOwner;
 class nsIOutputStream;
 class nsPluginInstanceOwner;
 
 #if defined(OS_WIN)
@@ -71,21 +72,23 @@ public:
   uint32_t id;
   nsCOMPtr<nsITimer> timer;
   void (*callback)(NPP npp, uint32_t timerID);
   bool inCallback;
   bool needUnschedule;
 };
 
 class nsNPAPIPluginInstance final : public nsIAudioChannelAgentCallback
+                                  , public mozilla::SupportsWeakPtr<nsNPAPIPluginInstance>
 {
 private:
   typedef mozilla::PluginLibrary PluginLibrary;
 
 public:
+  MOZ_DECLARE_WEAKREFERENCE_TYPENAME(nsNPAPIPluginInstance)
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSIAUDIOCHANNELAGENTCALLBACK
 
   nsresult Initialize(nsNPAPIPlugin *aPlugin, nsPluginInstanceOwner* aOwner, const nsACString& aMIMEType);
   nsresult Start();
   nsresult Stop();
   nsresult SetWindow(NPWindow* window);
   nsresult NewStreamFromPlugin(const char* type, const char* target, nsIOutputStream* *result);
--- a/dom/plugins/ipc/PluginAsyncSurrogate.cpp
+++ b/dom/plugins/ipc/PluginAsyncSurrogate.cpp
@@ -96,17 +96,16 @@ private:
   bool        mIsRecursive;
   static bool sHasEntered;
 };
 
 bool RecursionGuard::sHasEntered = false;
 
 PluginAsyncSurrogate::PluginAsyncSurrogate(PluginModuleParent* aParent)
   : mParent(aParent)
-  , mInstance(nullptr)
   , mMode(0)
   , mWindow(nullptr)
   , mAcceptCalls(false)
   , mInstantiated(false)
   , mAsyncSetWindow(false)
   , mInitCancelled(false)
   , mDestroyPending(false)
   , mAsyncCallsInFlight(0)
@@ -118,17 +117,20 @@ PluginAsyncSurrogate::~PluginAsyncSurrog
 {
 }
 
 bool
 PluginAsyncSurrogate::Init(NPMIMEType aPluginType, NPP aInstance, uint16_t aMode,
                            int16_t aArgc, char* aArgn[], char* aArgv[])
 {
   mMimeType = aPluginType;
-  mInstance = aInstance;
+  nsNPAPIPluginInstance* instance =
+    static_cast<nsNPAPIPluginInstance*>(aInstance->ndata);
+  MOZ_ASSERT(instance);
+  mInstance = instance;
   mMode = aMode;
   for (int i = 0; i < aArgc; ++i) {
     mNames.AppendElement(NullableString(aArgn[i]));
     mValues.AppendElement(NullableString(aArgv[i]));
   }
   return true;
 }
 
@@ -157,17 +159,21 @@ PluginAsyncSurrogate::Cast(NPP aInstance
     return nullptr;
   }
   return resolver->GetAsyncSurrogate();
 }
 
 nsresult
 PluginAsyncSurrogate::NPP_New(NPError* aError)
 {
-  nsresult rv = mParent->NPP_NewInternal(mMimeType.BeginWriting(), mInstance,
+  if (!mInstance) {
+    return NS_ERROR_NULL_POINTER;
+  }
+
+  nsresult rv = mParent->NPP_NewInternal(mMimeType.BeginWriting(), GetNPP(),
                                          mMode, mNames, mValues, nullptr,
                                          aError);
   if (NS_FAILED(rv)) {
     return rv;
   }
   return NS_OK;
 }
 
@@ -194,61 +200,72 @@ PluginAsyncSurrogate::NotifyDestroyPendi
 {
   PluginAsyncSurrogate* surrogate = Cast(aInstance);
   if (!surrogate) {
     return;
   }
   surrogate->NotifyDestroyPending();
 }
 
+NPP
+PluginAsyncSurrogate::GetNPP()
+{
+  MOZ_ASSERT(mInstance);
+  NPP npp;
+  DebugOnly<nsresult> rv = mInstance->GetNPP(&npp);
+  MOZ_ASSERT(NS_SUCCEEDED(rv));
+  return npp;
+}
+
 void
 PluginAsyncSurrogate::NotifyDestroyPending()
 {
   mDestroyPending = true;
-  nsJSNPRuntime::OnPluginDestroyPending(mInstance);
+  nsJSNPRuntime::OnPluginDestroyPending(GetNPP());
 }
 
 NPError
 PluginAsyncSurrogate::NPP_Destroy(NPSavedData** aSave)
 {
   NotifyDestroyPending();
   if (!WaitForInit()) {
     return NPERR_GENERIC_ERROR;
   }
-  return PluginModuleParent::NPP_Destroy(mInstance, aSave);
+  return PluginModuleParent::NPP_Destroy(GetNPP(), aSave);
 }
 
 NPError
 PluginAsyncSurrogate::NPP_GetValue(NPPVariable aVariable, void* aRetval)
 {
   if (aVariable != NPPVpluginScriptableNPObject) {
     if (!WaitForInit()) {
       return NPERR_GENERIC_ERROR;
     }
-    PluginInstanceParent* instance = PluginInstanceParent::Cast(mInstance);
+
+    PluginInstanceParent* instance = PluginInstanceParent::Cast(GetNPP());
     MOZ_ASSERT(instance);
     return instance->NPP_GetValue(aVariable, aRetval);
   }
 
-  NPObject* npobject = parent::_createobject(mInstance,
+  NPObject* npobject = parent::_createobject(GetNPP(),
                                              const_cast<NPClass*>(GetClass()));
   MOZ_ASSERT(npobject);
   MOZ_ASSERT(npobject->_class == GetClass());
   MOZ_ASSERT(npobject->referenceCount == 1);
   *(NPObject**)aRetval = npobject;
   return npobject ? NPERR_NO_ERROR : NPERR_GENERIC_ERROR;
 }
 
 NPError
 PluginAsyncSurrogate::NPP_SetValue(NPNVariable aVariable, void* aValue)
 {
   if (!WaitForInit()) {
     return NPERR_GENERIC_ERROR;
   }
-  return PluginModuleParent::NPP_SetValue(mInstance, aVariable, aValue);
+  return PluginModuleParent::NPP_SetValue(GetNPP(), aVariable, aValue);
 }
 
 NPError
 PluginAsyncSurrogate::NPP_NewStream(NPMIMEType aType, NPStream* aStream,
                                     NPBool aSeekable, uint16_t* aStype)
 {
   mPendingNewStreamCalls.AppendElement(PendingNewStreamCall(aType, aStream,
                                                             aSeekable));
@@ -424,17 +441,20 @@ void
 PluginAsyncSurrogate::DestroyAsyncStream(NPStream* aStream)
 {
   MOZ_ASSERT(aStream);
   nsNPAPIPluginStreamListener* streamListener = GetStreamListener(aStream);
   MOZ_ASSERT(streamListener);
   // streamListener was suspended during async init. We must resume the stream
   // request prior to calling _destroystream for cleanup to work correctly.
   streamListener->ResumeRequest();
-  parent::_destroystream(mInstance, aStream, NPRES_DONE);
+  if (!mInstance) {
+    return;
+  }
+  parent::_destroystream(GetNPP(), aStream, NPRES_DONE);
 }
 
 /* static */ bool
 PluginAsyncSurrogate::SetStreamType(NPStream* aStream, uint16_t aStreamType)
 {
   nsNPAPIPluginStreamListener* streamListener = GetStreamListener(aStream);
   if (!streamListener) {
     return false;
@@ -564,22 +584,20 @@ PluginAsyncSurrogate::NotifyAsyncInitFai
     }
   }
   mPendingNewStreamCalls.Clear();
 
   // Make sure that any WaitForInit calls on this surrogate will fail, or else
   // we'll be perma-blocked
   mInitCancelled = true;
 
-  nsNPAPIPluginInstance* inst =
-    static_cast<nsNPAPIPluginInstance*>(mInstance->ndata);
-  if (!inst) {
+  if (!mInstance) {
       return;
   }
-  nsPluginInstanceOwner* owner = inst->GetOwner();
+  nsPluginInstanceOwner* owner = mInstance->GetOwner();
   if (owner) {
     owner->NotifyHostAsyncInitFailed();
   }
 }
 
 // static
 NPObject*
 PluginAsyncSurrogate::ScriptableAllocate(NPP aInstance, NPClass* aClass)
@@ -658,21 +676,21 @@ PluginAsyncSurrogate::ScriptableHasMetho
   }
   bool result = realObject->_class->hasMethod(realObject, aName);
   if (!result && checkPluginObject) {
     // We may be calling into this object because properties in the WebIDL
     // object hadn't been set yet. Now that we're further along in
     // initialization, we should try again.
     const NPNetscapeFuncs* npn = object->mSurrogate->mParent->GetNetscapeFuncs();
     NPObject* pluginObject = nullptr;
-    NPError nperror = npn->getvalue(object->mSurrogate->mInstance,
+    NPError nperror = npn->getvalue(object->mSurrogate->GetNPP(),
                                     NPNVPluginElementNPObject,
                                     (void*)&pluginObject);
     if (nperror == NPERR_NO_ERROR) {
-      NPPAutoPusher nppPusher(object->mSurrogate->mInstance);
+      NPPAutoPusher nppPusher(object->mSurrogate->GetNPP());
       result = pluginObject->_class->hasMethod(pluginObject, aName);
       npn->releaseobject(pluginObject);
       NPUTF8* idstr = npn->utf8fromidentifier(aName);
       npn->memfree(idstr);
     }
   }
   return result;
 }
@@ -711,20 +729,20 @@ PluginAsyncSurrogate::GetPropertyHelper(
     static_cast<ParentNPObject*>(realObject)->parent;
   if (!actor) {
     return false;
   }
   bool success = actor->GetPropertyHelper(aName, aHasProperty, aHasMethod, aResult);
   if (!success) {
     const NPNetscapeFuncs* npn = mParent->GetNetscapeFuncs();
     NPObject* pluginObject = nullptr;
-    NPError nperror = npn->getvalue(mInstance, NPNVPluginElementNPObject,
+    NPError nperror = npn->getvalue(GetNPP(), NPNVPluginElementNPObject,
                                     (void*)&pluginObject);
     if (nperror == NPERR_NO_ERROR) {
-      NPPAutoPusher nppPusher(mInstance);
+      NPPAutoPusher nppPusher(GetNPP());
       bool hasProperty = nsJSObjWrapper::HasOwnProperty(pluginObject, aName);
       NPUTF8* idstr = npn->utf8fromidentifier(aName);
       npn->memfree(idstr);
       bool hasMethod = false;
       if (hasProperty) {
         hasMethod = pluginObject->_class->hasMethod(pluginObject, aName);
         success = pluginObject->_class->getProperty(pluginObject, aName, aResult);
         idstr = npn->utf8fromidentifier(aName);
@@ -819,21 +837,21 @@ PluginAsyncSurrogate::ScriptableHasPrope
   const NPNetscapeFuncs* npn = object->mSurrogate->mParent->GetNetscapeFuncs();
   NPUTF8* idstr = npn->utf8fromidentifier(aName);
   npn->memfree(idstr);
   if (!result && checkPluginObject) {
     // We may be calling into this object because properties in the WebIDL
     // object hadn't been set yet. Now that we're further along in
     // initialization, we should try again.
     NPObject* pluginObject = nullptr;
-    NPError nperror = npn->getvalue(object->mSurrogate->mInstance,
+    NPError nperror = npn->getvalue(object->mSurrogate->GetNPP(),
                                     NPNVPluginElementNPObject,
                                     (void*)&pluginObject);
     if (nperror == NPERR_NO_ERROR) {
-      NPPAutoPusher nppPusher(object->mSurrogate->mInstance);
+      NPPAutoPusher nppPusher(object->mSurrogate->GetNPP());
       result = nsJSObjWrapper::HasOwnProperty(pluginObject, aName);
       npn->releaseobject(pluginObject);
       idstr = npn->utf8fromidentifier(aName);
       npn->memfree(idstr);
     }
   }
   return result;
 }
--- a/dom/plugins/ipc/PluginAsyncSurrogate.h
+++ b/dom/plugins/ipc/PluginAsyncSurrogate.h
@@ -55,17 +55,17 @@ public:
   void NotifyDestroyPending();
 
   virtual PluginAsyncSurrogate*
   GetAsyncSurrogate() { return this; }
 
   virtual PluginInstanceParent*
   GetInstance() { return nullptr; }
 
-  NPP GetNPP() { return mInstance; }
+  NPP GetNPP();
 
   bool GetPropertyHelper(NPObject* aObject, NPIdentifier aName,
                          bool* aHasProperty, bool* aHasMethod,
                          NPVariant* aResult);
 
   PluginModuleParent* GetParent() { return mParent; }
 
   bool IsDestroyPending() const { return mDestroyPending; }
@@ -136,17 +136,17 @@ private:
     NPStream*   mStream;
     NPBool      mSeekable;
   };
 
 private:
   PluginModuleParent*             mParent;
   // These values are used to construct the plugin instance
   nsCString                       mMimeType;
-  NPP                             mInstance;
+  mozilla::WeakPtr<nsNPAPIPluginInstance> mInstance;
   uint16_t                        mMode;
   InfallibleTArray<nsCString>     mNames;
   InfallibleTArray<nsCString>     mValues;
   // This is safe to store as a pointer because the spec says it will remain
   // valid until destruction or a subsequent NPP_SetWindow call.
   NPWindow*                       mWindow;
   nsTArray<PendingNewStreamCall>  mPendingNewStreamCalls;
   UniquePtr<PluginDestructionGuard> mPluginDestructionGuard;