Bug 540868 part 2: keep all NPObjects (not just those with actors) in mObjectMap, and invalidate/deallocate them when we destroy the associated instance, r=bent
authorBenjamin Smedberg <benjamin@smedbergs.us>
Fri, 22 Jan 2010 10:06:13 -0500
changeset 46567 9648cabf2b581873c81b2b688f9205f09f2f4e01
parent 46566 161692738cb1ac8a5423dfdda0b752488443a73a
child 46568 48ac29df3879e866f12b3b5ca35a10d1527ecc10
push idunknown
push userunknown
push dateunknown
reviewersbent
bugs540868
milestone1.9.3a1pre
Bug 540868 part 2: keep all NPObjects (not just those with actors) in mObjectMap, and invalidate/deallocate them when we destroy the associated instance, r=bent
dom/plugins/PluginInstanceChild.cpp
dom/plugins/PluginMessageUtils.h
dom/plugins/PluginModuleChild.cpp
dom/plugins/PluginModuleChild.h
dom/plugins/PluginModuleParent.cpp
dom/plugins/PluginScriptableObjectChild.cpp
dom/plugins/PluginScriptableObjectChild.h
ipc/glue/IPCMessageUtils.h
--- a/dom/plugins/PluginInstanceChild.cpp
+++ b/dom/plugins/PluginInstanceChild.cpp
@@ -879,26 +879,17 @@ PluginInstanceChild::AllocPPluginScripta
     return new PluginScriptableObjectChild(Proxy);
 }
 
 bool
 PluginInstanceChild::DeallocPPluginScriptableObject(
     PPluginScriptableObjectChild* aObject)
 {
     AssertPluginThread();
-
-    PluginScriptableObjectChild* actor =
-        reinterpret_cast<PluginScriptableObjectChild*>(aObject);
-
-    NPObject* object = actor->GetObject(false);
-    if (object) {
-        PluginModuleChild::current()->UnregisterNPObject(object);
-    }
-
-    delete actor;
+    delete aObject;
     return true;
 }
 
 bool
 PluginInstanceChild::AnswerPPluginScriptableObjectConstructor(
                                            PPluginScriptableObjectChild* aActor)
 {
     AssertPluginThread();
--- a/dom/plugins/PluginMessageUtils.h
+++ b/dom/plugins/PluginMessageUtils.h
@@ -657,10 +657,9 @@ struct ParamTraits<NPNURLVariable>
 #elif defined(XP_OS2)
 #  error Sorry, OS/2 is not supported
 #elif defined(XP_UNIX) && defined(MOZ_X11)
 #  include "mozilla/plugins/NPEventX11.h"
 #else
 #  error Unsupported platform
 #endif
 
-
 #endif /* DOM_PLUGINS_PLUGINMESSAGEUTILS_H */
--- a/dom/plugins/PluginModuleChild.cpp
+++ b/dom/plugins/PluginModuleChild.cpp
@@ -294,89 +294,64 @@ PluginModuleChild::GetUserAgent()
 {
     if (!CallNPN_UserAgent(&mUserAgent))
         return NULL;
 
     return NullableStringGet(mUserAgent);
 }
 
 bool
-PluginModuleChild::RegisterNPObject(NPObject* aObject,
-                                    PluginScriptableObjectChild* aActor)
+PluginModuleChild::RegisterActorForNPObject(NPObject* aObject,
+                                            PluginScriptableObjectChild* aActor)
 {
     AssertPluginThread();
     NS_ASSERTION(mObjectMap.IsInitialized(), "Not initialized!");
     NS_ASSERTION(aObject && aActor, "Null pointer!");
-    NS_ASSERTION(!mObjectMap.Get(aObject, nsnull),
-                 "Reregistering the same object!");
-    return !!mObjectMap.Put(aObject, aActor);
+
+    NPObjectData* d = mObjectMap.GetEntry(aObject);
+    if (!d) {
+        NS_ERROR("NPObject not in object table");
+        return false;
+    }
+
+    d->actor = aActor;
+    return true;
 }
 
 void
-PluginModuleChild::UnregisterNPObject(NPObject* aObject)
+PluginModuleChild::UnregisterActorForNPObject(NPObject* aObject)
 {
     AssertPluginThread();
     NS_ASSERTION(mObjectMap.IsInitialized(), "Not initialized!");
     NS_ASSERTION(aObject, "Null pointer!");
-    mObjectMap.Remove(aObject);
+
+    mObjectMap.GetEntry(aObject)->actor = NULL;
 }
 
 PluginScriptableObjectChild*
 PluginModuleChild::GetActorForNPObject(NPObject* aObject)
 {
     AssertPluginThread();
     NS_ASSERTION(mObjectMap.IsInitialized(), "Not initialized!");
     NS_ASSERTION(aObject, "Null pointer!");
-    PluginScriptableObjectChild* actor;
-    return mObjectMap.Get(aObject, &actor) ? actor : nsnull;
+
+    NPObjectData* d = mObjectMap.GetEntry(aObject);
+    if (!d) {
+        NS_ERROR("Plugin using object not created with NPN_CreateObject?");
+        return NULL;
+    }
+
+    return d->actor;
 }
 
 #ifdef DEBUG
-namespace {
-
-struct SearchInfo {
-  PluginScriptableObjectChild* target;
-  bool found;
-};
-
-PLDHashOperator
-ActorSearch(const void* aKey,
-            PluginScriptableObjectChild* aData,
-            void* aUserData)
-{
-  SearchInfo* info = reinterpret_cast<SearchInfo*>(aUserData);
-  NS_ASSERTION(info->target && ! info->found, "Bad info ptr!");
-
-  if (aData == info->target) {
-    info->found = true;
-    return PL_DHASH_STOP;
-  }
-
-  return PL_DHASH_NEXT;
-}
-
-} // anonymous namespace
-
 bool
 PluginModuleChild::NPObjectIsRegistered(NPObject* aObject)
 {
-    return !!mObjectMap.Get(aObject, nsnull);
-}
-
-bool
-PluginModuleChild::NPObjectIsRegisteredForActor(
-                                            PluginScriptableObjectChild* aActor)
-{
-    AssertPluginThread();
-    NS_ASSERTION(mObjectMap.IsInitialized(), "Not initialized!");
-    NS_ASSERTION(aActor, "Null actor!");
-
-    SearchInfo info = { aActor, false };
-    mObjectMap.EnumerateRead(ActorSearch, &info);
-    return info.found;
+    return !!mObjectMap.GetEntry(aObject);
 }
 #endif
 
 //-----------------------------------------------------------------------------
 // FIXME/cjones: just getting this out of the way for the moment ...
 
 namespace mozilla {
 namespace plugins {
@@ -464,25 +439,16 @@ static NPIdentifier NP_CALLBACK
 _getintidentifier(int32_t intid);
 
 static NPUTF8* NP_CALLBACK
 _utf8fromidentifier(NPIdentifier identifier);
 
 static int32_t NP_CALLBACK
 _intfromidentifier(NPIdentifier identifier);
 
-static NPObject* NP_CALLBACK
-_createobject(NPP aNPP, NPClass* aClass);
-
-static NPObject* NP_CALLBACK
-_retainobject(NPObject* npobj);
-
-static void NP_CALLBACK
-_releaseobject(NPObject* npobj);
-
 static bool NP_CALLBACK
 _invoke(NPP aNPP, NPObject* npobj, NPIdentifier method, const NPVariant *args,
         uint32_t argCount, NPVariant *result);
 
 static bool NP_CALLBACK
 _invokedefault(NPP aNPP, NPObject* npobj, const NPVariant *args,
                uint32_t argCount, NPVariant *result);
 
@@ -589,19 +555,19 @@ const NPNetscapeFuncs PluginModuleChild:
     mozilla::plugins::child::_invalidateregion,
     mozilla::plugins::child::_forceredraw,
     mozilla::plugins::child::_getstringidentifier,
     mozilla::plugins::child::_getstringidentifiers,
     mozilla::plugins::child::_getintidentifier,
     mozilla::plugins::child::_identifierisstring,
     mozilla::plugins::child::_utf8fromidentifier,
     mozilla::plugins::child::_intfromidentifier,
-    mozilla::plugins::child::_createobject,
-    mozilla::plugins::child::_retainobject,
-    mozilla::plugins::child::_releaseobject,
+    PluginModuleChild::NPN_CreateObject,
+    PluginModuleChild::NPN_RetainObject,
+    PluginModuleChild::NPN_ReleaseObject,
     mozilla::plugins::child::_invoke,
     mozilla::plugins::child::_invokedefault,
     mozilla::plugins::child::_evaluate,
     mozilla::plugins::child::_getproperty,
     mozilla::plugins::child::_setproperty,
     mozilla::plugins::child::_removeproperty,
     mozilla::plugins::child::_hasproperty,
     mozilla::plugins::child::_hasmethod,
@@ -1044,68 +1010,16 @@ int32_t NP_CALLBACK
         NS_WARNING("Failed to send message!");
         return -1;
     }
 
     // -1 for consistency
     return (NPERR_NO_ERROR == err) ? val : -1;
 }
 
-NPObject* NP_CALLBACK
-_createobject(NPP aNPP,
-              NPClass* aClass)
-{
-    PLUGIN_LOG_DEBUG_FUNCTION;
-    AssertPluginThread();
-
-    NPObject* newObject;
-    if (aClass && aClass->allocate) {
-        newObject = aClass->allocate(aNPP, aClass);
-    }
-    else {
-        newObject = reinterpret_cast<NPObject*>(_memalloc(sizeof(NPObject)));
-    }
-
-    if (newObject) {
-        newObject->_class = aClass;
-        newObject->referenceCount = 1;
-        NS_LOG_ADDREF(newObject, 1, "NPObject", sizeof(NPObject));
-    }
-    return newObject;
-}
-
-NPObject* NP_CALLBACK
-_retainobject(NPObject* aNPObj)
-{
-    AssertPluginThread();
-
-    int32_t refCnt = PR_AtomicIncrement((PRInt32*)&aNPObj->referenceCount);
-    NS_LOG_ADDREF(aNPObj, refCnt, "NPObject", sizeof(NPObject));
-
-    return aNPObj;
-}
-
-void NP_CALLBACK
-_releaseobject(NPObject* aNPObj)
-{
-    AssertPluginThread();
-
-    int32_t refCnt = PR_AtomicDecrement((PRInt32*)&aNPObj->referenceCount);
-    NS_LOG_RELEASE(aNPObj, refCnt, "NPObject");
-
-    if (refCnt == 0) {
-        if (aNPObj->_class && aNPObj->_class->deallocate) {
-            aNPObj->_class->deallocate(aNPObj);
-        } else {
-            _memfree(aNPObj);
-        }
-    }
-    return;
-}
-
 bool NP_CALLBACK
 _invoke(NPP aNPP,
         NPObject* aNPObj,
         NPIdentifier aMethod,
         const NPVariant* aArgs,
         uint32_t aArgCount,
         NPVariant* aResult)
 {
@@ -1279,17 +1193,17 @@ void NP_CALLBACK
 
     if (NPVARIANT_IS_STRING(*aVariant)) {
         NPString str = NPVARIANT_TO_STRING(*aVariant);
         free(const_cast<NPUTF8*>(str.UTF8Characters));
     }
     else if (NPVARIANT_IS_OBJECT(*aVariant)) {
         NPObject* object = NPVARIANT_TO_OBJECT(*aVariant);
         if (object) {
-            _releaseobject(object);
+            PluginModuleChild::NPN_ReleaseObject(object);
         }
     }
     VOID_TO_NPVARIANT(*aVariant);
 }
 
 void NP_CALLBACK
 _setexception(NPObject* aNPObj,
               const NPUTF8* aMessage)
@@ -1585,10 +1499,108 @@ PluginModuleChild::PluginInstanceDestroy
     PLUGIN_LOG_DEBUG_METHOD;
     AssertPluginThread();
 
     NPP npp = aActor->GetNPP();
 
     *rv = mFunctions.destroy(npp, 0);
     npp->ndata = 0;
 
+    DeallocNPObjectsForInstance(aActor);
+
     return true;
 }
+
+NPObject* NP_CALLBACK
+PluginModuleChild::NPN_CreateObject(NPP aNPP, NPClass* aClass)
+{
+    PLUGIN_LOG_DEBUG_FUNCTION;
+    AssertPluginThread();
+
+    PluginInstanceChild* i = InstCast(aNPP);
+
+    NPObject* newObject;
+    if (aClass && aClass->allocate) {
+        newObject = aClass->allocate(aNPP, aClass);
+    }
+    else {
+        newObject = reinterpret_cast<NPObject*>(child::_memalloc(sizeof(NPObject)));
+    }
+
+    if (newObject) {
+        newObject->_class = aClass;
+        newObject->referenceCount = 1;
+        NS_LOG_ADDREF(newObject, 1, "NPObject", sizeof(NPObject));
+    }
+
+    NPObjectData* d = static_cast<PluginModuleChild*>(i->Manager())
+        ->mObjectMap.PutEntry(newObject);
+    NS_ASSERTION(!d->instance, "New NPObject already mapped?");
+    d->instance = i;
+
+    return newObject;
+}
+
+NPObject* NP_CALLBACK
+PluginModuleChild::NPN_RetainObject(NPObject* aNPObj)
+{
+    AssertPluginThread();
+
+    int32_t refCnt = PR_AtomicIncrement((PRInt32*)&aNPObj->referenceCount);
+    NS_LOG_ADDREF(aNPObj, refCnt, "NPObject", sizeof(NPObject));
+
+    return aNPObj;
+}
+
+void NP_CALLBACK
+PluginModuleChild::NPN_ReleaseObject(NPObject* aNPObj)
+{
+    AssertPluginThread();
+
+    int32_t refCnt = PR_AtomicDecrement((PRInt32*)&aNPObj->referenceCount);
+    NS_LOG_RELEASE(aNPObj, refCnt, "NPObject");
+
+    if (refCnt == 0) {
+        DeallocNPObject(aNPObj);
+#ifdef DEBUG
+        NPObjectData* d = current()->mObjectMap.GetEntry(aNPObj);
+        NS_ASSERTION(d, "NPObject not mapped?");
+        NS_ASSERTION(!d->actor, "NPObject has actor at destruction?");
+#endif
+        current()->mObjectMap.RemoveEntry(aNPObj);
+    }
+    return;
+}
+
+void
+PluginModuleChild::DeallocNPObject(NPObject* aNPObj)
+{
+    if (aNPObj->_class && aNPObj->_class->deallocate) {
+        aNPObj->_class->deallocate(aNPObj);
+    } else {
+        child::_memfree(aNPObj);
+    }
+}
+
+PLDHashOperator
+PluginModuleChild::DeallocForInstance(NPObjectData* d, void* userArg)
+{
+    if (d->instance == static_cast<PluginInstanceChild*>(userArg)) {
+        NPObject* o = d->GetKey();
+        if (o->_class && o->_class->invalidate)
+            o->_class->invalidate(o);
+
+        DeallocNPObject(o);
+
+        if (d->actor)
+            d->actor->NPObjectDestroyed();
+
+        return PL_DHASH_REMOVE;
+    }
+
+    return PL_DHASH_NEXT;
+}
+
+void
+PluginModuleChild::DeallocNPObjectsForInstance(PluginInstanceChild* instance)
+{
+    mObjectMap.EnumerateEntries(DeallocForInstance, instance);
+}
--- a/dom/plugins/PluginModuleChild.h
+++ b/dom/plugins/PluginModuleChild.h
@@ -46,17 +46,17 @@
 #include "base/basictypes.h"
 
 #include "prlink.h"
 
 #include "npapi.h"
 #include "npfunctions.h"
 
 #include "nsAutoPtr.h"
-#include "nsDataHashtable.h"
+#include "nsTHashtable.h"
 #include "nsHashKeys.h"
 
 #include "mozilla/plugins/PPluginModuleChild.h"
 #include "mozilla/plugins/PluginInstanceChild.h"
 
 // NOTE: stolen from nsNPAPIPlugin.h
 
 /*
@@ -86,16 +86,17 @@ typedef NS_NPAPIPLUGIN_CALLBACK(NPError,
 #ifdef XP_MACOSX
 typedef NS_NPAPIPLUGIN_CALLBACK(NPError, NP_MAIN) (NPNetscapeFuncs* nCallbacks, NPPluginFuncs* pCallbacks, NPP_ShutdownProcPtr* unloadProcPtr);
 #endif
 
 namespace mozilla {
 namespace plugins {
 
 class PluginScriptableObjectChild;
+class PluginInstanceChild;
 
 class PluginModuleChild : public PPluginModuleChild
 {
 protected:
     // Implement the PPluginModuleChild interface
     virtual bool AnswerNP_Initialize(NPError* rv);
 
     virtual PPluginInstanceChild*
@@ -133,32 +134,44 @@ public:
     void CleanUp();
 
     const char* GetUserAgent();
 
     static const NPNetscapeFuncs sBrowserFuncs;
 
     static PluginModuleChild* current();
 
-    bool RegisterNPObject(NPObject* aObject,
-                          PluginScriptableObjectChild* aActor);
+    bool RegisterActorForNPObject(NPObject* aObject,
+                                  PluginScriptableObjectChild* aActor);
 
-    void UnregisterNPObject(NPObject* aObject);
+    void UnregisterActorForNPObject(NPObject* aObject);
 
     PluginScriptableObjectChild* GetActorForNPObject(NPObject* aObject);
 
 #ifdef DEBUG
     bool NPObjectIsRegistered(NPObject* aObject);
-    bool NPObjectIsRegisteredForActor(PluginScriptableObjectChild* aActor);
 #endif
 
     bool
     PluginInstanceDestroyed(PluginInstanceChild* aActor,
                             NPError* rv);
 
+    /**
+     * The child implementation of NPN_CreateObject.
+     */
+    static NPObject* NP_CALLBACK NPN_CreateObject(NPP aNPP, NPClass* aClass);
+    /**
+     * The child implementation of NPN_RetainObject.
+     */
+    static NPObject* NP_CALLBACK NPN_RetainObject(NPObject* aNPObj);
+    /**
+     * The child implementation of NPN_ReleaseObject.
+     */
+    static void NP_CALLBACK NPN_ReleaseObject(NPObject* aNPObj);
+
 private:
     bool InitGraphics();
 
     std::string mPluginFilename;
     PRLibrary* mLibrary;
     nsCString mUserAgent;
 
     // we get this from the plugin
@@ -167,15 +180,50 @@ private:
 #elif OS_WIN
     NP_PLUGININIT mInitializeFunc;
     NP_GETENTRYPOINTS mGetEntryPointsFunc;
 #endif
     NP_PLUGINSHUTDOWN mShutdownFunc;
     NPPluginFuncs mFunctions;
     NPSavedData mSavedData;
 
-    nsDataHashtable<nsVoidPtrHashKey, PluginScriptableObjectChild*> mObjectMap;
+    struct NPObjectData : public nsPtrHashKey<NPObject>
+    {
+        NPObjectData(const NPObject* key)
+            : nsPtrHashKey<NPObject>(key)
+            , instance(NULL)
+            , actor(NULL)
+        { }
+
+        // never NULL
+        PluginInstanceChild* instance;
+
+        // sometimes NULL (no actor associated with an NPObject)
+        PluginScriptableObjectChild* actor;
+    };
+    /**
+     * mObjectMap contains all the currently active NPObjects (from NPN_CreateObject until the
+     * final release/dealloc, whether or not an actor is currently associated with the object.
+     */
+    nsTHashtable<NPObjectData> mObjectMap;
+
+    /**
+     * Dealloc an NPObject after last-release or when the associated instance
+     * is destroyed. It is the callers responsibility to remove the object
+     * from mObjectMap.
+     */
+    static void DeallocNPObject(NPObject* o);
+
+    /**
+     * After an instance has been destroyed, dealloc the objects associated
+     * with that instance.
+     */
+    void DeallocNPObjectsForInstance(PluginInstanceChild* instance);
+    /**
+     * Enumeration helper function for DeallocNPObjectsForInstance.
+     */
+    static PLDHashOperator DeallocForInstance(NPObjectData* d, void* userArg);
 };
 
 } /* namespace plugins */
 } /* namespace mozilla */
 
 #endif  // ifndef dom_plugins_PluginModuleChild_h
--- a/dom/plugins/PluginModuleParent.cpp
+++ b/dom/plugins/PluginModuleParent.cpp
@@ -240,20 +240,17 @@ PluginModuleParent::NPP_Destroy(NPP inst
         static_cast<PluginInstanceParent*>(instance->pdata);
 
     if (!parentInstance)
         return NPERR_NO_ERROR;
 
     NPError retval = parentInstance->Destroy();
     instance->pdata = nsnull;
 
-    if (!PluginInstanceParent::Call__delete__(parentInstance)) {
-        NS_ERROR("Failed to delete instance!");
-    }
-
+    (void) PluginInstanceParent::Call__delete__(parentInstance);
     return retval;
 }
 
 bool
 PluginModuleParent::EnsureValidNPIdentifier(NPIdentifier aIdentifier)
 {
     if (!mValidIdentifiers.GetEntry(aIdentifier)) {
         nsVoidPtrHashKey* newEntry = mValidIdentifiers.PutEntry(aIdentifier);
--- a/dom/plugins/PluginScriptableObjectChild.cpp
+++ b/dom/plugins/PluginScriptableObjectChild.cpp
@@ -449,46 +449,44 @@ PluginScriptableObjectChild::PluginScrip
   AssertPluginThread();
 }
 
 PluginScriptableObjectChild::~PluginScriptableObjectChild()
 {
   AssertPluginThread();
 
   if (mObject) {
+    PluginModuleChild::current()->UnregisterActorForNPObject(mObject);
+
     if (mObject->_class == GetClass()) {
       NS_ASSERTION(mType == Proxy, "Wrong type!");
       static_cast<ChildNPObject*>(mObject)->parent = nsnull;
     }
     else {
       NS_ASSERTION(mType == LocalObject, "Wrong type!");
       PluginModuleChild::sBrowserFuncs.releaseobject(mObject);
     }
   }
-
-  NS_ASSERTION(!PluginModuleChild::current()->
-               NPObjectIsRegisteredForActor(this),
-               "NPObjects still registered for this actor!");
 }
 
 void
 PluginScriptableObjectChild::InitializeProxy()
 {
   AssertPluginThread();
   NS_ASSERTION(mType == Proxy, "Bad type!");
   NS_ASSERTION(!mObject, "Calling Initialize more than once!");
   NS_ASSERTION(!mInvalidated, "Already invalidated?!");
 
   mInstance = static_cast<PluginInstanceChild*>(Manager());
   NS_ASSERTION(mInstance, "Null manager?!");
 
   NPObject* object = CreateProxyObject();
   NS_ASSERTION(object, "Failed to create object!");
 
-  if (!PluginModuleChild::current()->RegisterNPObject(object, this)) {
+  if (!PluginModuleChild::current()->RegisterActorForNPObject(object, this)) {
     NS_ERROR("Out of memory?");
   }
 
   mObject = object;
 }
 
 void
 PluginScriptableObjectChild::InitializeLocal(NPObject* aObject)
@@ -501,17 +499,17 @@ PluginScriptableObjectChild::InitializeL
   mInstance = static_cast<PluginInstanceChild*>(Manager());
   NS_ASSERTION(mInstance, "Null manager?!");
 
   PluginModuleChild::sBrowserFuncs.retainobject(aObject);
 
   NS_ASSERTION(!mProtectCount, "Should be zero!");
   mProtectCount++;
 
-  if (!PluginModuleChild::current()->RegisterNPObject(aObject, this)) {
+  if (!PluginModuleChild::current()->RegisterActorForNPObject(aObject, this)) {
       NS_ERROR("Out of memory?");
   }
 
   mObject = aObject;
 }
 
 NPObject*
 PluginScriptableObjectChild::CreateProxyObject()
@@ -599,42 +597,49 @@ void
 PluginScriptableObjectChild::DropNPObject()
 {
   NS_ASSERTION(mObject, "Invalidated object!");
   NS_ASSERTION(mObject->_class == GetClass(), "Wrong type of object!");
   NS_ASSERTION(mType == Proxy, "Shouldn't call this for non-proxy object!");
 
   // We think we're about to be deleted, but we could be racing with the other
   // process.
-  PluginModuleChild::current()->UnregisterNPObject(mObject);
+  PluginModuleChild::current()->UnregisterActorForNPObject(mObject);
   mObject = nsnull;
 
   CallUnprotect();
 }
 
+void
+PluginScriptableObjectChild::NPObjectDestroyed()
+{
+  NS_ASSERTION(LocalObject == mType,
+               "ScriptableDeallocate should have handled this for proxies");
+  mInvalidated = true;
+  mObject = NULL;
+}
+
 bool
 PluginScriptableObjectChild::AnswerInvalidate()
 {
   AssertPluginThread();
 
   if (mInvalidated) {
-    NS_WARNING("Called invalidate more than once?!");
     return true;
   }
 
   mInvalidated = true;
 
   NS_ASSERTION(mObject->_class != GetClass(), "Bad object type!");
   NS_ASSERTION(mType == LocalObject, "Bad type!");
 
   if (mObject->_class && mObject->_class->invalidate) {
     mObject->_class->invalidate(mObject);
   }
 
-  PluginModuleChild::current()->UnregisterNPObject(mObject);
   Unprotect();
 
   return true;
 }
 
 bool
 PluginScriptableObjectChild::AnswerHasMethod(const NPRemoteIdentifier& aId,
                                              bool* aHasMethod)
--- a/dom/plugins/PluginScriptableObjectChild.h
+++ b/dom/plugins/PluginScriptableObjectChild.h
@@ -163,16 +163,23 @@ public:
 
   // DropNPObject is only used for Proxy actors and is called when the child
   // process is no longer using the NPObject associated with this actor. The
   // parent process may subsequently use this actor again in which case a new
   // NPObject will be created and associated with this actor (see
   // ResurrectProxyObject).
   void DropNPObject();
 
+  /**
+   * After NPP_Destroy, all NPObjects associated with an instance are
+   * destroyed. We are informed of this destruction. This should only be called
+   * on Local actors.
+   */
+  void NPObjectDestroyed();
+
   bool
   Evaluate(NPString* aScript,
            NPVariant* aResult);
 
   ScriptableObjectType
   Type() const {
     return mType;
   }
--- a/ipc/glue/IPCMessageUtils.h
+++ b/ipc/glue/IPCMessageUtils.h
@@ -40,16 +40,20 @@
 #define __IPC_GLUE_IPCMESSAGEUTILS_H__
 
 #include "chrome/common/ipc_message_utils.h"
 
 #include "prtypes.h"
 #include "nsStringGlue.h"
 #include "nsTArray.h"
 
+#ifdef _MSC_VER
+#pragma warning( disable : 4800 )
+#endif
+
 namespace IPC {
 
 template <>
 struct ParamTraits<nsACString>
 {
   typedef nsACString paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)